From d20f1825d09c50175c6a44cf31608a5b9a8b50c7 Mon Sep 17 00:00:00 2001 From: Frederic Gingras Date: Mon, 16 Jan 2017 16:03:11 -0500 Subject: [PATCH 01/27] meta: create readme.md and outline sections --- README.markdown => INSTRUCTIONS.md | 0 README.md | 58 ++++++++++++++++++++++++++++++ 2 files changed, 58 insertions(+) rename README.markdown => INSTRUCTIONS.md (100%) create mode 100644 README.md diff --git a/README.markdown b/INSTRUCTIONS.md similarity index 100% rename from README.markdown rename to INSTRUCTIONS.md diff --git a/README.md b/README.md new file mode 100644 index 000000000..e4e386c44 --- /dev/null +++ b/README.md @@ -0,0 +1,58 @@ +# Wave Software Development Challenge + +## Intro + +TODO Discuss aproach to chosing the tech stack, problem at hand and what was kept in mind while +building the service / what where we optimizing for, even if this is a simple exercise. + +## Development + +### Technical stack + +TODO + +### Building + +TODO Talk about dependencies and follow with building instructions. + +### Testing + +TODO Discuss kinds of testing involved (unit, integration, system) and libraries used, touch on how +actually run these. + +## Production + +TODO Overview of what's discussed in this section and how some subject where simplified for the +exercise but could be expanded upon. + +### Deploying changes + +TODO Talk about `scripts/deploy.sh` and it could be scaled/automated in production using some custom +software or Ansible/Chef/Puppet/SaltStack. Touch on database migrations. + +### Provisioning new servers + +TODO Talk about host choice, server distro, `scripts/provision.sh`, touch on run manually in this +case but can be automated with Ansible/Tower | Chef/Server | Puppet/Server. + +### Understanding day-to-day operations + +**Server** + +**Application process** + +**Database** + +**Logging** + +**Performance monitoring** + +**User monitoring** + +**Security** + +**Disaster recovery** + +## Footnotes + +### What I am proud of From 6ae346c1f799e62b857d3ef945784b33036bbc1c Mon Sep 17 00:00:00 2001 From: Frederic Gingras Date: Mon, 16 Jan 2017 16:18:50 -0500 Subject: [PATCH 02/27] meta: readme: write intro --- README.md | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e4e386c44..98984de91 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,31 @@ ## Intro -TODO Discuss aproach to chosing the tech stack, problem at hand and what was kept in mind while -building the service / what where we optimizing for, even if this is a simple exercise. +**Technology** + +While choosing a set of technologies for this challenge I had two goals in mind: + +1. Using languages, software, and operating systems I have used in the past so + that I can get to a working solution fast and best showcase my skills. +1. Still picking some new tools/libraries for 1-2 thing as this challenge is a + perfect opportunity to better myself and explore new things in a safe environment. + +**Goals** + +The problem at hand is very simplistic but, can be interpreted in a myriad of +ways. Hence the problem here is now ticking the requirement but showing some +depth in the mastery of an aspect of web development you are comfortable with. + +A second goal should be thinking about the user, this is what Wave, and many +other great organizations do: start from the user. What is the user trying to +accomplish? How can we make it as easy as possible? How can we delight the +user? Often the answer is by doing your very best in each aspect Design / +Experience / User Interface / Performance / Stability / Iteration Speed / +Innovation. + +Third, thinking of the onsite interview, how can we make sure this project +includes grounds for interesting discussions. How can we make it technically +interesting and easy to change/update/modify. ## Development From cba5900aaf378993c493ae7721c7071f0186342d Mon Sep 17 00:00:00 2001 From: Frederic Gingras Date: Mon, 16 Jan 2017 16:57:43 -0500 Subject: [PATCH 03/27] meta: readme: write tech stack --- README.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 98984de91..8016e6740 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,20 @@ interesting and easy to change/update/modify. ### Technical stack -TODO +- Data + - [PostgreSQL](https://www.postgresql.org/) - _Stable for a long time, fast when used correctly, wide userbase, versatile_ +- Backend + - [Node.js](https://nodejs.org/en/) - _Fast to develop in, fast at runtime for our use case, now adopted by many big company, in active development, wide community, packages for many things web related_ + - [Merry](https://github.com/yoshuawuyts/merry/) **New** - _Fast, fun, opiniated but most importantly: simple_ + - [Knex](http://knexjs.org/) - _Versatile, simple, promise based, and fun SQL query builder_ +- Frontend + - [Choo](https://github.com/yoshuawuyts/choo/) **New** - _Minimal size, small API, light on tooling, thoughfully designed, fun_ + - [Tachyons](http://tachyons.io/) - _Allows for "designing" in the brower, easier changes to code, and very simple to learn and use_ +- Operations + - [Ubuntu](https://www.ubuntu.com/server) - _Easy to work with, wide adoption, package availability, most engineers have experience with it_ + - [Runit](http://smarden.org/runit/) - _Simple in design, works well as process manager, include nice guarantees for our use case_ + - [Bash Scripts](https://www.gnu.org/software/bash/) - _Known by most developers, simple, easy to read and update_ + - (If this service was to be ran in production some more heavyweight configuration management tool would most likely be used to make sure deployment scales to multiple servers and happens in a "rolling" fashion. It would also be used to provision new machines. For this challenge we'll do those steps by hand (running bash scripts that is)) ### Building From 65071849ded93c95ff738749326141999d3da901 Mon Sep 17 00:00:00 2001 From: Frederic Gingras Date: Mon, 16 Jan 2017 17:56:19 -0500 Subject: [PATCH 04/27] meta: inital node.js and client setup --- .editorconfig | 17 + .gitignore | 1 + Makefile | 31 + client/app.css | 5 + client/app.js | 30 + client/index.html | 16 + client/not-found.html | 37 + client/tachyons.min.css | 3 + package.json | 17 + server.js | 43 + yarn.lock | 3446 +++++++++++++++++++++++++++++++++++++++ 11 files changed, 3646 insertions(+) create mode 100644 .editorconfig create mode 100644 .gitignore create mode 100644 Makefile create mode 100644 client/app.css create mode 100644 client/app.js create mode 100644 client/index.html create mode 100644 client/not-found.html create mode 100644 client/tachyons.min.css create mode 100644 package.json create mode 100644 server.js create mode 100644 yarn.lock diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..788ff7f27 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,17 @@ +root = true + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true + +[*.{js,html}] +indent_style = space +indent_size = 2 + +[Makefile] +indent_style = tab + +[{package.json,.travis.yml}] +indent_style = space +indent_size = 2 diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..c2658d7d1 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +node_modules/ diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..218cf3573 --- /dev/null +++ b/Makefile @@ -0,0 +1,31 @@ +# Start the application server +run: + node --harmony server.js | ./node_modules/.bin/merry + +# Installs all required dependencies +deps: + yarn + +# Ensures your code follows the [standard](https://github.com/feross/standard) +lint: + ./node_modules/.bin/standard --fix + +# Creates a new database for the application to use (run once) +db-create: + psql -c "CREATE ROLE wave_challenge WITH SUPERUSER LOGIN PASSWORD 'wave_challenge'" + psql -c "CREATE DATABASE wave_challenge WITH OWNER wave_challenge" + +# Runs all pending migrations againt the database +db-migrate: + ./node_modules/.bin/knex migrate:latest + +# Reverts the last migration +db-rollback: + ./node_modules/.bin/knex migrate:rollback + +# Create a new migration file, call passing in a NAME for the file: +# +# make db-create-migration NAME=add-users-table +db-create-migration: + ./node_modules/.bin/knex migrate:make $(NAME) + diff --git a/client/app.css b/client/app.css new file mode 100644 index 000000000..53e4161c0 --- /dev/null +++ b/client/app.css @@ -0,0 +1,5 @@ +html, body { + font-family: sans-serif; + margin: 0; + background: #fafafa; +} diff --git a/client/app.js b/client/app.js new file mode 100644 index 000000000..1ac458996 --- /dev/null +++ b/client/app.js @@ -0,0 +1,30 @@ +var html = require('choo/html') +var choo = require('choo') +var app = choo() + +app.model({ + state: {title: 'Not quite set yet'}, + reducers: { + update: function (state, data) { + return {title: data} + } + } +}) + +function mainView (state, prev, send) { + return html` +
+

Title: ${state.title}

+ +
+ ` + + function update (e) { + send('update', e.target.value) + } +} + +app.router(['/', mainView]) + +var tree = app.start() +document.body.appendChild(tree) diff --git a/client/index.html b/client/index.html new file mode 100644 index 000000000..5d71e7ab6 --- /dev/null +++ b/client/index.html @@ -0,0 +1,16 @@ + + + + + + + + Data Import | Wave + + + + + + + + diff --git a/client/not-found.html b/client/not-found.html new file mode 100644 index 000000000..ebb8abee4 --- /dev/null +++ b/client/not-found.html @@ -0,0 +1,37 @@ + + + + Not Found | Wave + + + +

404

+

+ Sorry, we can't find the page you are looking for. +
+ Please double check the URL or return home. +

+ + diff --git a/client/tachyons.min.css b/client/tachyons.min.css new file mode 100644 index 000000000..7a74bce46 --- /dev/null +++ b/client/tachyons.min.css @@ -0,0 +1,3 @@ +/*! TACHYONS v4.6.1 | http://tachyons.io */ +/*! normalize.css v5.0.0 | MIT License | github.com/necolas/normalize.css */html{font-family:sans-serif;line-height:1.15;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}body{margin:0}article,aside,footer,header,nav,section{display:block}h1{font-size:2em;margin:.67em 0}figcaption,figure,main{display:block}figure{margin:1em 40px}hr{box-sizing:content-box;height:0;overflow:visible}pre{font-family:monospace,monospace;font-size:1em}a{background-color:transparent;-webkit-text-decoration-skip:objects}a:active,a:hover{outline-width:0}abbr[title]{border-bottom:none;text-decoration:underline;text-decoration:underline dotted}b,strong{font-weight:inherit;font-weight:bolder}code,kbd,samp{font-family:monospace,monospace;font-size:1em}dfn{font-style:italic}mark{background-color:#ff0;color:#000}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}audio,video{display:inline-block}audio:not([controls]){display:none;height:0}img{border-style:none}svg:not(:root){overflow:hidden}button,input,optgroup,select,textarea{font-family:sans-serif;font-size:100%;line-height:1.15;margin:0}button,input{overflow:visible}button,select{text-transform:none}[type=reset],[type=submit],button,html [type=button]{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}fieldset{border:1px solid silver;margin:0 2px;padding:.35em .625em .75em}legend{box-sizing:border-box;color:inherit;display:table;max-width:100%;padding:0;white-space:normal}progress{display:inline-block;vertical-align:baseline}textarea{overflow:auto}[type=checkbox],[type=radio]{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}details,menu{display:block}summary{display:list-item}canvas{display:inline-block}[hidden],template{display:none}.border-box,a,article,body,code,dd,div,dl,dt,fieldset,footer,form,h1,h2,h3,h4,h5,h6,header,html,input[type=email],input[type=number],input[type=password],input[type=tel],input[type=text],input[type=url],legend,li,main,ol,p,pre,section,table,td,textarea,th,tr,ul{box-sizing:border-box}.aspect-ratio{height:0;position:relative}.aspect-ratio--16x9{padding-bottom:56.25%}.aspect-ratio--9x16{padding-bottom:177.77%}.aspect-ratio--4x3{padding-bottom:75%}.aspect-ratio--3x4{padding-bottom:133.33%}.aspect-ratio--6x4{padding-bottom:66.6%}.aspect-ratio--4x6{padding-bottom:150%}.aspect-ratio--8x5{padding-bottom:62.5%}.aspect-ratio--5x8{padding-bottom:160%}.aspect-ratio--7x5{padding-bottom:71.42%}.aspect-ratio--5x7{padding-bottom:140%}.aspect-ratio--1x1{padding-bottom:100%}.aspect-ratio--object{position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%;z-index:100}img{max-width:100%}.cover{background-size:cover!important}.contain{background-size:contain!important}.bg-center{background-position:50%}.bg-center,.bg-top{background-repeat:no-repeat}.bg-top{background-position:top}.bg-right{background-position:100%}.bg-bottom,.bg-right{background-repeat:no-repeat}.bg-bottom{background-position:bottom}.bg-left{background-repeat:no-repeat;background-position:0}.outline{outline:1px solid}.outline-transparent{outline:1px solid transparent}.outline-0{outline:0}.ba{border-style:solid;border-width:1px}.bt{border-top-style:solid;border-top-width:1px}.br{border-right-style:solid;border-right-width:1px}.bb{border-bottom-style:solid;border-bottom-width:1px}.bl{border-left-style:solid;border-left-width:1px}.bn{border-style:none;border-width:0}.b--black{border-color:#000}.b--near-black{border-color:#111}.b--dark-gray{border-color:#333}.b--mid-gray{border-color:#555}.b--gray{border-color:#777}.b--silver{border-color:#999}.b--light-silver{border-color:#aaa}.b--light-gray{border-color:#eee}.b--near-white{border-color:#f4f4f4}.b--white{border-color:#fff}.b--white-90{border-color:hsla(0,0%,100%,.9)}.b--white-80{border-color:hsla(0,0%,100%,.8)}.b--white-70{border-color:hsla(0,0%,100%,.7)}.b--white-60{border-color:hsla(0,0%,100%,.6)}.b--white-50{border-color:hsla(0,0%,100%,.5)}.b--white-40{border-color:hsla(0,0%,100%,.4)}.b--white-30{border-color:hsla(0,0%,100%,.3)}.b--white-20{border-color:hsla(0,0%,100%,.2)}.b--white-10{border-color:hsla(0,0%,100%,.1)}.b--white-05{border-color:hsla(0,0%,100%,.05)}.b--white-025{border-color:hsla(0,0%,100%,.025)}.b--white-0125{border-color:hsla(0,0%,100%,.0125)}.b--black-90{border-color:rgba(0,0,0,.9)}.b--black-80{border-color:rgba(0,0,0,.8)}.b--black-70{border-color:rgba(0,0,0,.7)}.b--black-60{border-color:rgba(0,0,0,.6)}.b--black-50{border-color:rgba(0,0,0,.5)}.b--black-40{border-color:rgba(0,0,0,.4)}.b--black-30{border-color:rgba(0,0,0,.3)}.b--black-20{border-color:rgba(0,0,0,.2)}.b--black-10{border-color:rgba(0,0,0,.1)}.b--black-05{border-color:rgba(0,0,0,.05)}.b--black-025{border-color:rgba(0,0,0,.025)}.b--black-0125{border-color:rgba(0,0,0,.0125)}.b--dark-red{border-color:#e7040f}.b--red{border-color:#ff4136}.b--light-red{border-color:#ff725c}.b--orange{border-color:#ff6300}.b--gold{border-color:#ffb700}.b--yellow{border-color:gold}.b--light-yellow{border-color:#fbf1a9}.b--purple{border-color:#5e2ca5}.b--light-purple{border-color:#a463f2}.b--dark-pink{border-color:#d5008f}.b--hot-pink{border-color:#ff41b4}.b--pink{border-color:#ff80cc}.b--light-pink{border-color:#ffa3d7}.b--dark-green{border-color:#137752}.b--green{border-color:#19a974}.b--light-green{border-color:#9eebcf}.b--navy{border-color:#001b44}.b--dark-blue{border-color:#00449e}.b--blue{border-color:#357edd}.b--light-blue{border-color:#96ccff}.b--lightest-blue{border-color:#cdecff}.b--washed-blue{border-color:#f6fffe}.b--washed-green{border-color:#e8fdf5}.b--washed-yellow{border-color:#fffceb}.b--washed-red{border-color:#ffdfdf}.b--transparent{border-color:transparent}.br0{border-radius:0}.br1{border-radius:.125rem}.br2{border-radius:.25rem}.br3{border-radius:.5rem}.br4{border-radius:1rem}.br-100{border-radius:100%}.br-pill{border-radius:9999px}.br--bottom{border-top-left-radius:0;border-top-right-radius:0}.br--top{border-bottom-right-radius:0}.br--right,.br--top{border-bottom-left-radius:0}.br--right{border-top-left-radius:0}.br--left{border-top-right-radius:0;border-bottom-right-radius:0}.b--dotted{border-style:dotted}.b--dashed{border-style:dashed}.b--solid{border-style:solid}.b--none{border-style:none}.bw0{border-width:0}.bw1{border-width:.125rem}.bw2{border-width:.25rem}.bw3{border-width:.5rem}.bw4{border-width:1rem}.bw5{border-width:2rem}.bt-0{border-top-width:0}.br-0{border-right-width:0}.bb-0{border-bottom-width:0}.bl-0{border-left-width:0}.shadow-1{box-shadow:0 0 4px 2px rgba(0,0,0,.2)}.shadow-2{box-shadow:0 0 8px 2px rgba(0,0,0,.2)}.shadow-3{box-shadow:2px 2px 4px 2px rgba(0,0,0,.2)}.shadow-4{box-shadow:2px 2px 8px 0 rgba(0,0,0,.2)}.shadow-5{box-shadow:4px 4px 8px 0 rgba(0,0,0,.2)}.pre{overflow-x:auto;overflow-y:hidden;overflow:scroll}.top-0{top:0}.right-0{right:0}.bottom-0{bottom:0}.left-0{left:0}.top-1{top:1rem}.right-1{right:1rem}.bottom-1{bottom:1rem}.left-1{left:1rem}.top-2{top:2rem}.right-2{right:2rem}.bottom-2{bottom:2rem}.left-2{left:2rem}.top--1{top:-1rem}.right--1{right:-1rem}.bottom--1{bottom:-1rem}.left--1{left:-1rem}.top--2{top:-2rem}.right--2{right:-2rem}.bottom--2{bottom:-2rem}.left--2{left:-2rem}.absolute--fill{top:0;right:0;bottom:0;left:0}.cf:after,.cf:before{content:" ";display:table}.cf:after{clear:both}.cf{*zoom:1}.cl{clear:left}.cr{clear:right}.cb{clear:both}.cn{clear:none}.dn{display:none}.di{display:inline}.db{display:block}.dib{display:inline-block}.dit{display:inline-table}.dt{display:table}.dtc{display:table-cell}.dt-row{display:table-row}.dt-row-group{display:table-row-group}.dt-column{display:table-column}.dt-column-group{display:table-column-group}.dt--fixed{table-layout:fixed;width:100%}.flex{display:-webkit-box;display:-ms-flexbox;display:flex}.inline-flex{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex}.flex-auto{-webkit-box-flex:1;-ms-flex:1 1 auto;flex:1 1 auto;min-width:0;min-height:0}.flex-none{-webkit-box-flex:0;-ms-flex:none;flex:none}.flex-column{-webkit-box-orient:vertical;-ms-flex-direction:column;flex-direction:column}.flex-column,.flex-row{-webkit-box-direction:normal}.flex-row{-webkit-box-orient:horizontal;-ms-flex-direction:row;flex-direction:row}.flex-wrap{-ms-flex-wrap:wrap;flex-wrap:wrap}.items-start{-webkit-box-align:start;-ms-flex-align:start;align-items:flex-start}.items-end{-webkit-box-align:end;-ms-flex-align:end;align-items:flex-end}.items-center{-webkit-box-align:center;-ms-flex-align:center;align-items:center}.items-baseline{-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline}.items-stretch{-webkit-box-align:stretch;-ms-flex-align:stretch;align-items:stretch}.self-start{-ms-flex-item-align:start;align-self:flex-start}.self-end{-ms-flex-item-align:end;align-self:flex-end}.self-center{-ms-flex-item-align:center;-ms-grid-row-align:center;align-self:center}.self-baseline{-ms-flex-item-align:baseline;align-self:baseline}.self-stretch{-ms-flex-item-align:stretch;-ms-grid-row-align:stretch;align-self:stretch}.justify-start{-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start}.justify-end{-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end}.justify-center{-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.justify-between{-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.justify-around{-ms-flex-pack:distribute;justify-content:space-around}.content-start{-ms-flex-line-pack:start;align-content:flex-start}.content-end{-ms-flex-line-pack:end;align-content:flex-end}.content-center{-ms-flex-line-pack:center;align-content:center}.content-between{-ms-flex-line-pack:justify;align-content:space-between}.content-around{-ms-flex-line-pack:distribute;align-content:space-around}.content-stretch{-ms-flex-line-pack:stretch;align-content:stretch}.order-0{-webkit-box-ordinal-group:1;-ms-flex-order:0;order:0}.order-1{-webkit-box-ordinal-group:2;-ms-flex-order:1;order:1}.order-2{-webkit-box-ordinal-group:3;-ms-flex-order:2;order:2}.order-3{-webkit-box-ordinal-group:4;-ms-flex-order:3;order:3}.order-4{-webkit-box-ordinal-group:5;-ms-flex-order:4;order:4}.order-5{-webkit-box-ordinal-group:6;-ms-flex-order:5;order:5}.order-6{-webkit-box-ordinal-group:7;-ms-flex-order:6;order:6}.order-7{-webkit-box-ordinal-group:8;-ms-flex-order:7;order:7}.order-8{-webkit-box-ordinal-group:9;-ms-flex-order:8;order:8}.order-last{-webkit-box-ordinal-group:100000;-ms-flex-order:99999;order:99999}.fl{float:left}.fl,.fr{_display:inline}.fr{float:right}.fn{float:none}.sans-serif{font-family:-apple-system,BlinkMacSystemFont,avenir next,avenir,helvetica neue,helvetica,ubuntu,roboto,noto,segoe ui,arial,sans-serif}.serif{font-family:georgia,times,serif}.system-sans-serif{font-family:sans-serif}.system-serif{font-family:serif}.code,code{font-family:Consolas,monaco,monospace}.courier{font-family:Courier Next,courier,monospace}.helvetica{font-family:helvetica neue,helvetica,sans-serif}.avenir{font-family:avenir next,avenir,sans-serif}.athelas{font-family:athelas,georgia,serif}.georgia{font-family:georgia,serif}.times{font-family:times,serif}.bodoni{font-family:Bodoni MT,serif}.calisto{font-family:Calisto MT,serif}.garamond{font-family:garamond,serif}.baskerville{font-family:baskerville,serif}.i{font-style:italic}.fs-normal{font-style:normal}.normal{font-weight:400}.b{font-weight:700}.fw1{font-weight:100}.fw2{font-weight:200}.fw3{font-weight:300}.fw4{font-weight:400}.fw5{font-weight:500}.fw6{font-weight:600}.fw7{font-weight:700}.fw8{font-weight:800}.fw9{font-weight:900}.input-reset{-webkit-appearance:none;-moz-appearance:none}.button-reset::-moz-focus-inner,.input-reset::-moz-focus-inner{border:0;padding:0}.h1{height:1rem}.h2{height:2rem}.h3{height:4rem}.h4{height:8rem}.h5{height:16rem}.h-25{height:25%}.h-50{height:50%}.h-75{height:75%}.h-100{height:100%}.min-h-100{min-height:100%}.vh-25{height:25vh}.vh-50{height:50vh}.vh-75{height:75vh}.vh-100{height:100vh}.min-vh-100{min-height:100vh}.h-auto{height:auto}.h-inherit{height:inherit}.tracked{letter-spacing:.1em}.tracked-tight{letter-spacing:-.05em}.tracked-mega{letter-spacing:.25em}.lh-solid{line-height:1}.lh-title{line-height:1.25}.lh-copy{line-height:1.5}.link{text-decoration:none}.link,.link:active,.link:focus,.link:hover,.link:link,.link:visited{-webkit-transition:color .15s ease-in;transition:color .15s ease-in}.link:focus{outline:1px dotted currentColor}.list{list-style-type:none}.mw-100{max-width:100%}.mw1{max-width:1rem}.mw2{max-width:2rem}.mw3{max-width:4rem}.mw4{max-width:8rem}.mw5{max-width:16rem}.mw6{max-width:32rem}.mw7{max-width:48rem}.mw8{max-width:64rem}.mw9{max-width:96rem}.mw-none{max-width:none}.w1{width:1rem}.w2{width:2rem}.w3{width:4rem}.w4{width:8rem}.w5{width:16rem}.w-10{width:10%}.w-20{width:20%}.w-25{width:25%}.w-30{width:30%}.w-33{width:33%}.w-34{width:34%}.w-40{width:40%}.w-50{width:50%}.w-60{width:60%}.w-70{width:70%}.w-75{width:75%}.w-80{width:80%}.w-90{width:90%}.w-100{width:100%}.w-third{width:33.33333%}.w-two-thirds{width:66.66667%}.w-auto{width:auto}.overflow-visible{overflow:visible}.overflow-hidden{overflow:hidden}.overflow-scroll{overflow:scroll}.overflow-auto{overflow:auto}.overflow-x-visible{overflow-x:visible}.overflow-x-hidden{overflow-x:hidden}.overflow-x-scroll{overflow-x:scroll}.overflow-x-auto{overflow-x:auto}.overflow-y-visible{overflow-y:visible}.overflow-y-hidden{overflow-y:hidden}.overflow-y-scroll{overflow-y:scroll}.overflow-y-auto{overflow-y:auto}.static{position:static}.relative{position:relative}.absolute{position:absolute}.fixed{position:fixed}.o-100{opacity:1}.o-90{opacity:.9}.o-80{opacity:.8}.o-70{opacity:.7}.o-60{opacity:.6}.o-50{opacity:.5}.o-40{opacity:.4}.o-30{opacity:.3}.o-20{opacity:.2}.o-10{opacity:.1}.o-05{opacity:.05}.o-025{opacity:.025}.o-0{opacity:0}.rotate-45{-webkit-transform:rotate(45deg);transform:rotate(45deg)}.rotate-90{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.rotate-135{-webkit-transform:rotate(135deg);transform:rotate(135deg)}.rotate-180{-webkit-transform:rotate(180deg);transform:rotate(180deg)}.rotate-225{-webkit-transform:rotate(225deg);transform:rotate(225deg)}.rotate-270{-webkit-transform:rotate(270deg);transform:rotate(270deg)}.rotate-315{-webkit-transform:rotate(315deg);transform:rotate(315deg)}.black-90{color:rgba(0,0,0,.9)}.black-80{color:rgba(0,0,0,.8)}.black-70{color:rgba(0,0,0,.7)}.black-60{color:rgba(0,0,0,.6)}.black-50{color:rgba(0,0,0,.5)}.black-40{color:rgba(0,0,0,.4)}.black-30{color:rgba(0,0,0,.3)}.black-20{color:rgba(0,0,0,.2)}.black-10{color:rgba(0,0,0,.1)}.black-05{color:rgba(0,0,0,.05)}.white-90{color:hsla(0,0%,100%,.9)}.white-80{color:hsla(0,0%,100%,.8)}.white-70{color:hsla(0,0%,100%,.7)}.white-60{color:hsla(0,0%,100%,.6)}.white-50{color:hsla(0,0%,100%,.5)}.white-40{color:hsla(0,0%,100%,.4)}.white-30{color:hsla(0,0%,100%,.3)}.white-20{color:hsla(0,0%,100%,.2)}.white-10{color:hsla(0,0%,100%,.1)}.black{color:#000}.near-black{color:#111}.dark-gray{color:#333}.mid-gray{color:#555}.gray{color:#777}.silver{color:#999}.light-silver{color:#aaa}.moon-gray{color:#ccc}.light-gray{color:#eee}.near-white{color:#f4f4f4}.white{color:#fff}.dark-red{color:#e7040f}.red{color:#ff4136}.light-red{color:#ff725c}.orange{color:#ff6300}.gold{color:#ffb700}.yellow{color:gold}.light-yellow{color:#fbf1a9}.purple{color:#5e2ca5}.light-purple{color:#a463f2}.dark-pink{color:#d5008f}.hot-pink{color:#ff41b4}.pink{color:#ff80cc}.light-pink{color:#ffa3d7}.dark-green{color:#137752}.green{color:#19a974}.light-green{color:#9eebcf}.navy{color:#001b44}.dark-blue{color:#00449e}.blue{color:#357edd}.light-blue{color:#96ccff}.lightest-blue{color:#cdecff}.washed-blue{color:#f6fffe}.washed-green{color:#e8fdf5}.washed-yellow{color:#fffceb}.washed-red{color:#ffdfdf}.bg-black-90{background-color:rgba(0,0,0,.9)}.bg-black-80{background-color:rgba(0,0,0,.8)}.bg-black-70{background-color:rgba(0,0,0,.7)}.bg-black-60{background-color:rgba(0,0,0,.6)}.bg-black-50{background-color:rgba(0,0,0,.5)}.bg-black-40{background-color:rgba(0,0,0,.4)}.bg-black-30{background-color:rgba(0,0,0,.3)}.bg-black-20{background-color:rgba(0,0,0,.2)}.bg-black-10{background-color:rgba(0,0,0,.1)}.bg-black-05{background-color:rgba(0,0,0,.05)}.bg-white-90{background-color:hsla(0,0%,100%,.9)}.bg-white-80{background-color:hsla(0,0%,100%,.8)}.bg-white-70{background-color:hsla(0,0%,100%,.7)}.bg-white-60{background-color:hsla(0,0%,100%,.6)}.bg-white-50{background-color:hsla(0,0%,100%,.5)}.bg-white-40{background-color:hsla(0,0%,100%,.4)}.bg-white-30{background-color:hsla(0,0%,100%,.3)}.bg-white-20{background-color:hsla(0,0%,100%,.2)}.bg-white-10{background-color:hsla(0,0%,100%,.1)}.bg-black{background-color:#000}.bg-near-black{background-color:#111}.bg-dark-gray{background-color:#333}.bg-mid-gray{background-color:#555}.bg-gray{background-color:#777}.bg-silver{background-color:#999}.bg-light-silver{background-color:#aaa}.bg-moon-gray{background-color:#ccc}.bg-light-gray{background-color:#eee}.bg-near-white{background-color:#f4f4f4}.bg-white{background-color:#fff}.bg-transparent{background-color:transparent}.bg-dark-red{background-color:#e7040f}.bg-red{background-color:#ff4136}.bg-light-red{background-color:#ff725c}.bg-orange{background-color:#ff6300}.bg-gold{background-color:#ffb700}.bg-yellow{background-color:gold}.bg-light-yellow{background-color:#fbf1a9}.bg-purple{background-color:#5e2ca5}.bg-light-purple{background-color:#a463f2}.bg-dark-pink{background-color:#d5008f}.bg-hot-pink{background-color:#ff41b4}.bg-pink{background-color:#ff80cc}.bg-light-pink{background-color:#ffa3d7}.bg-dark-green{background-color:#137752}.bg-green{background-color:#19a974}.bg-light-green{background-color:#9eebcf}.bg-navy{background-color:#001b44}.bg-dark-blue{background-color:#00449e}.bg-blue{background-color:#357edd}.bg-light-blue{background-color:#96ccff}.bg-lightest-blue{background-color:#cdecff}.bg-washed-blue{background-color:#f6fffe}.bg-washed-green{background-color:#e8fdf5}.bg-washed-yellow{background-color:#fffceb}.bg-washed-red{background-color:#ffdfdf}.hover-black:focus,.hover-black:hover{color:#000}.hover-near-black:focus,.hover-near-black:hover{color:#111}.hover-dark-gray:focus,.hover-dark-gray:hover{color:#333}.hover-mid-gray:focus,.hover-mid-gray:hover{color:#555}.hover-gray:focus,.hover-gray:hover{color:#777}.hover-silver:focus,.hover-silver:hover{color:#999}.hover-light-silver:focus,.hover-light-silver:hover{color:#aaa}.hover-moon-gray:focus,.hover-moon-gray:hover{color:#ccc}.hover-light-gray:focus,.hover-light-gray:hover{color:#eee}.hover-near-white:focus,.hover-near-white:hover{color:#f4f4f4}.hover-white:focus,.hover-white:hover{color:#fff}.hover-black-90:focus,.hover-black-90:hover{color:rgba(0,0,0,.9)}.hover-black-80:focus,.hover-black-80:hover{color:rgba(0,0,0,.8)}.hover-black-70:focus,.hover-black-70:hover{color:rgba(0,0,0,.7)}.hover-black-60:focus,.hover-black-60:hover{color:rgba(0,0,0,.6)}.hover-black-50:focus,.hover-black-50:hover{color:rgba(0,0,0,.5)}.hover-black-40:focus,.hover-black-40:hover{color:rgba(0,0,0,.4)}.hover-black-30:focus,.hover-black-30:hover{color:rgba(0,0,0,.3)}.hover-black-20:focus,.hover-black-20:hover{color:rgba(0,0,0,.2)}.hover-black-10:focus,.hover-black-10:hover{color:rgba(0,0,0,.1)}.hover-white-90:focus,.hover-white-90:hover{color:hsla(0,0%,100%,.9)}.hover-white-80:focus,.hover-white-80:hover{color:hsla(0,0%,100%,.8)}.hover-white-70:focus,.hover-white-70:hover{color:hsla(0,0%,100%,.7)}.hover-white-60:focus,.hover-white-60:hover{color:hsla(0,0%,100%,.6)}.hover-white-50:focus,.hover-white-50:hover{color:hsla(0,0%,100%,.5)}.hover-white-40:focus,.hover-white-40:hover{color:hsla(0,0%,100%,.4)}.hover-white-30:focus,.hover-white-30:hover{color:hsla(0,0%,100%,.3)}.hover-white-20:focus,.hover-white-20:hover{color:hsla(0,0%,100%,.2)}.hover-white-10:focus,.hover-white-10:hover{color:hsla(0,0%,100%,.1)}.hover-bg-black:focus,.hover-bg-black:hover{background-color:#000}.hover-bg-near-black:focus,.hover-bg-near-black:hover{background-color:#111}.hover-bg-dark-gray:focus,.hover-bg-dark-gray:hover{background-color:#333}.hover-bg-dark-gray:focus,.hover-bg-mid-gray:hover{background-color:#555}.hover-bg-gray:focus,.hover-bg-gray:hover{background-color:#777}.hover-bg-silver:focus,.hover-bg-silver:hover{background-color:#999}.hover-bg-light-silver:focus,.hover-bg-light-silver:hover{background-color:#aaa}.hover-bg-moon-gray:focus,.hover-bg-moon-gray:hover{background-color:#ccc}.hover-bg-light-gray:focus,.hover-bg-light-gray:hover{background-color:#eee}.hover-bg-near-white:focus,.hover-bg-near-white:hover{background-color:#f4f4f4}.hover-bg-white:focus,.hover-bg-white:hover{background-color:#fff}.hover-bg-transparent:focus,.hover-bg-transparent:hover{background-color:transparent}.hover-bg-black-90:focus,.hover-bg-black-90:hover{background-color:rgba(0,0,0,.9)}.hover-bg-black-80:focus,.hover-bg-black-80:hover{background-color:rgba(0,0,0,.8)}.hover-bg-black-70:focus,.hover-bg-black-70:hover{background-color:rgba(0,0,0,.7)}.hover-bg-black-60:focus,.hover-bg-black-60:hover{background-color:rgba(0,0,0,.6)}.hover-bg-black-50:focus,.hover-bg-black-50:hover{background-color:rgba(0,0,0,.5)}.hover-bg-black-40:focus,.hover-bg-black-40:hover{background-color:rgba(0,0,0,.4)}.hover-bg-black-30:focus,.hover-bg-black-30:hover{background-color:rgba(0,0,0,.3)}.hover-bg-black-20:focus,.hover-bg-black-20:hover{background-color:rgba(0,0,0,.2)}.hover-bg-black-10:focus,.hover-bg-black-10:hover{background-color:rgba(0,0,0,.1)}.hover-bg-white-90:focus,.hover-bg-white-90:hover{background-color:hsla(0,0%,100%,.9)}.hover-bg-white-80:focus,.hover-bg-white-80:hover{background-color:hsla(0,0%,100%,.8)}.hover-bg-white-70:focus,.hover-bg-white-70:hover{background-color:hsla(0,0%,100%,.7)}.hover-bg-white-60:focus,.hover-bg-white-60:hover{background-color:hsla(0,0%,100%,.6)}.hover-bg-white-50:focus,.hover-bg-white-50:hover{background-color:hsla(0,0%,100%,.5)}.hover-bg-white-40:focus,.hover-bg-white-40:hover{background-color:hsla(0,0%,100%,.4)}.hover-bg-white-30:focus,.hover-bg-white-30:hover{background-color:hsla(0,0%,100%,.3)}.hover-bg-white-20:focus,.hover-bg-white-20:hover{background-color:hsla(0,0%,100%,.2)}.hover-bg-white-10:focus,.hover-bg-white-10:hover{background-color:hsla(0,0%,100%,.1)}.hover-dark-red:focus,.hover-dark-red:hover{color:#e7040f}.hover-red:focus,.hover-red:hover{color:#ff4136}.hover-light-red:focus,.hover-light-red:hover{color:#ff725c}.hover-orange:focus,.hover-orange:hover{color:#ff6300}.hover-gold:focus,.hover-gold:hover{color:#ffb700}.hover-yellow:focus,.hover-yellow:hover{color:gold}.hover-light-yellow:focus,.hover-light-yellow:hover{color:#fbf1a9}.hover-purple:focus,.hover-purple:hover{color:#5e2ca5}.hover-light-purple:focus,.hover-light-purple:hover{color:#a463f2}.hover-dark-pink:focus,.hover-dark-pink:hover{color:#d5008f}.hover-hot-pink:focus,.hover-hot-pink:hover{color:#ff41b4}.hover-pink:focus,.hover-pink:hover{color:#ff80cc}.hover-light-pink:focus,.hover-light-pink:hover{color:#ffa3d7}.hover-dark-green:focus,.hover-dark-green:hover{color:#137752}.hover-green:focus,.hover-green:hover{color:#19a974}.hover-light-green:focus,.hover-light-green:hover{color:#9eebcf}.hover-navy:focus,.hover-navy:hover{color:#001b44}.hover-dark-blue:focus,.hover-dark-blue:hover{color:#00449e}.hover-blue:focus,.hover-blue:hover{color:#357edd}.hover-light-blue:focus,.hover-light-blue:hover{color:#96ccff}.hover-lightest-blue:focus,.hover-lightest-blue:hover{color:#cdecff}.hover-washed-blue:focus,.hover-washed-blue:hover{color:#f6fffe}.hover-washed-green:focus,.hover-washed-green:hover{color:#e8fdf5}.hover-washed-yellow:focus,.hover-washed-yellow:hover{color:#fffceb}.hover-washed-red:focus,.hover-washed-red:hover{color:#ffdfdf}.hover-bg-dark-red:focus,.hover-bg-dark-red:hover{background-color:#e7040f}.hover-bg-red:focus,.hover-bg-red:hover{background-color:#ff4136}.hover-bg-light-red:focus,.hover-bg-light-red:hover{background-color:#ff725c}.hover-bg-orange:focus,.hover-bg-orange:hover{background-color:#ff6300}.hover-bg-gold:focus,.hover-bg-gold:hover{background-color:#ffb700}.hover-bg-yellow:focus,.hover-bg-yellow:hover{background-color:gold}.hover-bg-light-yellow:focus,.hover-bg-light-yellow:hover{background-color:#fbf1a9}.hover-bg-purple:focus,.hover-bg-purple:hover{background-color:#5e2ca5}.hover-bg-light-purple:focus,.hover-bg-light-purple:hover{background-color:#a463f2}.hover-bg-dark-pink:focus,.hover-bg-dark-pink:hover{background-color:#d5008f}.hover-bg-hot-pink:focus,.hover-bg-hot-pink:hover{background-color:#ff41b4}.hover-bg-pink:focus,.hover-bg-pink:hover{background-color:#ff80cc}.hover-bg-light-pink:focus,.hover-bg-light-pink:hover{background-color:#ffa3d7}.hover-bg-dark-green:focus,.hover-bg-dark-green:hover{background-color:#137752}.hover-bg-green:focus,.hover-bg-green:hover{background-color:#19a974}.hover-bg-light-green:focus,.hover-bg-light-green:hover{background-color:#9eebcf}.hover-bg-navy:focus,.hover-bg-navy:hover{background-color:#001b44}.hover-bg-dark-blue:focus,.hover-bg-dark-blue:hover{background-color:#00449e}.hover-bg-blue:focus,.hover-bg-blue:hover{background-color:#357edd}.hover-bg-light-blue:focus,.hover-bg-light-blue:hover{background-color:#96ccff}.hover-bg-lightest-blue:focus,.hover-bg-lightest-blue:hover{background-color:#cdecff}.hover-bg-washed-blue:focus,.hover-bg-washed-blue:hover{background-color:#f6fffe}.hover-bg-washed-green:focus,.hover-bg-washed-green:hover{background-color:#e8fdf5}.hover-bg-washed-yellow:focus,.hover-bg-washed-yellow:hover{background-color:#fffceb}.hover-bg-washed-red:focus,.hover-bg-washed-red:hover{background-color:#ffdfdf}.pa0{padding:0}.pa1{padding:.25rem}.pa2{padding:.5rem}.pa3{padding:1rem}.pa4{padding:2rem}.pa5{padding:4rem}.pa6{padding:8rem}.pa7{padding:16rem}.pl0{padding-left:0}.pl1{padding-left:.25rem}.pl2{padding-left:.5rem}.pl3{padding-left:1rem}.pl4{padding-left:2rem}.pl5{padding-left:4rem}.pl6{padding-left:8rem}.pl7{padding-left:16rem}.pr0{padding-right:0}.pr1{padding-right:.25rem}.pr2{padding-right:.5rem}.pr3{padding-right:1rem}.pr4{padding-right:2rem}.pr5{padding-right:4rem}.pr6{padding-right:8rem}.pr7{padding-right:16rem}.pb0{padding-bottom:0}.pb1{padding-bottom:.25rem}.pb2{padding-bottom:.5rem}.pb3{padding-bottom:1rem}.pb4{padding-bottom:2rem}.pb5{padding-bottom:4rem}.pb6{padding-bottom:8rem}.pb7{padding-bottom:16rem}.pt0{padding-top:0}.pt1{padding-top:.25rem}.pt2{padding-top:.5rem}.pt3{padding-top:1rem}.pt4{padding-top:2rem}.pt5{padding-top:4rem}.pt6{padding-top:8rem}.pt7{padding-top:16rem}.pv0{padding-top:0;padding-bottom:0}.pv1{padding-top:.25rem;padding-bottom:.25rem}.pv2{padding-top:.5rem;padding-bottom:.5rem}.pv3{padding-top:1rem;padding-bottom:1rem}.pv4{padding-top:2rem;padding-bottom:2rem}.pv5{padding-top:4rem;padding-bottom:4rem}.pv6{padding-top:8rem;padding-bottom:8rem}.pv7{padding-top:16rem;padding-bottom:16rem}.ph0{padding-left:0;padding-right:0}.ph1{padding-left:.25rem;padding-right:.25rem}.ph2{padding-left:.5rem;padding-right:.5rem}.ph3{padding-left:1rem;padding-right:1rem}.ph4{padding-left:2rem;padding-right:2rem}.ph5{padding-left:4rem;padding-right:4rem}.ph6{padding-left:8rem;padding-right:8rem}.ph7{padding-left:16rem;padding-right:16rem}.ma0{margin:0}.ma1{margin:.25rem}.ma2{margin:.5rem}.ma3{margin:1rem}.ma4{margin:2rem}.ma5{margin:4rem}.ma6{margin:8rem}.ma7{margin:16rem}.ml0{margin-left:0}.ml1{margin-left:.25rem}.ml2{margin-left:.5rem}.ml3{margin-left:1rem}.ml4{margin-left:2rem}.ml5{margin-left:4rem}.ml6{margin-left:8rem}.ml7{margin-left:16rem}.mr0{margin-right:0}.mr1{margin-right:.25rem}.mr2{margin-right:.5rem}.mr3{margin-right:1rem}.mr4{margin-right:2rem}.mr5{margin-right:4rem}.mr6{margin-right:8rem}.mr7{margin-right:16rem}.mb0{margin-bottom:0}.mb1{margin-bottom:.25rem}.mb2{margin-bottom:.5rem}.mb3{margin-bottom:1rem}.mb4{margin-bottom:2rem}.mb5{margin-bottom:4rem}.mb6{margin-bottom:8rem}.mb7{margin-bottom:16rem}.mt0{margin-top:0}.mt1{margin-top:.25rem}.mt2{margin-top:.5rem}.mt3{margin-top:1rem}.mt4{margin-top:2rem}.mt5{margin-top:4rem}.mt6{margin-top:8rem}.mt7{margin-top:16rem}.mv0{margin-top:0;margin-bottom:0}.mv1{margin-top:.25rem;margin-bottom:.25rem}.mv2{margin-top:.5rem;margin-bottom:.5rem}.mv3{margin-top:1rem;margin-bottom:1rem}.mv4{margin-top:2rem;margin-bottom:2rem}.mv5{margin-top:4rem;margin-bottom:4rem}.mv6{margin-top:8rem;margin-bottom:8rem}.mv7{margin-top:16rem;margin-bottom:16rem}.mh0{margin-left:0;margin-right:0}.mh1{margin-left:.25rem;margin-right:.25rem}.mh2{margin-left:.5rem;margin-right:.5rem}.mh3{margin-left:1rem;margin-right:1rem}.mh4{margin-left:2rem;margin-right:2rem}.mh5{margin-left:4rem;margin-right:4rem}.mh6{margin-left:8rem;margin-right:8rem}.mh7{margin-left:16rem;margin-right:16rem}.na1{margin:-.25rem}.na2{margin:-.5rem}.na3{margin:-1rem}.na4{margin:-2rem}.na5{margin:-4rem}.na6{margin:-8rem}.na7{margin:-16rem}.nl1{margin-left:-.25rem}.nl2{margin-left:-.5rem}.nl3{margin-left:-1rem}.nl4{margin-left:-2rem}.nl5{margin-left:-4rem}.nl6{margin-left:-8rem}.nl7{margin-left:-16rem}.nr1{margin-right:-.25rem}.nr2{margin-right:-.5rem}.nr3{margin-right:-1rem}.nr4{margin-right:-2rem}.nr5{margin-right:-4rem}.nr6{margin-right:-8rem}.nr7{margin-right:-16rem}.nb1{margin-bottom:-.25rem}.nb2{margin-bottom:-.5rem}.nb3{margin-bottom:-1rem}.nb4{margin-bottom:-2rem}.nb5{margin-bottom:-4rem}.nb6{margin-bottom:-8rem}.nb7{margin-bottom:-16rem}.nt1{margin-top:-.25rem}.nt2{margin-top:-.5rem}.nt3{margin-top:-1rem}.nt4{margin-top:-2rem}.nt5{margin-top:-4rem}.nt6{margin-top:-8rem}.nt7{margin-top:-16rem}.collapse{border-collapse:collapse;border-spacing:0}.striped--light-silver:nth-child(odd){background-color:#aaa}.striped--moon-gray:nth-child(odd){background-color:#ccc}.striped--light-gray:nth-child(odd){background-color:#eee}.striped--near-white:nth-child(odd){background-color:#f4f4f4}.stripe-light:nth-child(odd){background-color:hsla(0,0%,100%,.1)}.stripe-dark:nth-child(odd){background-color:rgba(0,0,0,.1)}.strike{text-decoration:line-through}.underline{text-decoration:underline}.no-underline{text-decoration:none}.tl{text-align:left}.tr{text-align:right}.tc{text-align:center}.ttc{text-transform:capitalize}.ttl{text-transform:lowercase}.ttu{text-transform:uppercase}.ttn{text-transform:none}.f-6,.f-headline{font-size:6rem}.f-5,.f-subheadline{font-size:5rem}.f1{font-size:3rem}.f2{font-size:2.25rem}.f3{font-size:1.5rem}.f4{font-size:1.25rem}.f5{font-size:1rem}.f6{font-size:.875rem}.measure{max-width:30em}.measure-wide{max-width:34em}.measure-narrow{max-width:20em}.indent{text-indent:1em;margin-top:0;margin-bottom:0}.small-caps{font-variant:small-caps}.truncate{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.overflow-container{overflow-y:scroll}.center{margin-right:auto;margin-left:auto}.clip{position:fixed!important;_position:absolute!important;clip:rect(1px 1px 1px 1px);clip:rect(1px,1px,1px,1px)}.ws-normal{white-space:normal}.nowrap{white-space:nowrap}.pre{white-space:pre}.v-base{vertical-align:baseline}.v-mid{vertical-align:middle}.v-top{vertical-align:top}.v-btm{vertical-align:bottom}.dim{opacity:1}.dim,.dim:focus,.dim:hover{-webkit-transition:opacity .15s ease-in;transition:opacity .15s ease-in}.dim:focus,.dim:hover{opacity:.5}.dim:active{opacity:.8;-webkit-transition:opacity .15s ease-out;transition:opacity .15s ease-out}.glow,.glow:focus,.glow:hover{-webkit-transition:opacity .15s ease-in;transition:opacity .15s ease-in}.glow:focus,.glow:hover{opacity:1}.hide-child .child{opacity:0;-webkit-transition:opacity .15s ease-in;transition:opacity .15s ease-in}.hide-child:active .child,.hide-child:focus .child,.hide-child:hover .child{opacity:1;-webkit-transition:opacity .15s ease-in;transition:opacity .15s ease-in}.underline-hover:focus,.underline-hover:hover{text-decoration:underline}.grow{-moz-osx-font-smoothing:grayscale;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-transform:translateZ(0);transform:translateZ(0);-webkit-transition:-webkit-transform .25s ease-out;transition:-webkit-transform .25s ease-out;transition:transform .25s ease-out;transition:transform .25s ease-out,-webkit-transform .25s ease-out}.grow:focus,.grow:hover{-webkit-transform:scale(1.05);transform:scale(1.05)}.grow:active{-webkit-transform:scale(.9);transform:scale(.9)}.grow-large{-moz-osx-font-smoothing:grayscale;-webkit-backface-visibility:hidden;backface-visibility:hidden;-webkit-transform:translateZ(0);transform:translateZ(0);-webkit-transition:-webkit-transform .25s ease-in-out;transition:-webkit-transform .25s ease-in-out;transition:transform .25s ease-in-out;transition:transform .25s ease-in-out,-webkit-transform .25s ease-in-out}.grow-large:focus,.grow-large:hover{-webkit-transform:scale(1.2);transform:scale(1.2)}.grow-large:active{-webkit-transform:scale(.95);transform:scale(.95)}.pointer:hover,.shadow-hover{cursor:pointer}.shadow-hover{position:relative;-webkit-transition:all .5s cubic-bezier(.165,.84,.44,1);transition:all .5s cubic-bezier(.165,.84,.44,1)}.shadow-hover:after{content:"";box-shadow:0 0 16px 2px rgba(0,0,0,.2);opacity:0;position:absolute;top:0;left:0;width:100%;height:100%;z-index:-1;-webkit-transition:opacity .5s cubic-bezier(.165,.84,.44,1);transition:opacity .5s cubic-bezier(.165,.84,.44,1)}.shadow-hover:focus:after,.shadow-hover:hover:after{opacity:1}.bg-animate,.bg-animate:focus,.bg-animate:hover{-webkit-transition:background-color .15s ease-in-out;transition:background-color .15s ease-in-out}.z-0{z-index:0}.z-1{z-index:1}.z-2{z-index:2}.z-3{z-index:3}.z-4{z-index:4}.z-5{z-index:5}.z-999{z-index:999}.z-9999{z-index:9999}.z-max{z-index:2147483647}.z-inherit{z-index:inherit}.z-initial{z-index:auto}.z-unset{z-index:unset}.nested-copy-line-height ol,.nested-copy-line-height p,.nested-copy-line-height ul{line-height:1.5}.nested-headline-line-height h1,.nested-headline-line-height h2,.nested-headline-line-height h3,.nested-headline-line-height h4,.nested-headline-line-height h5,.nested-headline-line-height h6{line-height:1.25}.nested-list-reset ol,.nested-list-reset ul{padding-left:0;margin-left:0;list-style-type:none}.nested-copy-indent p+p{text-indent:1em;margin-top:0;margin-bottom:0}.nested-copy-seperator p+p{margin-top:1.5em}.nested-img img{width:100%;max-width:100%;display:block}.nested-links a{color:#357edd;-webkit-transition:color .15s ease-in;transition:color .15s ease-in}.nested-links a:focus,.nested-links a:hover{color:#96ccff;-webkit-transition:color .15s ease-in;transition:color .15s ease-in}.debug *{outline:1px solid gold}.debug-white *{outline:1px solid #fff}.debug-black *{outline:1px solid #000}.debug-grid{background:transparent url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAICAYAAADED76LAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyhpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTExIDc5LjE1ODMyNSwgMjAxNS8wOS8xMC0wMToxMDoyMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6MTRDOTY4N0U2N0VFMTFFNjg2MzZDQjkwNkQ4MjgwMEIiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6MTRDOTY4N0Q2N0VFMTFFNjg2MzZDQjkwNkQ4MjgwMEIiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTUgKE1hY2ludG9zaCkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo3NjcyQkQ3NjY3QzUxMUU2QjJCQ0UyNDA4MTAwMjE3MSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo3NjcyQkQ3NzY3QzUxMUU2QjJCQ0UyNDA4MTAwMjE3MSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PsBS+GMAAAAjSURBVHjaYvz//z8DLsD4gcGXiYEAGBIKGBne//fFpwAgwAB98AaF2pjlUQAAAABJRU5ErkJggg==) repeat 0 0}.debug-grid-16{background:transparent url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyhpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTExIDc5LjE1ODMyNSwgMjAxNS8wOS8xMC0wMToxMDoyMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bWxuczp4bXA9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC8iIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6ODYyRjhERDU2N0YyMTFFNjg2MzZDQjkwNkQ4MjgwMEIiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6ODYyRjhERDQ2N0YyMTFFNjg2MzZDQjkwNkQ4MjgwMEIiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTUgKE1hY2ludG9zaCkiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo3NjcyQkQ3QTY3QzUxMUU2QjJCQ0UyNDA4MTAwMjE3MSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo3NjcyQkQ3QjY3QzUxMUU2QjJCQ0UyNDA4MTAwMjE3MSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/PvCS01IAAABMSURBVHjaYmR4/5+BFPBfAMFm/MBgx8RAGWCn1AAmSg34Q6kBDKMGMDCwICeMIemF/5QawEipAWwUhwEjMDvbAWlWkvVBwu8vQIABAEwBCph8U6c0AAAAAElFTkSuQmCC) repeat 0 0}.debug-grid-8-solid{background:#fff url(data:image/jpeg;base64,/9j/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP/sABFEdWNreQABAAQAAAAAAAD/4QMxaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJBZG9iZSBYTVAgQ29yZSA1LjYtYzExMSA3OS4xNTgzMjUsIDIwMTUvMDkvMTAtMDE6MTA6MjAgICAgICAgICI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnhtcD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLyIgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iIHhtbG5zOnN0UmVmPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvc1R5cGUvUmVzb3VyY2VSZWYjIiB4bXA6Q3JlYXRvclRvb2w9IkFkb2JlIFBob3Rvc2hvcCBDQyAyMDE1IChNYWNpbnRvc2gpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOkIxMjI0OTczNjdCMzExRTZCMkJDRTI0MDgxMDAyMTcxIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOkIxMjI0OTc0NjdCMzExRTZCMkJDRTI0MDgxMDAyMTcxIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6QjEyMjQ5NzE2N0IzMTFFNkIyQkNFMjQwODEwMDIxNzEiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6QjEyMjQ5NzI2N0IzMTFFNkIyQkNFMjQwODEwMDIxNzEiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz7/7gAOQWRvYmUAZMAAAAAB/9sAhAAbGhopHSlBJiZBQi8vL0JHPz4+P0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHAR0pKTQmND8oKD9HPzU/R0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0dHR0f/wAARCAAIAAgDASIAAhEBAxEB/8QAWQABAQAAAAAAAAAAAAAAAAAAAAYBAQEAAAAAAAAAAAAAAAAAAAIEEAEBAAMBAAAAAAAAAAAAAAABADECA0ERAAEDBQAAAAAAAAAAAAAAAAARITFBUWESIv/aAAwDAQACEQMRAD8AoOnTV1QTD7JJshP3vSM3P//Z) repeat 0 0}.debug-grid-16-solid{background:#fff url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAIAAACQkWg2AAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyhpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMTExIDc5LjE1ODMyNSwgMjAxNS8wOS8xMC0wMToxMDoyMCAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTUgKE1hY2ludG9zaCkiIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6NzY3MkJEN0U2N0M1MTFFNkIyQkNFMjQwODEwMDIxNzEiIHhtcE1NOkRvY3VtZW50SUQ9InhtcC5kaWQ6NzY3MkJEN0Y2N0M1MTFFNkIyQkNFMjQwODEwMDIxNzEiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0ieG1wLmlpZDo3NjcyQkQ3QzY3QzUxMUU2QjJCQ0UyNDA4MTAwMjE3MSIgc3RSZWY6ZG9jdW1lbnRJRD0ieG1wLmRpZDo3NjcyQkQ3RDY3QzUxMUU2QjJCQ0UyNDA4MTAwMjE3MSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pve6J3kAAAAzSURBVHjaYvz//z8D0UDsMwMjSRoYP5Gq4SPNbRjVMEQ1fCRDg+in/6+J1AJUxsgAEGAA31BAJMS0GYEAAAAASUVORK5CYII=) repeat 0 0}@media screen and (min-width:30em){.aspect-ratio-ns{height:0;position:relative}.aspect-ratio--16x9-ns{padding-bottom:56.25%}.aspect-ratio--9x16-ns{padding-bottom:177.77%}.aspect-ratio--4x3-ns{padding-bottom:75%}.aspect-ratio--3x4-ns{padding-bottom:133.33%}.aspect-ratio--6x4-ns{padding-bottom:66.6%}.aspect-ratio--4x6-ns{padding-bottom:150%}.aspect-ratio--8x5-ns{padding-bottom:62.5%}.aspect-ratio--5x8-ns{padding-bottom:160%}.aspect-ratio--7x5-ns{padding-bottom:71.42%}.aspect-ratio--5x7-ns{padding-bottom:140%}.aspect-ratio--1x1-ns{padding-bottom:100%}.aspect-ratio--object-ns{position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%;z-index:100}.cover-ns{background-size:cover!important}.contain-ns{background-size:contain!important}.bg-center-ns{background-position:50%}.bg-center-ns,.bg-top-ns{background-repeat:no-repeat}.bg-top-ns{background-position:top}.bg-right-ns{background-position:100%}.bg-bottom-ns,.bg-right-ns{background-repeat:no-repeat}.bg-bottom-ns{background-position:bottom}.bg-left-ns{background-repeat:no-repeat;background-position:0}.outline-ns{outline:1px solid}.outline-transparent-ns{outline:1px solid transparent}.outline-0-ns{outline:0}.ba-ns{border-style:solid;border-width:1px}.bt-ns{border-top-style:solid;border-top-width:1px}.br-ns{border-right-style:solid;border-right-width:1px}.bb-ns{border-bottom-style:solid;border-bottom-width:1px}.bl-ns{border-left-style:solid;border-left-width:1px}.bn-ns{border-style:none;border-width:0}.br0-ns{border-radius:0}.br1-ns{border-radius:.125rem}.br2-ns{border-radius:.25rem}.br3-ns{border-radius:.5rem}.br4-ns{border-radius:1rem}.br-100-ns{border-radius:100%}.br-pill-ns{border-radius:9999px}.br--bottom-ns{border-top-left-radius:0;border-top-right-radius:0}.br--top-ns{border-bottom-right-radius:0}.br--right-ns,.br--top-ns{border-bottom-left-radius:0}.br--right-ns{border-top-left-radius:0}.br--left-ns{border-top-right-radius:0;border-bottom-right-radius:0}.b--dotted-ns{border-style:dotted}.b--dashed-ns{border-style:dashed}.b--solid-ns{border-style:solid}.b--none-ns{border-style:none}.bw0-ns{border-width:0}.bw1-ns{border-width:.125rem}.bw2-ns{border-width:.25rem}.bw3-ns{border-width:.5rem}.bw4-ns{border-width:1rem}.bw5-ns{border-width:2rem}.bt-0-ns{border-top-width:0}.br-0-ns{border-right-width:0}.bb-0-ns{border-bottom-width:0}.bl-0-ns{border-left-width:0}.shadow-1-ns{box-shadow:0 0 4px 2px rgba(0,0,0,.2)}.shadow-2-ns{box-shadow:0 0 8px 2px rgba(0,0,0,.2)}.shadow-3-ns{box-shadow:2px 2px 4px 2px rgba(0,0,0,.2)}.shadow-4-ns{box-shadow:2px 2px 8px 0 rgba(0,0,0,.2)}.shadow-5-ns{box-shadow:4px 4px 8px 0 rgba(0,0,0,.2)}.top-0-ns{top:0}.left-0-ns{left:0}.right-0-ns{right:0}.bottom-0-ns{bottom:0}.top-1-ns{top:1rem}.left-1-ns{left:1rem}.right-1-ns{right:1rem}.bottom-1-ns{bottom:1rem}.top-2-ns{top:2rem}.left-2-ns{left:2rem}.right-2-ns{right:2rem}.bottom-2-ns{bottom:2rem}.top--1-ns{top:-1rem}.right--1-ns{right:-1rem}.bottom--1-ns{bottom:-1rem}.left--1-ns{left:-1rem}.top--2-ns{top:-2rem}.right--2-ns{right:-2rem}.bottom--2-ns{bottom:-2rem}.left--2-ns{left:-2rem}.absolute--fill-ns{top:0;right:0;bottom:0;left:0}.cl-ns{clear:left}.cr-ns{clear:right}.cb-ns{clear:both}.cn-ns{clear:none}.dn-ns{display:none}.di-ns{display:inline}.db-ns{display:block}.dib-ns{display:inline-block}.dit-ns{display:inline-table}.dt-ns{display:table}.dtc-ns{display:table-cell}.dt-row-ns{display:table-row}.dt-row-group-ns{display:table-row-group}.dt-column-ns{display:table-column}.dt-column-group-ns{display:table-column-group}.dt--fixed-ns{table-layout:fixed;width:100%}.flex-ns{display:-webkit-box;display:-ms-flexbox;display:flex}.inline-flex-ns{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex}.flex-auto-ns{-webkit-box-flex:1;-ms-flex:1 1 auto;flex:1 1 auto;min-width:0;min-height:0}.flex-none-ns{-webkit-box-flex:0;-ms-flex:none;flex:none}.flex-column-ns{-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.flex-row-ns{-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row}.flex-wrap-ns{-ms-flex-wrap:wrap;flex-wrap:wrap}.items-start-ns{-webkit-box-align:start;-ms-flex-align:start;align-items:flex-start}.items-end-ns{-webkit-box-align:end;-ms-flex-align:end;align-items:flex-end}.items-center-ns{-webkit-box-align:center;-ms-flex-align:center;align-items:center}.items-baseline-ns{-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline}.items-stretch-ns{-webkit-box-align:stretch;-ms-flex-align:stretch;align-items:stretch}.self-start-ns{-ms-flex-item-align:start;align-self:flex-start}.self-end-ns{-ms-flex-item-align:end;align-self:flex-end}.self-center-ns{-ms-flex-item-align:center;-ms-grid-row-align:center;align-self:center}.self-baseline-ns{-ms-flex-item-align:baseline;align-self:baseline}.self-stretch-ns{-ms-flex-item-align:stretch;-ms-grid-row-align:stretch;align-self:stretch}.justify-start-ns{-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start}.justify-end-ns{-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end}.justify-center-ns{-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.justify-between-ns{-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.justify-around-ns{-ms-flex-pack:distribute;justify-content:space-around}.content-start-ns{-ms-flex-line-pack:start;align-content:flex-start}.content-end-ns{-ms-flex-line-pack:end;align-content:flex-end}.content-center-ns{-ms-flex-line-pack:center;align-content:center}.content-between-ns{-ms-flex-line-pack:justify;align-content:space-between}.content-around-ns{-ms-flex-line-pack:distribute;align-content:space-around}.content-stretch-ns{-ms-flex-line-pack:stretch;align-content:stretch}.order-0-ns{-webkit-box-ordinal-group:1;-ms-flex-order:0;order:0}.order-1-ns{-webkit-box-ordinal-group:2;-ms-flex-order:1;order:1}.order-2-ns{-webkit-box-ordinal-group:3;-ms-flex-order:2;order:2}.order-3-ns{-webkit-box-ordinal-group:4;-ms-flex-order:3;order:3}.order-4-ns{-webkit-box-ordinal-group:5;-ms-flex-order:4;order:4}.order-5-ns{-webkit-box-ordinal-group:6;-ms-flex-order:5;order:5}.order-6-ns{-webkit-box-ordinal-group:7;-ms-flex-order:6;order:6}.order-7-ns{-webkit-box-ordinal-group:8;-ms-flex-order:7;order:7}.order-8-ns{-webkit-box-ordinal-group:9;-ms-flex-order:8;order:8}.order-last-ns{-webkit-box-ordinal-group:100000;-ms-flex-order:99999;order:99999}.fl-ns{float:left}.fl-ns,.fr-ns{display:inline}.fr-ns{float:right}.fn-ns{float:none}.i-ns{font-style:italic}.fs-normal-ns{font-style:normal}.normal-ns{font-weight:400}.b-ns{font-weight:700}.fw1-ns{font-weight:100}.fw2-ns{font-weight:200}.fw3-ns{font-weight:300}.fw4-ns{font-weight:400}.fw5-ns{font-weight:500}.fw6-ns{font-weight:600}.fw7-ns{font-weight:700}.fw8-ns{font-weight:800}.fw9-ns{font-weight:900}.h1-ns{height:1rem}.h2-ns{height:2rem}.h3-ns{height:4rem}.h4-ns{height:8rem}.h5-ns{height:16rem}.h-25-ns{height:25%}.h-50-ns{height:50%}.h-75-ns{height:75%}.h-100-ns{height:100%}.min-h-100-ns{min-height:100%}.vh-25-ns{height:25vh}.vh-50-ns{height:50vh}.vh-75-ns{height:75vh}.vh-100-ns{height:100vh}.min-vh-100-ns{min-height:100vh}.h-auto-ns{height:auto}.h-inherit-ns{height:inherit}.tracked-ns{letter-spacing:.1em}.tracked-tight-ns{letter-spacing:-.05em}.tracked-mega-ns{letter-spacing:.25em}.lh-solid-ns{line-height:1}.lh-title-ns{line-height:1.25}.lh-copy-ns{line-height:1.5}.mw-100-ns{max-width:100%}.mw1-ns{max-width:1rem}.mw2-ns{max-width:2rem}.mw3-ns{max-width:4rem}.mw4-ns{max-width:8rem}.mw5-ns{max-width:16rem}.mw6-ns{max-width:32rem}.mw7-ns{max-width:48rem}.mw8-ns{max-width:64rem}.mw9-ns{max-width:96rem}.mw-none-ns{max-width:none}.w1-ns{width:1rem}.w2-ns{width:2rem}.w3-ns{width:4rem}.w4-ns{width:8rem}.w5-ns{width:16rem}.w-10-ns{width:10%}.w-20-ns{width:20%}.w-25-ns{width:25%}.w-30-ns{width:30%}.w-33-ns{width:33%}.w-34-ns{width:34%}.w-40-ns{width:40%}.w-50-ns{width:50%}.w-60-ns{width:60%}.w-70-ns{width:70%}.w-75-ns{width:75%}.w-80-ns{width:80%}.w-90-ns{width:90%}.w-100-ns{width:100%}.w-third-ns{width:33.33333%}.w-two-thirds-ns{width:66.66667%}.w-auto-ns{width:auto}.overflow-visible-ns{overflow:visible}.overflow-hidden-ns{overflow:hidden}.overflow-scroll-ns{overflow:scroll}.overflow-auto-ns{overflow:auto}.overflow-x-visible-ns{overflow-x:visible}.overflow-x-hidden-ns{overflow-x:hidden}.overflow-x-scroll-ns{overflow-x:scroll}.overflow-x-auto-ns{overflow-x:auto}.overflow-y-visible-ns{overflow-y:visible}.overflow-y-hidden-ns{overflow-y:hidden}.overflow-y-scroll-ns{overflow-y:scroll}.overflow-y-auto-ns{overflow-y:auto}.static-ns{position:static}.relative-ns{position:relative}.absolute-ns{position:absolute}.fixed-ns{position:fixed}.rotate-45-ns{-webkit-transform:rotate(45deg);transform:rotate(45deg)}.rotate-90-ns{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.rotate-135-ns{-webkit-transform:rotate(135deg);transform:rotate(135deg)}.rotate-180-ns{-webkit-transform:rotate(180deg);transform:rotate(180deg)}.rotate-225-ns{-webkit-transform:rotate(225deg);transform:rotate(225deg)}.rotate-270-ns{-webkit-transform:rotate(270deg);transform:rotate(270deg)}.rotate-315-ns{-webkit-transform:rotate(315deg);transform:rotate(315deg)}.pa0-ns{padding:0}.pa1-ns{padding:.25rem}.pa2-ns{padding:.5rem}.pa3-ns{padding:1rem}.pa4-ns{padding:2rem}.pa5-ns{padding:4rem}.pa6-ns{padding:8rem}.pa7-ns{padding:16rem}.pl0-ns{padding-left:0}.pl1-ns{padding-left:.25rem}.pl2-ns{padding-left:.5rem}.pl3-ns{padding-left:1rem}.pl4-ns{padding-left:2rem}.pl5-ns{padding-left:4rem}.pl6-ns{padding-left:8rem}.pl7-ns{padding-left:16rem}.pr0-ns{padding-right:0}.pr1-ns{padding-right:.25rem}.pr2-ns{padding-right:.5rem}.pr3-ns{padding-right:1rem}.pr4-ns{padding-right:2rem}.pr5-ns{padding-right:4rem}.pr6-ns{padding-right:8rem}.pr7-ns{padding-right:16rem}.pb0-ns{padding-bottom:0}.pb1-ns{padding-bottom:.25rem}.pb2-ns{padding-bottom:.5rem}.pb3-ns{padding-bottom:1rem}.pb4-ns{padding-bottom:2rem}.pb5-ns{padding-bottom:4rem}.pb6-ns{padding-bottom:8rem}.pb7-ns{padding-bottom:16rem}.pt0-ns{padding-top:0}.pt1-ns{padding-top:.25rem}.pt2-ns{padding-top:.5rem}.pt3-ns{padding-top:1rem}.pt4-ns{padding-top:2rem}.pt5-ns{padding-top:4rem}.pt6-ns{padding-top:8rem}.pt7-ns{padding-top:16rem}.pv0-ns{padding-top:0;padding-bottom:0}.pv1-ns{padding-top:.25rem;padding-bottom:.25rem}.pv2-ns{padding-top:.5rem;padding-bottom:.5rem}.pv3-ns{padding-top:1rem;padding-bottom:1rem}.pv4-ns{padding-top:2rem;padding-bottom:2rem}.pv5-ns{padding-top:4rem;padding-bottom:4rem}.pv6-ns{padding-top:8rem;padding-bottom:8rem}.pv7-ns{padding-top:16rem;padding-bottom:16rem}.ph0-ns{padding-left:0;padding-right:0}.ph1-ns{padding-left:.25rem;padding-right:.25rem}.ph2-ns{padding-left:.5rem;padding-right:.5rem}.ph3-ns{padding-left:1rem;padding-right:1rem}.ph4-ns{padding-left:2rem;padding-right:2rem}.ph5-ns{padding-left:4rem;padding-right:4rem}.ph6-ns{padding-left:8rem;padding-right:8rem}.ph7-ns{padding-left:16rem;padding-right:16rem}.ma0-ns{margin:0}.ma1-ns{margin:.25rem}.ma2-ns{margin:.5rem}.ma3-ns{margin:1rem}.ma4-ns{margin:2rem}.ma5-ns{margin:4rem}.ma6-ns{margin:8rem}.ma7-ns{margin:16rem}.ml0-ns{margin-left:0}.ml1-ns{margin-left:.25rem}.ml2-ns{margin-left:.5rem}.ml3-ns{margin-left:1rem}.ml4-ns{margin-left:2rem}.ml5-ns{margin-left:4rem}.ml6-ns{margin-left:8rem}.ml7-ns{margin-left:16rem}.mr0-ns{margin-right:0}.mr1-ns{margin-right:.25rem}.mr2-ns{margin-right:.5rem}.mr3-ns{margin-right:1rem}.mr4-ns{margin-right:2rem}.mr5-ns{margin-right:4rem}.mr6-ns{margin-right:8rem}.mr7-ns{margin-right:16rem}.mb0-ns{margin-bottom:0}.mb1-ns{margin-bottom:.25rem}.mb2-ns{margin-bottom:.5rem}.mb3-ns{margin-bottom:1rem}.mb4-ns{margin-bottom:2rem}.mb5-ns{margin-bottom:4rem}.mb6-ns{margin-bottom:8rem}.mb7-ns{margin-bottom:16rem}.mt0-ns{margin-top:0}.mt1-ns{margin-top:.25rem}.mt2-ns{margin-top:.5rem}.mt3-ns{margin-top:1rem}.mt4-ns{margin-top:2rem}.mt5-ns{margin-top:4rem}.mt6-ns{margin-top:8rem}.mt7-ns{margin-top:16rem}.mv0-ns{margin-top:0;margin-bottom:0}.mv1-ns{margin-top:.25rem;margin-bottom:.25rem}.mv2-ns{margin-top:.5rem;margin-bottom:.5rem}.mv3-ns{margin-top:1rem;margin-bottom:1rem}.mv4-ns{margin-top:2rem;margin-bottom:2rem}.mv5-ns{margin-top:4rem;margin-bottom:4rem}.mv6-ns{margin-top:8rem;margin-bottom:8rem}.mv7-ns{margin-top:16rem;margin-bottom:16rem}.mh0-ns{margin-left:0;margin-right:0}.mh1-ns{margin-left:.25rem;margin-right:.25rem}.mh2-ns{margin-left:.5rem;margin-right:.5rem}.mh3-ns{margin-left:1rem;margin-right:1rem}.mh4-ns{margin-left:2rem;margin-right:2rem}.mh5-ns{margin-left:4rem;margin-right:4rem}.mh6-ns{margin-left:8rem;margin-right:8rem}.mh7-ns{margin-left:16rem;margin-right:16rem}.na1-ns{margin:-.25rem}.na2-ns{margin:-.5rem}.na3-ns{margin:-1rem}.na4-ns{margin:-2rem}.na5-ns{margin:-4rem}.na6-ns{margin:-8rem}.na7-ns{margin:-16rem}.nl1-ns{margin-left:-.25rem}.nl2-ns{margin-left:-.5rem}.nl3-ns{margin-left:-1rem}.nl4-ns{margin-left:-2rem}.nl5-ns{margin-left:-4rem}.nl6-ns{margin-left:-8rem}.nl7-ns{margin-left:-16rem}.nr1-ns{margin-right:-.25rem}.nr2-ns{margin-right:-.5rem}.nr3-ns{margin-right:-1rem}.nr4-ns{margin-right:-2rem}.nr5-ns{margin-right:-4rem}.nr6-ns{margin-right:-8rem}.nr7-ns{margin-right:-16rem}.nb1-ns{margin-bottom:-.25rem}.nb2-ns{margin-bottom:-.5rem}.nb3-ns{margin-bottom:-1rem}.nb4-ns{margin-bottom:-2rem}.nb5-ns{margin-bottom:-4rem}.nb6-ns{margin-bottom:-8rem}.nb7-ns{margin-bottom:-16rem}.nt1-ns{margin-top:-.25rem}.nt2-ns{margin-top:-.5rem}.nt3-ns{margin-top:-1rem}.nt4-ns{margin-top:-2rem}.nt5-ns{margin-top:-4rem}.nt6-ns{margin-top:-8rem}.nt7-ns{margin-top:-16rem}.strike-ns{text-decoration:line-through}.underline-ns{text-decoration:underline}.no-underline-ns{text-decoration:none}.tl-ns{text-align:left}.tr-ns{text-align:right}.tc-ns{text-align:center}.ttc-ns{text-transform:capitalize}.ttl-ns{text-transform:lowercase}.ttu-ns{text-transform:uppercase}.ttn-ns{text-transform:none}.f-6-ns,.f-headline-ns{font-size:6rem}.f-5-ns,.f-subheadline-ns{font-size:5rem}.f1-ns{font-size:3rem}.f2-ns{font-size:2.25rem}.f3-ns{font-size:1.5rem}.f4-ns{font-size:1.25rem}.f5-ns{font-size:1rem}.f6-ns{font-size:.875rem}.measure-ns{max-width:30em}.measure-wide-ns{max-width:34em}.measure-narrow-ns{max-width:20em}.indent-ns{text-indent:1em;margin-top:0;margin-bottom:0}.small-caps-ns{font-variant:small-caps}.truncate-ns{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.clip-ns{position:fixed!important;position:absolute!important;clip:rect(1px 1px 1px 1px);clip:rect(1px,1px,1px,1px)}.ws-normal-ns{white-space:normal}.nowrap-ns{white-space:nowrap}.pre-ns{white-space:pre}.v-base-ns{vertical-align:baseline}.v-mid-ns{vertical-align:middle}.v-top-ns{vertical-align:top}.v-btm-ns{vertical-align:bottom}}@media screen and (min-width:30em) and (max-width:60em){.aspect-ratio-m{height:0;position:relative}.aspect-ratio--16x9-m{padding-bottom:56.25%}.aspect-ratio--9x16-m{padding-bottom:177.77%}.aspect-ratio--4x3-m{padding-bottom:75%}.aspect-ratio--3x4-m{padding-bottom:133.33%}.aspect-ratio--6x4-m{padding-bottom:66.6%}.aspect-ratio--4x6-m{padding-bottom:150%}.aspect-ratio--8x5-m{padding-bottom:62.5%}.aspect-ratio--5x8-m{padding-bottom:160%}.aspect-ratio--7x5-m{padding-bottom:71.42%}.aspect-ratio--5x7-m{padding-bottom:140%}.aspect-ratio--1x1-m{padding-bottom:100%}.aspect-ratio--object-m{position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%;z-index:100}.cover-m{background-size:cover!important}.contain-m{background-size:contain!important}.bg-center-m{background-position:50%}.bg-center-m,.bg-top-m{background-repeat:no-repeat}.bg-top-m{background-position:top}.bg-right-m{background-position:100%}.bg-bottom-m,.bg-right-m{background-repeat:no-repeat}.bg-bottom-m{background-position:bottom}.bg-left-m{background-repeat:no-repeat;background-position:0}.outline-m{outline:1px solid}.outline-transparent-m{outline:1px solid transparent}.outline-0-m{outline:0}.outline-l{outline:1px solid}.outline-transparent-l{outline:1px solid transparent}.outline-0-l{outline:0}.ba-m{border-style:solid;border-width:1px}.bt-m{border-top-style:solid;border-top-width:1px}.br-m{border-right-style:solid;border-right-width:1px}.bb-m{border-bottom-style:solid;border-bottom-width:1px}.bl-m{border-left-style:solid;border-left-width:1px}.bn-m{border-style:none;border-width:0}.br0-m{border-radius:0}.br1-m{border-radius:.125rem}.br2-m{border-radius:.25rem}.br3-m{border-radius:.5rem}.br4-m{border-radius:1rem}.br-100-m{border-radius:100%}.br-pill-m{border-radius:9999px}.br--bottom-m{border-top-left-radius:0;border-top-right-radius:0}.br--top-m{border-bottom-right-radius:0}.br--right-m,.br--top-m{border-bottom-left-radius:0}.br--right-m{border-top-left-radius:0}.br--left-m{border-top-right-radius:0;border-bottom-right-radius:0}.b--dotted-m{border-style:dotted}.b--dashed-m{border-style:dashed}.b--solid-m{border-style:solid}.b--none-m{border-style:none}.bw0-m{border-width:0}.bw1-m{border-width:.125rem}.bw2-m{border-width:.25rem}.bw3-m{border-width:.5rem}.bw4-m{border-width:1rem}.bw5-m{border-width:2rem}.bt-0-m{border-top-width:0}.br-0-m{border-right-width:0}.bb-0-m{border-bottom-width:0}.bl-0-m{border-left-width:0}.shadow-1-m{box-shadow:0 0 4px 2px rgba(0,0,0,.2)}.shadow-2-m{box-shadow:0 0 8px 2px rgba(0,0,0,.2)}.shadow-3-m{box-shadow:2px 2px 4px 2px rgba(0,0,0,.2)}.shadow-4-m{box-shadow:2px 2px 8px 0 rgba(0,0,0,.2)}.shadow-5-m{box-shadow:4px 4px 8px 0 rgba(0,0,0,.2)}.top-0-m{top:0}.left-0-m{left:0}.right-0-m{right:0}.bottom-0-m{bottom:0}.top-1-m{top:1rem}.left-1-m{left:1rem}.right-1-m{right:1rem}.bottom-1-m{bottom:1rem}.top-2-m{top:2rem}.left-2-m{left:2rem}.right-2-m{right:2rem}.bottom-2-m{bottom:2rem}.top--1-m{top:-1rem}.right--1-m{right:-1rem}.bottom--1-m{bottom:-1rem}.left--1-m{left:-1rem}.top--2-m{top:-2rem}.right--2-m{right:-2rem}.bottom--2-m{bottom:-2rem}.left--2-m{left:-2rem}.absolute--fill-m{top:0;right:0;bottom:0;left:0}.cl-m{clear:left}.cr-m{clear:right}.cb-m{clear:both}.cn-m{clear:none}.dn-m{display:none}.di-m{display:inline}.db-m{display:block}.dib-m{display:inline-block}.dit-m{display:inline-table}.dt-m{display:table}.dtc-m{display:table-cell}.dt-row-m{display:table-row}.dt-row-group-m{display:table-row-group}.dt-column-m{display:table-column}.dt-column-group-m{display:table-column-group}.dt--fixed-m{table-layout:fixed;width:100%}.flex-m{display:-webkit-box;display:-ms-flexbox;display:flex}.inline-flex-m{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex}.flex-auto-m{-webkit-box-flex:1;-ms-flex:1 1 auto;flex:1 1 auto;min-width:0;min-height:0}.flex-none-m{-webkit-box-flex:0;-ms-flex:none;flex:none}.flex-column-m{-webkit-box-orient:vertical;-ms-flex-direction:column;flex-direction:column}.flex-column-m,.flex-row-m{-webkit-box-direction:normal}.flex-row-m{-webkit-box-orient:horizontal;-ms-flex-direction:row;flex-direction:row}.flex-wrap-m{-ms-flex-wrap:wrap;flex-wrap:wrap}.items-start-m{-webkit-box-align:start;-ms-flex-align:start;align-items:flex-start}.items-end-m{-webkit-box-align:end;-ms-flex-align:end;align-items:flex-end}.items-center-m{-webkit-box-align:center;-ms-flex-align:center;align-items:center}.items-baseline-m{-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline}.items-stretch-m{-webkit-box-align:stretch;-ms-flex-align:stretch;align-items:stretch}.self-start-m{-ms-flex-item-align:start;align-self:flex-start}.self-end-m{-ms-flex-item-align:end;align-self:flex-end}.self-center-m{-ms-flex-item-align:center;-ms-grid-row-align:center;align-self:center}.self-baseline-m{-ms-flex-item-align:baseline;align-self:baseline}.self-stretch-m{-ms-flex-item-align:stretch;-ms-grid-row-align:stretch;align-self:stretch}.justify-start-m{-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start}.justify-end-m{-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end}.justify-center-m{-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.justify-between-m{-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.justify-around-m{-ms-flex-pack:distribute;justify-content:space-around}.content-start-m{-ms-flex-line-pack:start;align-content:flex-start}.content-end-m{-ms-flex-line-pack:end;align-content:flex-end}.content-center-m{-ms-flex-line-pack:center;align-content:center}.content-between-m{-ms-flex-line-pack:justify;align-content:space-between}.content-around-m{-ms-flex-line-pack:distribute;align-content:space-around}.content-stretch-m{-ms-flex-line-pack:stretch;align-content:stretch}.order-0-m{-webkit-box-ordinal-group:1;-ms-flex-order:0;order:0}.order-1-m{-webkit-box-ordinal-group:2;-ms-flex-order:1;order:1}.order-2-m{-webkit-box-ordinal-group:3;-ms-flex-order:2;order:2}.order-3-m{-webkit-box-ordinal-group:4;-ms-flex-order:3;order:3}.order-4-m{-webkit-box-ordinal-group:5;-ms-flex-order:4;order:4}.order-5-m{-webkit-box-ordinal-group:6;-ms-flex-order:5;order:5}.order-6-m{-webkit-box-ordinal-group:7;-ms-flex-order:6;order:6}.order-7-m{-webkit-box-ordinal-group:8;-ms-flex-order:7;order:7}.order-8-m{-webkit-box-ordinal-group:9;-ms-flex-order:8;order:8}.order-last-m{-webkit-box-ordinal-group:100000;-ms-flex-order:99999;order:99999}.fl-m{float:left}.fl-m,.fr-m{display:inline}.fr-m{float:right}.fn-m{float:none}.i-m{font-style:italic}.fs-normal-m{font-style:normal}.normal-m{font-weight:400}.b-m{font-weight:700}.fw1-m{font-weight:100}.fw2-m{font-weight:200}.fw3-m{font-weight:300}.fw4-m{font-weight:400}.fw5-m{font-weight:500}.fw6-m{font-weight:600}.fw7-m{font-weight:700}.fw8-m{font-weight:800}.fw9-m{font-weight:900}.h1-m{height:1rem}.h2-m{height:2rem}.h3-m{height:4rem}.h4-m{height:8rem}.h5-m{height:16rem}.h-25-m{height:25%}.h-50-m{height:50%}.h-75-m{height:75%}.h-100-m{height:100%}.min-h-100-ns{min-height:100%}.vh-25-m{height:25vh}.vh-50-m{height:50vh}.vh-75-m{height:75vh}.vh-100-m{height:100vh}.min-vh-100-m{min-height:100vh}.h-auto-m{height:auto}.h-inherit-m{height:inherit}.tracked-m{letter-spacing:.1em}.tracked-tight-m{letter-spacing:-.05em}.tracked-mega-m{letter-spacing:.25em}.lh-solid-m{line-height:1}.lh-title-m{line-height:1.25}.lh-copy-m{line-height:1.5}.mw-100-m{max-width:100%}.mw1-m{max-width:1rem}.mw2-m{max-width:2rem}.mw3-m{max-width:4rem}.mw4-m{max-width:8rem}.mw5-m{max-width:16rem}.mw6-m{max-width:32rem}.mw7-m{max-width:48rem}.mw8-m{max-width:64rem}.mw9-m{max-width:96rem}.mw-none-m{max-width:none}.w1-m{width:1rem}.w2-m{width:2rem}.w3-m{width:4rem}.w4-m{width:8rem}.w5-m{width:16rem}.w-10-m{width:10%}.w-20-m{width:20%}.w-25-m{width:25%}.w-30-m{width:30%}.w-33-m{width:33%}.w-34-m{width:34%}.w-40-m{width:40%}.w-50-m{width:50%}.w-60-m{width:60%}.w-70-m{width:70%}.w-75-m{width:75%}.w-80-m{width:80%}.w-90-m{width:90%}.w-100-m{width:100%}.w-third-m{width:33.33333%}.w-two-thirds-m{width:66.66667%}.w-auto-m{width:auto}.overflow-visible-m{overflow:visible}.overflow-hidden-m{overflow:hidden}.overflow-scroll-m{overflow:scroll}.overflow-auto-m{overflow:auto}.overflow-x-visible-m{overflow-x:visible}.overflow-x-hidden-m{overflow-x:hidden}.overflow-x-scroll-m{overflow-x:scroll}.overflow-x-auto-m{overflow-x:auto}.overflow-y-visible-m{overflow-y:visible}.overflow-y-hidden-m{overflow-y:hidden}.overflow-y-scroll-m{overflow-y:scroll}.overflow-y-auto-m{overflow-y:auto}.static-m{position:static}.relative-m{position:relative}.absolute-m{position:absolute}.fixed-m{position:fixed}.rotate-45-m{-webkit-transform:rotate(45deg);transform:rotate(45deg)}.rotate-90-m{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.rotate-135-m{-webkit-transform:rotate(135deg);transform:rotate(135deg)}.rotate-180-m{-webkit-transform:rotate(180deg);transform:rotate(180deg)}.rotate-225-m{-webkit-transform:rotate(225deg);transform:rotate(225deg)}.rotate-270-m{-webkit-transform:rotate(270deg);transform:rotate(270deg)}.rotate-315-m{-webkit-transform:rotate(315deg);transform:rotate(315deg)}.pa0-m{padding:0}.pa1-m{padding:.25rem}.pa2-m{padding:.5rem}.pa3-m{padding:1rem}.pa4-m{padding:2rem}.pa5-m{padding:4rem}.pa6-m{padding:8rem}.pa7-m{padding:16rem}.pl0-m{padding-left:0}.pl1-m{padding-left:.25rem}.pl2-m{padding-left:.5rem}.pl3-m{padding-left:1rem}.pl4-m{padding-left:2rem}.pl5-m{padding-left:4rem}.pl6-m{padding-left:8rem}.pl7-m{padding-left:16rem}.pr0-m{padding-right:0}.pr1-m{padding-right:.25rem}.pr2-m{padding-right:.5rem}.pr3-m{padding-right:1rem}.pr4-m{padding-right:2rem}.pr5-m{padding-right:4rem}.pr6-m{padding-right:8rem}.pr7-m{padding-right:16rem}.pb0-m{padding-bottom:0}.pb1-m{padding-bottom:.25rem}.pb2-m{padding-bottom:.5rem}.pb3-m{padding-bottom:1rem}.pb4-m{padding-bottom:2rem}.pb5-m{padding-bottom:4rem}.pb6-m{padding-bottom:8rem}.pb7-m{padding-bottom:16rem}.pt0-m{padding-top:0}.pt1-m{padding-top:.25rem}.pt2-m{padding-top:.5rem}.pt3-m{padding-top:1rem}.pt4-m{padding-top:2rem}.pt5-m{padding-top:4rem}.pt6-m{padding-top:8rem}.pt7-m{padding-top:16rem}.pv0-m{padding-top:0;padding-bottom:0}.pv1-m{padding-top:.25rem;padding-bottom:.25rem}.pv2-m{padding-top:.5rem;padding-bottom:.5rem}.pv3-m{padding-top:1rem;padding-bottom:1rem}.pv4-m{padding-top:2rem;padding-bottom:2rem}.pv5-m{padding-top:4rem;padding-bottom:4rem}.pv6-m{padding-top:8rem;padding-bottom:8rem}.pv7-m{padding-top:16rem;padding-bottom:16rem}.ph0-m{padding-left:0;padding-right:0}.ph1-m{padding-left:.25rem;padding-right:.25rem}.ph2-m{padding-left:.5rem;padding-right:.5rem}.ph3-m{padding-left:1rem;padding-right:1rem}.ph4-m{padding-left:2rem;padding-right:2rem}.ph5-m{padding-left:4rem;padding-right:4rem}.ph6-m{padding-left:8rem;padding-right:8rem}.ph7-m{padding-left:16rem;padding-right:16rem}.ma0-m{margin:0}.ma1-m{margin:.25rem}.ma2-m{margin:.5rem}.ma3-m{margin:1rem}.ma4-m{margin:2rem}.ma5-m{margin:4rem}.ma6-m{margin:8rem}.ma7-m{margin:16rem}.ml0-m{margin-left:0}.ml1-m{margin-left:.25rem}.ml2-m{margin-left:.5rem}.ml3-m{margin-left:1rem}.ml4-m{margin-left:2rem}.ml5-m{margin-left:4rem}.ml6-m{margin-left:8rem}.ml7-m{margin-left:16rem}.mr0-m{margin-right:0}.mr1-m{margin-right:.25rem}.mr2-m{margin-right:.5rem}.mr3-m{margin-right:1rem}.mr4-m{margin-right:2rem}.mr5-m{margin-right:4rem}.mr6-m{margin-right:8rem}.mr7-m{margin-right:16rem}.mb0-m{margin-bottom:0}.mb1-m{margin-bottom:.25rem}.mb2-m{margin-bottom:.5rem}.mb3-m{margin-bottom:1rem}.mb4-m{margin-bottom:2rem}.mb5-m{margin-bottom:4rem}.mb6-m{margin-bottom:8rem}.mb7-m{margin-bottom:16rem}.mt0-m{margin-top:0}.mt1-m{margin-top:.25rem}.mt2-m{margin-top:.5rem}.mt3-m{margin-top:1rem}.mt4-m{margin-top:2rem}.mt5-m{margin-top:4rem}.mt6-m{margin-top:8rem}.mt7-m{margin-top:16rem}.mv0-m{margin-top:0;margin-bottom:0}.mv1-m{margin-top:.25rem;margin-bottom:.25rem}.mv2-m{margin-top:.5rem;margin-bottom:.5rem}.mv3-m{margin-top:1rem;margin-bottom:1rem}.mv4-m{margin-top:2rem;margin-bottom:2rem}.mv5-m{margin-top:4rem;margin-bottom:4rem}.mv6-m{margin-top:8rem;margin-bottom:8rem}.mv7-m{margin-top:16rem;margin-bottom:16rem}.mh0-m{margin-left:0;margin-right:0}.mh1-m{margin-left:.25rem;margin-right:.25rem}.mh2-m{margin-left:.5rem;margin-right:.5rem}.mh3-m{margin-left:1rem;margin-right:1rem}.mh4-m{margin-left:2rem;margin-right:2rem}.mh5-m{margin-left:4rem;margin-right:4rem}.mh6-m{margin-left:8rem;margin-right:8rem}.mh7-m{margin-left:16rem;margin-right:16rem}.na1-m{margin:-.25rem}.na2-m{margin:-.5rem}.na3-m{margin:-1rem}.na4-m{margin:-2rem}.na5-m{margin:-4rem}.na6-m{margin:-8rem}.na7-m{margin:-16rem}.nl1-m{margin-left:-.25rem}.nl2-m{margin-left:-.5rem}.nl3-m{margin-left:-1rem}.nl4-m{margin-left:-2rem}.nl5-m{margin-left:-4rem}.nl6-m{margin-left:-8rem}.nl7-m{margin-left:-16rem}.nr1-m{margin-right:-.25rem}.nr2-m{margin-right:-.5rem}.nr3-m{margin-right:-1rem}.nr4-m{margin-right:-2rem}.nr5-m{margin-right:-4rem}.nr6-m{margin-right:-8rem}.nr7-m{margin-right:-16rem}.nb1-m{margin-bottom:-.25rem}.nb2-m{margin-bottom:-.5rem}.nb3-m{margin-bottom:-1rem}.nb4-m{margin-bottom:-2rem}.nb5-m{margin-bottom:-4rem}.nb6-m{margin-bottom:-8rem}.nb7-m{margin-bottom:-16rem}.nt1-m{margin-top:-.25rem}.nt2-m{margin-top:-.5rem}.nt3-m{margin-top:-1rem}.nt4-m{margin-top:-2rem}.nt5-m{margin-top:-4rem}.nt6-m{margin-top:-8rem}.nt7-m{margin-top:-16rem}.strike-m{text-decoration:line-through}.underline-m{text-decoration:underline}.no-underline-m{text-decoration:none}.tl-m{text-align:left}.tr-m{text-align:right}.tc-m{text-align:center}.ttc-m{text-transform:capitalize}.ttl-m{text-transform:lowercase}.ttu-m{text-transform:uppercase}.ttn-m{text-transform:none}.f-6-m,.f-headline-m{font-size:6rem}.f-5-m,.f-subheadline-m{font-size:5rem}.f1-m{font-size:3rem}.f2-m{font-size:2.25rem}.f3-m{font-size:1.5rem}.f4-m{font-size:1.25rem}.f5-m{font-size:1rem}.f6-m{font-size:.875rem}.measure-m{max-width:30em}.measure-wide-m{max-width:34em}.measure-narrow-m{max-width:20em}.indent-m{text-indent:1em;margin-top:0;margin-bottom:0}.small-caps-m{font-variant:small-caps}.truncate-m{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.clip-m{position:fixed!important;position:absolute!important;clip:rect(1px 1px 1px 1px);clip:rect(1px,1px,1px,1px)}.ws-normal-m{white-space:normal}.nowrap-m{white-space:nowrap}.pre-m{white-space:pre}.v-base-m{vertical-align:baseline}.v-mid-m{vertical-align:middle}.v-top-m{vertical-align:top}.v-btm-m{vertical-align:bottom}}@media screen and (min-width:60em){.aspect-ratio-l{height:0;position:relative}.aspect-ratio--16x9-l{padding-bottom:56.25%}.aspect-ratio--9x16-l{padding-bottom:177.77%}.aspect-ratio--4x3-l{padding-bottom:75%}.aspect-ratio--3x4-l{padding-bottom:133.33%}.aspect-ratio--6x4-l{padding-bottom:66.6%}.aspect-ratio--4x6-l{padding-bottom:150%}.aspect-ratio--8x5-l{padding-bottom:62.5%}.aspect-ratio--5x8-l{padding-bottom:160%}.aspect-ratio--7x5-l{padding-bottom:71.42%}.aspect-ratio--5x7-l{padding-bottom:140%}.aspect-ratio--1x1-l{padding-bottom:100%}.aspect-ratio--object-l{position:absolute;top:0;right:0;bottom:0;left:0;width:100%;height:100%;z-index:100}.cover-l{background-size:cover!important}.contain-l{background-size:contain!important}.bg-center-l{background-position:50%}.bg-center-l,.bg-top-l{background-repeat:no-repeat}.bg-top-l{background-position:top}.bg-right-l{background-position:100%}.bg-bottom-l,.bg-right-l{background-repeat:no-repeat}.bg-bottom-l{background-position:bottom}.bg-left-l{background-repeat:no-repeat;background-position:0}.ba-l{border-style:solid;border-width:1px}.bt-l{border-top-style:solid;border-top-width:1px}.br-l{border-right-style:solid;border-right-width:1px}.bb-l{border-bottom-style:solid;border-bottom-width:1px}.bl-l{border-left-style:solid;border-left-width:1px}.bn-l{border-style:none;border-width:0}.br0-l{border-radius:0}.br1-l{border-radius:.125rem}.br2-l{border-radius:.25rem}.br3-l{border-radius:.5rem}.br4-l{border-radius:1rem}.br-100-l{border-radius:100%}.br-pill-l{border-radius:9999px}.br--bottom-l{border-top-left-radius:0;border-top-right-radius:0}.br--top-l{border-bottom-right-radius:0}.br--right-l,.br--top-l{border-bottom-left-radius:0}.br--right-l{border-top-left-radius:0}.br--left-l{border-top-right-radius:0;border-bottom-right-radius:0}.b--dotted-l{border-style:dotted}.b--dashed-l{border-style:dashed}.b--solid-l{border-style:solid}.b--none-l{border-style:none}.bw0-l{border-width:0}.bw1-l{border-width:.125rem}.bw2-l{border-width:.25rem}.bw3-l{border-width:.5rem}.bw4-l{border-width:1rem}.bw5-l{border-width:2rem}.bt-0-l{border-top-width:0}.br-0-l{border-right-width:0}.bb-0-l{border-bottom-width:0}.bl-0-l{border-left-width:0}.shadow-1-l{box-shadow:0 0 4px 2px rgba(0,0,0,.2)}.shadow-2-l{box-shadow:0 0 8px 2px rgba(0,0,0,.2)}.shadow-3-l{box-shadow:2px 2px 4px 2px rgba(0,0,0,.2)}.shadow-4-l{box-shadow:2px 2px 8px 0 rgba(0,0,0,.2)}.shadow-5-l{box-shadow:4px 4px 8px 0 rgba(0,0,0,.2)}.top-0-l{top:0}.left-0-l{left:0}.right-0-l{right:0}.bottom-0-l{bottom:0}.top-1-l{top:1rem}.left-1-l{left:1rem}.right-1-l{right:1rem}.bottom-1-l{bottom:1rem}.top-2-l{top:2rem}.left-2-l{left:2rem}.right-2-l{right:2rem}.bottom-2-l{bottom:2rem}.top--1-l{top:-1rem}.right--1-l{right:-1rem}.bottom--1-l{bottom:-1rem}.left--1-l{left:-1rem}.top--2-l{top:-2rem}.right--2-l{right:-2rem}.bottom--2-l{bottom:-2rem}.left--2-l{left:-2rem}.absolute--fill-l{top:0;right:0;bottom:0;left:0}.cl-l{clear:left}.cr-l{clear:right}.cb-l{clear:both}.cn-l{clear:none}.dn-l{display:none}.di-l{display:inline}.db-l{display:block}.dib-l{display:inline-block}.dit-l{display:inline-table}.dt-l{display:table}.dtc-l{display:table-cell}.dt-row-l{display:table-row}.dt-row-group-l{display:table-row-group}.dt-column-l{display:table-column}.dt-column-group-l{display:table-column-group}.dt--fixed-l{table-layout:fixed;width:100%}.flex-l{display:-webkit-box;display:-ms-flexbox;display:flex}.inline-flex-l{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex}.flex-auto-l{-webkit-box-flex:1;-ms-flex:1 1 auto;flex:1 1 auto;min-width:0;min-height:0}.flex-none-l{-webkit-box-flex:0;-ms-flex:none;flex:none}.flex-column-l{-webkit-box-orient:vertical;-ms-flex-direction:column;flex-direction:column}.flex-column-l,.flex-row-l{-webkit-box-direction:normal}.flex-row-l{-webkit-box-orient:horizontal;-ms-flex-direction:row;flex-direction:row}.flex-wrap-l{-ms-flex-wrap:wrap;flex-wrap:wrap}.items-start-l{-webkit-box-align:start;-ms-flex-align:start;align-items:flex-start}.items-end-l{-webkit-box-align:end;-ms-flex-align:end;align-items:flex-end}.items-center-l{-webkit-box-align:center;-ms-flex-align:center;align-items:center}.items-baseline-l{-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline}.items-stretch-l{-webkit-box-align:stretch;-ms-flex-align:stretch;align-items:stretch}.self-start-l{-ms-flex-item-align:start;align-self:flex-start}.self-end-l{-ms-flex-item-align:end;align-self:flex-end}.self-center-l{-ms-flex-item-align:center;-ms-grid-row-align:center;align-self:center}.self-baseline-l{-ms-flex-item-align:baseline;align-self:baseline}.self-stretch-l{-ms-flex-item-align:stretch;-ms-grid-row-align:stretch;align-self:stretch}.justify-start-l{-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start}.justify-end-l{-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end}.justify-center-l{-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.justify-between-l{-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.justify-around-l{-ms-flex-pack:distribute;justify-content:space-around}.content-start-l{-ms-flex-line-pack:start;align-content:flex-start}.content-end-l{-ms-flex-line-pack:end;align-content:flex-end}.content-center-l{-ms-flex-line-pack:center;align-content:center}.content-between-l{-ms-flex-line-pack:justify;align-content:space-between}.content-around-l{-ms-flex-line-pack:distribute;align-content:space-around}.content-stretch-l{-ms-flex-line-pack:stretch;align-content:stretch}.order-0-l{-webkit-box-ordinal-group:1;-ms-flex-order:0;order:0}.order-1-l{-webkit-box-ordinal-group:2;-ms-flex-order:1;order:1}.order-2-l{-webkit-box-ordinal-group:3;-ms-flex-order:2;order:2}.order-3-l{-webkit-box-ordinal-group:4;-ms-flex-order:3;order:3}.order-4-l{-webkit-box-ordinal-group:5;-ms-flex-order:4;order:4}.order-5-l{-webkit-box-ordinal-group:6;-ms-flex-order:5;order:5}.order-6-l{-webkit-box-ordinal-group:7;-ms-flex-order:6;order:6}.order-7-l{-webkit-box-ordinal-group:8;-ms-flex-order:7;order:7}.order-8-l{-webkit-box-ordinal-group:9;-ms-flex-order:8;order:8}.order-last-l{-webkit-box-ordinal-group:100000;-ms-flex-order:99999;order:99999}.fl-l{float:left}.fl-l,.fr-l{display:inline}.fr-l{float:right}.fn-l{float:none}.i-l{font-style:italic}.fs-normal-l{font-style:normal}.normal-l{font-weight:400}.b-l{font-weight:700}.fw1-l{font-weight:100}.fw2-l{font-weight:200}.fw3-l{font-weight:300}.fw4-l{font-weight:400}.fw5-l{font-weight:500}.fw6-l{font-weight:600}.fw7-l{font-weight:700}.fw8-l{font-weight:800}.fw9-l{font-weight:900}.h1-l{height:1rem}.h2-l{height:2rem}.h3-l{height:4rem}.h4-l{height:8rem}.h5-l{height:16rem}.h-25-l{height:25%}.h-50-l{height:50%}.h-75-l{height:75%}.h-100-l{height:100%}.min-h-100-l{min-height:100%}.vh-25-l{height:25vh}.vh-50-l{height:50vh}.vh-75-l{height:75vh}.vh-100-l{height:100vh}.min-vh-100-l{min-height:100vh}.h-auto-l{height:auto}.h-inherit-l{height:inherit}.tracked-l{letter-spacing:.1em}.tracked-tight-l{letter-spacing:-.05em}.tracked-mega-l{letter-spacing:.25em}.lh-solid-l{line-height:1}.lh-title-l{line-height:1.25}.lh-copy-l{line-height:1.5}.mw-100-l{max-width:100%}.mw1-l{max-width:1rem}.mw2-l{max-width:2rem}.mw3-l{max-width:4rem}.mw4-l{max-width:8rem}.mw5-l{max-width:16rem}.mw6-l{max-width:32rem}.mw7-l{max-width:48rem}.mw8-l{max-width:64rem}.mw9-l{max-width:96rem}.mw-none-l{max-width:none}.w1-l{width:1rem}.w2-l{width:2rem}.w3-l{width:4rem}.w4-l{width:8rem}.w5-l{width:16rem}.w-10-l{width:10%}.w-20-l{width:20%}.w-25-l{width:25%}.w-30-l{width:30%}.w-33-l{width:33%}.w-34-l{width:34%}.w-40-l{width:40%}.w-50-l{width:50%}.w-60-l{width:60%}.w-70-l{width:70%}.w-75-l{width:75%}.w-80-l{width:80%}.w-90-l{width:90%}.w-100-l{width:100%}.w-third-l{width:33.33333%}.w-two-thirds-l{width:66.66667%}.w-auto-l{width:auto}.overflow-visible-l{overflow:visible}.overflow-hidden-l{overflow:hidden}.overflow-scroll-l{overflow:scroll}.overflow-auto-l{overflow:auto}.overflow-x-visible-l{overflow-x:visible}.overflow-x-hidden-l{overflow-x:hidden}.overflow-x-scroll-l{overflow-x:scroll}.overflow-x-auto-l{overflow-x:auto}.overflow-y-visible-l{overflow-y:visible}.overflow-y-hidden-l{overflow-y:hidden}.overflow-y-scroll-l{overflow-y:scroll}.overflow-y-auto-l{overflow-y:auto}.static-l{position:static}.relative-l{position:relative}.absolute-l{position:absolute}.fixed-l{position:fixed}.rotate-45-l{-webkit-transform:rotate(45deg);transform:rotate(45deg)}.rotate-90-l{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.rotate-135-l{-webkit-transform:rotate(135deg);transform:rotate(135deg)}.rotate-180-l{-webkit-transform:rotate(180deg);transform:rotate(180deg)}.rotate-225-l{-webkit-transform:rotate(225deg);transform:rotate(225deg)}.rotate-270-l{-webkit-transform:rotate(270deg);transform:rotate(270deg)}.rotate-315-l{-webkit-transform:rotate(315deg);transform:rotate(315deg)}.pa0-l{padding:0}.pa1-l{padding:.25rem}.pa2-l{padding:.5rem}.pa3-l{padding:1rem}.pa4-l{padding:2rem}.pa5-l{padding:4rem}.pa6-l{padding:8rem}.pa7-l{padding:16rem}.pl0-l{padding-left:0}.pl1-l{padding-left:.25rem}.pl2-l{padding-left:.5rem}.pl3-l{padding-left:1rem}.pl4-l{padding-left:2rem}.pl5-l{padding-left:4rem}.pl6-l{padding-left:8rem}.pl7-l{padding-left:16rem}.pr0-l{padding-right:0}.pr1-l{padding-right:.25rem}.pr2-l{padding-right:.5rem}.pr3-l{padding-right:1rem}.pr4-l{padding-right:2rem}.pr5-l{padding-right:4rem}.pr6-l{padding-right:8rem}.pr7-l{padding-right:16rem}.pb0-l{padding-bottom:0}.pb1-l{padding-bottom:.25rem}.pb2-l{padding-bottom:.5rem}.pb3-l{padding-bottom:1rem}.pb4-l{padding-bottom:2rem}.pb5-l{padding-bottom:4rem}.pb6-l{padding-bottom:8rem}.pb7-l{padding-bottom:16rem}.pt0-l{padding-top:0}.pt1-l{padding-top:.25rem}.pt2-l{padding-top:.5rem}.pt3-l{padding-top:1rem}.pt4-l{padding-top:2rem}.pt5-l{padding-top:4rem}.pt6-l{padding-top:8rem}.pt7-l{padding-top:16rem}.pv0-l{padding-top:0;padding-bottom:0}.pv1-l{padding-top:.25rem;padding-bottom:.25rem}.pv2-l{padding-top:.5rem;padding-bottom:.5rem}.pv3-l{padding-top:1rem;padding-bottom:1rem}.pv4-l{padding-top:2rem;padding-bottom:2rem}.pv5-l{padding-top:4rem;padding-bottom:4rem}.pv6-l{padding-top:8rem;padding-bottom:8rem}.pv7-l{padding-top:16rem;padding-bottom:16rem}.ph0-l{padding-left:0;padding-right:0}.ph1-l{padding-left:.25rem;padding-right:.25rem}.ph2-l{padding-left:.5rem;padding-right:.5rem}.ph3-l{padding-left:1rem;padding-right:1rem}.ph4-l{padding-left:2rem;padding-right:2rem}.ph5-l{padding-left:4rem;padding-right:4rem}.ph6-l{padding-left:8rem;padding-right:8rem}.ph7-l{padding-left:16rem;padding-right:16rem}.ma0-l{margin:0}.ma1-l{margin:.25rem}.ma2-l{margin:.5rem}.ma3-l{margin:1rem}.ma4-l{margin:2rem}.ma5-l{margin:4rem}.ma6-l{margin:8rem}.ma7-l{margin:16rem}.ml0-l{margin-left:0}.ml1-l{margin-left:.25rem}.ml2-l{margin-left:.5rem}.ml3-l{margin-left:1rem}.ml4-l{margin-left:2rem}.ml5-l{margin-left:4rem}.ml6-l{margin-left:8rem}.ml7-l{margin-left:16rem}.mr0-l{margin-right:0}.mr1-l{margin-right:.25rem}.mr2-l{margin-right:.5rem}.mr3-l{margin-right:1rem}.mr4-l{margin-right:2rem}.mr5-l{margin-right:4rem}.mr6-l{margin-right:8rem}.mr7-l{margin-right:16rem}.mb0-l{margin-bottom:0}.mb1-l{margin-bottom:.25rem}.mb2-l{margin-bottom:.5rem}.mb3-l{margin-bottom:1rem}.mb4-l{margin-bottom:2rem}.mb5-l{margin-bottom:4rem}.mb6-l{margin-bottom:8rem}.mb7-l{margin-bottom:16rem}.mt0-l{margin-top:0}.mt1-l{margin-top:.25rem}.mt2-l{margin-top:.5rem}.mt3-l{margin-top:1rem}.mt4-l{margin-top:2rem}.mt5-l{margin-top:4rem}.mt6-l{margin-top:8rem}.mt7-l{margin-top:16rem}.mv0-l{margin-top:0;margin-bottom:0}.mv1-l{margin-top:.25rem;margin-bottom:.25rem}.mv2-l{margin-top:.5rem;margin-bottom:.5rem}.mv3-l{margin-top:1rem;margin-bottom:1rem}.mv4-l{margin-top:2rem;margin-bottom:2rem}.mv5-l{margin-top:4rem;margin-bottom:4rem}.mv6-l{margin-top:8rem;margin-bottom:8rem}.mv7-l{margin-top:16rem;margin-bottom:16rem}.mh0-l{margin-left:0;margin-right:0}.mh1-l{margin-left:.25rem;margin-right:.25rem}.mh2-l{margin-left:.5rem;margin-right:.5rem}.mh3-l{margin-left:1rem;margin-right:1rem}.mh4-l{margin-left:2rem;margin-right:2rem}.mh5-l{margin-left:4rem;margin-right:4rem}.mh6-l{margin-left:8rem;margin-right:8rem}.mh7-l{margin-left:16rem;margin-right:16rem}.na1-l{margin:-.25rem}.na2-l{margin:-.5rem}.na3-l{margin:-1rem}.na4-l{margin:-2rem}.na5-l{margin:-4rem}.na6-l{margin:-8rem}.na7-l{margin:-16rem}.nl1-l{margin-left:-.25rem}.nl2-l{margin-left:-.5rem}.nl3-l{margin-left:-1rem}.nl4-l{margin-left:-2rem}.nl5-l{margin-left:-4rem}.nl6-l{margin-left:-8rem}.nl7-l{margin-left:-16rem}.nr1-l{margin-right:-.25rem}.nr2-l{margin-right:-.5rem}.nr3-l{margin-right:-1rem}.nr4-l{margin-right:-2rem}.nr5-l{margin-right:-4rem}.nr6-l{margin-right:-8rem}.nr7-l{margin-right:-16rem}.nb1-l{margin-bottom:-.25rem}.nb2-l{margin-bottom:-.5rem}.nb3-l{margin-bottom:-1rem}.nb4-l{margin-bottom:-2rem}.nb5-l{margin-bottom:-4rem}.nb6-l{margin-bottom:-8rem}.nb7-l{margin-bottom:-16rem}.nt1-l{margin-top:-.25rem}.nt2-l{margin-top:-.5rem}.nt3-l{margin-top:-1rem}.nt4-l{margin-top:-2rem}.nt5-l{margin-top:-4rem}.nt6-l{margin-top:-8rem}.nt7-l{margin-top:-16rem}.strike-l{text-decoration:line-through}.underline-l{text-decoration:underline}.no-underline-l{text-decoration:none}.tl-l{text-align:left}.tr-l{text-align:right}.tc-l{text-align:center}.ttc-l{text-transform:capitalize}.ttl-l{text-transform:lowercase}.ttu-l{text-transform:uppercase}.ttn-l{text-transform:none}.f-6-l,.f-headline-l{font-size:6rem}.f-5-l,.f-subheadline-l{font-size:5rem}.f1-l{font-size:3rem}.f2-l{font-size:2.25rem}.f3-l{font-size:1.5rem}.f4-l{font-size:1.25rem}.f5-l{font-size:1rem}.f6-l{font-size:.875rem}.measure-l{max-width:30em}.measure-wide-l{max-width:34em}.measure-narrow-l{max-width:20em}.indent-l{text-indent:1em;margin-top:0;margin-bottom:0}.small-caps-l{font-variant:small-caps}.truncate-l{white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.clip-l{position:fixed!important;position:absolute!important;clip:rect(1px 1px 1px 1px);clip:rect(1px,1px,1px,1px)}.ws-normal-l{white-space:normal}.nowrap-l{white-space:nowrap}.pre-l{white-space:pre}.v-base-l{vertical-align:baseline}.v-mid-l{vertical-align:middle}.v-top-l{vertical-align:top}.v-btm-l{vertical-align:bottom}} + diff --git a/package.json b/package.json new file mode 100644 index 000000000..b842d06b5 --- /dev/null +++ b/package.json @@ -0,0 +1,17 @@ +{ + "name": "se-challenge-expenses", + "version": "1.0.0", + "main": "server.js", + "repository": "git@github.com:kiasaki/wave-challenge.git", + "author": "Frederic Gingras ", + "license": "MIT", + "dependencies": { + "bankai": "^5.2.1", + "choo": "^4.0.3", + "knex": "^0.12.6", + "merry": "^4.1.0" + }, + "devDependencies": { + "standard": "^8.6.0" + } +} diff --git a/server.js b/server.js new file mode 100644 index 000000000..8fe99bfd9 --- /dev/null +++ b/server.js @@ -0,0 +1,43 @@ +var fs = require('fs') +var path = require('path') +var http = require('http') +var merry = require('merry') +var bankai = require('bankai') + +var env = merry.env({PORT: 8000}) +var app = merry() + +app.router([ + // Static assets + ['/', serveStaticFile('index.html', 'text/html')], + ['/app.js', serveClientJs], + ['/app.css', serveStaticFile('app.css', 'text/css')], + ['/tachyons.min.css', serveStaticFile('tachyons.min.css', 'text/css')], + + // API + ['/upload', {get: handleUpload}], + + // Error and Not found handlers + ['/404', serveStaticFile('not-found.html', 'text/html')] +]) + +http.createServer(app.start()).listen(env.PORT) +app.log.info('started listening on port ' + env.PORT) + +function handleUpload (req, res, ctx, done) { + done(merry.error({statusCode: 400})) + done(null, 'hello world') +} + +function serveClientJs (req, res, ctx, done) { + var clientPath = path.join(__dirname, 'client', 'app.js') + done(null, bankai(clientPath).js(req, res)) +} + +function serveStaticFile (filename, contentType) { + return function (req, res, ctx, done) { + var absolutePath = path.join(__dirname, 'client', filename) + res.writeHead(200, {'Content-Type': contentType}) + done(null, fs.createReadStream(absolutePath).pipe(res)) + } +} diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 000000000..e0987647b --- /dev/null +++ b/yarn.lock @@ -0,0 +1,3446 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +JSONStream@^1.0.3: + version "1.3.0" + resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.0.tgz#680ab9ac6572a8a1a207e0b38721db1c77b215e5" + dependencies: + jsonparse "^1.2.0" + through ">=2.2.7 <3" + +abbrev@1: + version "1.0.9" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135" + +acorn-jsx@^3.0.0, acorn-jsx@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" + dependencies: + acorn "^3.0.4" + +acorn@^1.0.3: + version "1.2.2" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-1.2.2.tgz#c8ce27de0acc76d896d2b1fad3df588d9e82f014" + +acorn@^2.1.0, acorn@^2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-2.7.0.tgz#ab6e7d9d886aaca8b085bc3312b79a198433f0e7" + +acorn@^3.0.4, acorn@^3.1.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" + +acorn@^4.0.0, acorn@^4.0.1: + version "4.0.4" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.4.tgz#17a8d6a7a6c4ef538b814ec9abac2779293bf30a" + +ajv-keywords@^1.0.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.0.tgz#c11e6859eafff83e0dafc416929472eca946aa2c" + +ajv@^4.7.0: + version "4.10.4" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.10.4.tgz#c0974dd00b3464984892d6010aa9c2c945933254" + dependencies: + co "^4.6.0" + json-stable-stringify "^1.0.1" + +align-text@^0.1.1, align-text@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117" + dependencies: + kind-of "^3.0.2" + longest "^1.0.1" + repeat-string "^1.5.2" + +amdefine@>=0.0.4: + version "1.0.1" + resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" + +ansi-escapes@^1.1.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" + +ansi-regex@^0.2.0, ansi-regex@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-0.2.1.tgz#0d8e946967a3d8143f93e24e298525fc1b2235f9" + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + +ansi-styles@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-1.1.0.tgz#eaecbf66cd706882760b2f4691582b8f55d7a7de" + +ansi-styles@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + +anymatch@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.0.tgz#a3e52fa39168c825ff57b0248126ce5a8ff95507" + dependencies: + arrify "^1.0.0" + micromatch "^2.1.5" + +ap@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/ap/-/ap-0.1.0.tgz#d8a3f26615379398a1b53ca6cc1a666a0fbfe150" + +aproba@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.0.4.tgz#2713680775e7614c8ba186c065d4e2e52d1072c0" + +are-we-there-yet@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.2.tgz#80e470e95a084794fe1899262c5667c6e88de1b3" + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.0 || ^1.1.13" + +argparse@^1.0.7: + version "1.0.9" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86" + dependencies: + sprintf-js "~1.0.2" + +arr-diff@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" + dependencies: + arr-flatten "^1.0.1" + +arr-flatten@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.0.1.tgz#e5ffe54d45e19f32f216e91eb99c8ce892bb604b" + +array-filter@~0.0.0: + version "0.0.1" + resolved "https://registry.yarnpkg.com/array-filter/-/array-filter-0.0.1.tgz#7da8cf2e26628ed732803581fd21f67cacd2eeec" + +array-map@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/array-map/-/array-map-0.0.0.tgz#88a2bab73d1cf7bcd5c1b118a003f66f665fa662" + +array-reduce@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/array-reduce/-/array-reduce-0.0.0.tgz#173899d3ffd1c7d9383e4479525dbe278cab5f2b" + +array-union@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" + dependencies: + array-uniq "^1.0.1" + +array-uniq@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" + +array-unique@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" + +arrify@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" + +asn1.js@^4.0.0: + version "4.9.1" + resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.9.1.tgz#48ba240b45a9280e94748990ba597d216617fd40" + dependencies: + bn.js "^4.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +asn1@~0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" + +assert-plus@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" + +assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + +assert@^1.4.0: + version "1.4.1" + resolved "https://registry.yarnpkg.com/assert/-/assert-1.4.1.tgz#99912d591836b5a6f5b345c0f07eefc08fc65d91" + dependencies: + util "0.10.3" + +astw@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/astw/-/astw-2.0.0.tgz#08121ac8288d35611c0ceec663f6cd545604897d" + dependencies: + acorn "^1.0.3" + +async-each@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" + +async@~0.2.6: + version "0.2.10" + resolved "https://registry.yarnpkg.com/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1" + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + +aws-sign2@~0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" + +aws4@^1.2.1: + version "1.5.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.5.0.tgz#0a29ffb79c31c9e712eeb087e8e7a64b4a56d755" + +babel-code-frame@^6.16.0: + version "6.20.0" + resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.20.0.tgz#b968f839090f9a8bc6d41938fb96cb84f7387b26" + dependencies: + chalk "^1.1.0" + esutils "^2.0.2" + js-tokens "^2.0.0" + +babel-runtime@^6.11.6: + version "6.20.0" + resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.20.0.tgz#87300bdcf4cd770f09bf0048c64204e17806d16f" + dependencies: + core-js "^2.4.0" + regenerator-runtime "^0.10.0" + +balanced-match@^0.4.1: + version "0.4.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" + +bankai@^5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/bankai/-/bankai-5.2.1.tgz#3f155b7268dd46b52525c1ad3135e9f2caae206b" + dependencies: + bole "^3.0.1" + browserify "^13.1.0" + bundle-collapser "^1.2.1" + concat-stream "^1.5.2" + create-html "^1.1.0" + css-extract "^1.2.0" + explain-error "^1.0.3" + from2 "^2.3.0" + garnish "^5.2.0" + map-limit "0.0.1" + mkdirp "^0.5.1" + opn "^4.0.2" + pump "^1.0.1" + resolve "^1.1.7" + sheetify "^6.0.1" + subarg "^1.0.0" + uglifyify "^3.0.4" + unassertify "^2.0.3" + watchify "^3.7.0" + watchify-request "^2.1.0" + xtend "^4.0.1" + yo-yoify "^3.5.0" + +barracks@^9.0.0: + version "9.3.0" + resolved "https://registry.yarnpkg.com/barracks/-/barracks-9.3.0.tgz#8eb222e62e814531c84a0718a83867113bd89c03" + dependencies: + nanotick "^1.1.2" + xtend "^4.0.1" + +base64-js@^1.0.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.0.tgz#a39992d723584811982be5e290bb6a53d86700f1" + +bcrypt-pbkdf@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.0.tgz#3ca76b85241c7170bf7d9703e7b9aa74630040d4" + dependencies: + tweetnacl "^0.14.3" + +bel@^4.0.0: + version "4.5.1" + resolved "https://registry.yarnpkg.com/bel/-/bel-4.5.1.tgz#fd857415359780ad195670bdd02766ab2f71f182" + dependencies: + global "^4.3.0" + hyperx "^2.0.2" + on-load "^3.2.0" + +binary-extensions@^1.0.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.8.0.tgz#48ec8d16df4377eae5fa5884682480af4d95c774" + +bl@^0.9.3: + version "0.9.5" + resolved "https://registry.yarnpkg.com/bl/-/bl-0.9.5.tgz#c06b797af085ea00bc527afc8efcf11de2232054" + dependencies: + readable-stream "~1.0.26" + +bl@^1.1.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.0.tgz#1397e7ec42c5f5dc387470c500e34a9f6be9ea98" + dependencies: + readable-stream "^2.0.5" + +block-stream@*: + version "0.0.9" + resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" + dependencies: + inherits "~2.0.0" + +bluebird@^3.4.6: + version "3.4.7" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.4.7.tgz#f72d760be09b7f76d08ed8fae98b289a8d05fab3" + +bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: + version "4.11.6" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.6.tgz#53344adb14617a13f6e8dd2ce28905d1c0ba3215" + +body@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/body/-/body-0.1.0.tgz#e714fe28cd8848aa34cdf2c9f242bbe2e15d1cd8" + dependencies: + content-types "~0.1.0" + +bole@^3.0.1: + version "3.0.2" + resolved "https://registry.yarnpkg.com/bole/-/bole-3.0.2.tgz#bc8a483ca94049da9b837c1ad11cdfebee6e0514" + dependencies: + fast-safe-stringify "~1.1.0" + individual "~3.0.0" + +boom@2.x.x: + version "2.10.1" + resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" + dependencies: + hoek "2.x.x" + +boom@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/boom/-/boom-4.2.0.tgz#c1a74174b11fbba223f6162d4fd8851a1b82a536" + dependencies: + hoek "4.x.x" + +brace-expansion@^1.0.0: + version "1.1.6" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.6.tgz#7197d7eaa9b87e648390ea61fc66c84427420df9" + dependencies: + balanced-match "^0.4.1" + concat-map "0.0.1" + +braces@^1.8.2: + version "1.8.5" + resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" + dependencies: + expand-range "^1.8.1" + preserve "^0.2.0" + repeat-element "^1.1.2" + +brorand@^1.0.1: + version "1.0.6" + resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.0.6.tgz#4028706b915f91f7b349a2e0bf3c376039d216e5" + +browser-pack@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/browser-pack/-/browser-pack-5.0.1.tgz#4197719b20c6e0aaa09451c5111e53efb6fbc18d" + dependencies: + JSONStream "^1.0.3" + combine-source-map "~0.6.1" + defined "^1.0.0" + through2 "^1.0.0" + umd "^3.0.0" + +browser-pack@^6.0.1: + version "6.0.2" + resolved "https://registry.yarnpkg.com/browser-pack/-/browser-pack-6.0.2.tgz#f86cd6cef4f5300c8e63e07a4d512f65fbff4531" + dependencies: + JSONStream "^1.0.3" + combine-source-map "~0.7.1" + defined "^1.0.0" + through2 "^2.0.0" + umd "^3.0.0" + +browser-resolve@^1.11.0, browser-resolve@^1.7.0: + version "1.11.2" + resolved "https://registry.yarnpkg.com/browser-resolve/-/browser-resolve-1.11.2.tgz#8ff09b0a2c421718a1051c260b32e48f442938ce" + dependencies: + resolve "1.1.7" + +browser-unpack@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/browser-unpack/-/browser-unpack-1.1.1.tgz#42d1423bf719074c1ef88d82e6b94752a41882bd" + dependencies: + acorn "^2.1.0" + browser-pack "^5.0.1" + concat-stream "^1.5.0" + minimist "^1.1.1" + +browserify-aes@^1.0.0, browserify-aes@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.0.6.tgz#5e7725dbdef1fd5930d4ebab48567ce451c48a0a" + dependencies: + buffer-xor "^1.0.2" + cipher-base "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.0" + inherits "^2.0.1" + +browserify-cipher@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.0.tgz#9988244874bf5ed4e28da95666dcd66ac8fc363a" + dependencies: + browserify-aes "^1.0.4" + browserify-des "^1.0.0" + evp_bytestokey "^1.0.0" + +browserify-des@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.0.tgz#daa277717470922ed2fe18594118a175439721dd" + dependencies: + cipher-base "^1.0.1" + des.js "^1.0.0" + inherits "^2.0.1" + +browserify-rsa@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524" + dependencies: + bn.js "^4.1.0" + randombytes "^2.0.1" + +browserify-sign@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.0.0.tgz#10773910c3c206d5420a46aad8694f820b85968f" + dependencies: + bn.js "^4.1.1" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.2" + elliptic "^6.0.0" + inherits "^2.0.1" + parse-asn1 "^5.0.0" + +browserify-zlib@~0.1.2: + version "0.1.4" + resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.1.4.tgz#bb35f8a519f600e0fa6b8485241c979d0141fb2d" + dependencies: + pako "~0.2.0" + +browserify@^13.0.0, browserify@^13.1.0: + version "13.3.0" + resolved "https://registry.yarnpkg.com/browserify/-/browserify-13.3.0.tgz#b5a9c9020243f0c70e4675bec8223bc627e415ce" + dependencies: + JSONStream "^1.0.3" + assert "^1.4.0" + browser-pack "^6.0.1" + browser-resolve "^1.11.0" + browserify-zlib "~0.1.2" + buffer "^4.1.0" + cached-path-relative "^1.0.0" + concat-stream "~1.5.1" + console-browserify "^1.1.0" + constants-browserify "~1.0.0" + crypto-browserify "^3.0.0" + defined "^1.0.0" + deps-sort "^2.0.0" + domain-browser "~1.1.0" + duplexer2 "~0.1.2" + events "~1.1.0" + glob "^7.1.0" + has "^1.0.0" + htmlescape "^1.1.0" + https-browserify "~0.0.0" + inherits "~2.0.1" + insert-module-globals "^7.0.0" + labeled-stream-splicer "^2.0.0" + module-deps "^4.0.8" + os-browserify "~0.1.1" + parents "^1.0.1" + path-browserify "~0.0.0" + process "~0.11.0" + punycode "^1.3.2" + querystring-es3 "~0.2.0" + read-only-stream "^2.0.0" + readable-stream "^2.0.2" + resolve "^1.1.4" + shasum "^1.0.0" + shell-quote "^1.6.1" + stream-browserify "^2.0.0" + stream-http "^2.0.0" + string_decoder "~0.10.0" + subarg "^1.0.0" + syntax-error "^1.1.1" + through2 "^2.0.0" + timers-browserify "^1.0.1" + tty-browserify "~0.0.0" + url "~0.11.0" + util "~0.10.1" + vm-browserify "~0.0.1" + xtend "^4.0.0" + +buffer-shims@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/buffer-shims/-/buffer-shims-1.0.0.tgz#9978ce317388c649ad8793028c3477ef044a8b51" + +buffer-xor@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" + +buffer@^4.1.0: + version "4.9.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + isarray "^1.0.0" + +builtin-status-codes@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" + +bundle-collapser@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/bundle-collapser/-/bundle-collapser-1.2.1.tgz#e119afc92638e440b9085f47ae081fa756cba33d" + dependencies: + browser-pack "^5.0.1" + browser-unpack "^1.1.0" + concat-stream "^1.5.0" + falafel "^1.2.0" + minimist "^1.1.1" + through2 "^2.0.0" + +cached-path-relative@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/cached-path-relative/-/cached-path-relative-1.0.0.tgz#d1094c577fbd9a8b8bd43c96af6188aa205d05f4" + +call-matcher@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/call-matcher/-/call-matcher-1.0.1.tgz#5134d077984f712a54dad3cbf62de28dce416ca8" + dependencies: + core-js "^2.0.0" + deep-equal "^1.0.0" + espurify "^1.6.0" + estraverse "^4.0.0" + +caller-path@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" + dependencies: + callsites "^0.2.0" + +callsites@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" + +camelcase@^1.0.2: + version "1.2.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" + +caseless@~0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7" + +center-align@^0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad" + dependencies: + align-text "^0.1.3" + lazy-cache "^1.0.3" + +chalk@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-0.5.1.tgz#663b3a648b68b55d04690d49167aa837858f2174" + dependencies: + ansi-styles "^1.1.0" + escape-string-regexp "^1.0.0" + has-ansi "^0.1.0" + strip-ansi "^0.3.0" + supports-color "^0.2.0" + +chalk@^1.0.0, chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + dependencies: + ansi-styles "^2.2.1" + escape-string-regexp "^1.0.2" + has-ansi "^2.0.0" + strip-ansi "^3.0.0" + supports-color "^2.0.0" + +chokidar@^1.0.0: + version "1.6.1" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.6.1.tgz#2f4447ab5e96e50fb3d789fd90d4c72e0e4c70c2" + dependencies: + anymatch "^1.3.0" + async-each "^1.0.0" + glob-parent "^2.0.0" + inherits "^2.0.1" + is-binary-path "^1.0.0" + is-glob "^2.0.0" + path-is-absolute "^1.0.0" + readdirp "^2.0.0" + optionalDependencies: + fsevents "^1.0.0" + +choo@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/choo/-/choo-4.0.3.tgz#e099cfec9a761560b636a97fc44fdecc7fdb8829" + dependencies: + barracks "^9.0.0" + document-ready "~1.0.2" + global "^4.3.0" + nanoraf "^2.1.1" + sheet-router "^4.0.1" + xtend "^4.0.1" + yo-yo "^1.2.2" + +cipher-base@^1.0.0, cipher-base@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.3.tgz#eeabf194419ce900da3018c207d212f2a6df0a07" + dependencies: + inherits "^2.0.1" + +circular-json@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.1.tgz#be8b36aefccde8b3ca7aa2d6afc07a37242c0d2d" + +cli-cursor@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" + dependencies: + restore-cursor "^1.0.1" + +cli-width@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.1.0.tgz#b234ca209b29ef66fc518d9b98d5847b00edf00a" + +cliui@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1" + dependencies: + center-align "^0.1.1" + right-align "^0.1.1" + wordwrap "0.0.2" + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + +combine-errors@3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/combine-errors/-/combine-errors-3.0.1.tgz#79a04c22db8a6c5846a951dc41e8838f92e1c1e9" + dependencies: + custom-error-instance "2.1.1" + +combine-source-map@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/combine-source-map/-/combine-source-map-0.6.1.tgz#9b4a09c316033d768e0f11e029fa2730e079ad96" + dependencies: + convert-source-map "~1.1.0" + inline-source-map "~0.5.0" + lodash.memoize "~3.0.3" + source-map "~0.4.2" + +combine-source-map@~0.7.1: + version "0.7.2" + resolved "https://registry.yarnpkg.com/combine-source-map/-/combine-source-map-0.7.2.tgz#0870312856b307a87cc4ac486f3a9a62aeccc09e" + dependencies: + convert-source-map "~1.1.0" + inline-source-map "~0.6.0" + lodash.memoize "~3.0.3" + source-map "~0.5.3" + +combined-stream@^1.0.5, combined-stream@~1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009" + dependencies: + delayed-stream "~1.0.0" + +commander@2.5.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.5.0.tgz#d777b6a4d847d423e5d475da864294ac1ff5aa9d" + +commander@^2.2.0, commander@^2.9.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" + dependencies: + graceful-readlink ">= 1.0.0" + +component-type@1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/component-type/-/component-type-1.2.1.tgz#8a47901700238e4fc32269771230226f24b415a9" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + +concat-stream@^1.4.6, concat-stream@^1.5.0, concat-stream@^1.5.2, concat-stream@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7" + dependencies: + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" + +concat-stream@~1.4.5: + version "1.4.10" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.4.10.tgz#acc3bbf5602cb8cc980c6ac840fa7d8603e3ef36" + dependencies: + inherits "~2.0.1" + readable-stream "~1.1.9" + typedarray "~0.0.5" + +concat-stream@~1.5.0, concat-stream@~1.5.1: + version "1.5.2" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.5.2.tgz#708978624d856af41a5a741defdd261da752c266" + dependencies: + inherits "~2.0.1" + readable-stream "~2.0.0" + typedarray "~0.0.5" + +console-browserify@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10" + dependencies: + date-now "^0.1.4" + +console-control-strings@^1.0.0, console-control-strings@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + +constants-browserify@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" + +content-types@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/content-types/-/content-types-0.1.0.tgz#0e790b3abfef90f6ecb77ae8585db9099caf7578" + dependencies: + iterators "~0.1.0" + +convert-source-map@^1.1.1, convert-source-map@~1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.1.3.tgz#4829c877e9fe49b3161f3bf3673888e204699860" + +core-js@^2.0.0, core-js@^2.4.0: + version "2.4.1" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.4.1.tgz#4de911e667b0eae9124e34254b53aea6fc618d3e" + +core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + +corsify@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/corsify/-/corsify-2.1.0.tgz#11a45bc47ab30c54d00bb869ea1802fbcd9a09d0" + dependencies: + http-methods "~0.1.0" + +create-ecdh@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.0.tgz#888c723596cdf7612f6498233eebd7a35301737d" + dependencies: + bn.js "^4.1.0" + elliptic "^6.0.0" + +create-hash@^1.1.0, create-hash@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.1.2.tgz#51210062d7bb7479f6c65bb41a92208b1d61abad" + dependencies: + cipher-base "^1.0.1" + inherits "^2.0.1" + ripemd160 "^1.0.0" + sha.js "^2.3.6" + +create-hmac@^1.1.0, create-hmac@^1.1.2: + version "1.1.4" + resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.4.tgz#d3fb4ba253eb8b3f56e39ea2fbcb8af747bd3170" + dependencies: + create-hash "^1.1.0" + inherits "^2.0.1" + +create-html@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/create-html/-/create-html-1.1.0.tgz#238b59104f99b9a460e7dae73829c96e17c00454" + dependencies: + exit "^0.1.2" + minimist "^1.2.0" + +cryptiles@2.x.x: + version "2.0.5" + resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" + dependencies: + boom "2.x.x" + +crypto-browserify@^3.0.0: + version "3.11.0" + resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.11.0.tgz#3652a0906ab9b2a7e0c3ce66a408e957a2485522" + dependencies: + browserify-cipher "^1.0.0" + browserify-sign "^4.0.0" + create-ecdh "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.0" + diffie-hellman "^5.0.0" + inherits "^2.0.1" + pbkdf2 "^3.0.3" + public-encrypt "^4.0.0" + randombytes "^2.0.0" + +css-extract@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/css-extract/-/css-extract-1.2.0.tgz#c4a67509b8a55f10ca0b7a95d0496a09bec8ce2b" + dependencies: + bl "^1.1.2" + from2-string "^1.1.0" + static-module "^1.3.0" + through2 "^2.0.1" + +custom-error-instance@2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/custom-error-instance/-/custom-error-instance-2.1.1.tgz#3cf6391487a6629a6247eb0ca0ce00081b7e361a" + +d@^0.1.1, d@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/d/-/d-0.1.1.tgz#da184c535d18d8ee7ba2aa229b914009fae11309" + dependencies: + es5-ext "~0.10.2" + +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + dependencies: + assert-plus "^1.0.0" + +date-now@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" + +debug-log@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/debug-log/-/debug-log-1.0.1.tgz#2307632d4c04382b8df8a32f70b895046d52745f" + +debug@^2.1.1, debug@^2.1.3: + version "2.6.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.0.tgz#bc596bcabe7617f11d9fa15361eded5608b8499b" + dependencies: + ms "0.7.2" + +debug@~2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" + dependencies: + ms "0.7.1" + +decamelize@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + +deep-equal@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" + +deep-extend@~0.4.0: + version "0.4.1" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.1.tgz#efe4113d08085f4e6f9687759810f807469e2253" + +deep-is@~0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" + +defined@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" + +deglob@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/deglob/-/deglob-2.1.0.tgz#4d44abe16ef32c779b4972bd141a80325029a14a" + dependencies: + find-root "^1.0.0" + glob "^7.0.5" + ignore "^3.0.9" + pkg-config "^1.1.0" + run-parallel "^1.1.2" + uniq "^1.0.1" + +del@^2.0.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" + dependencies: + globby "^5.0.0" + is-path-cwd "^1.0.0" + is-path-in-cwd "^1.0.0" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + rimraf "^2.2.8" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + +deps-sort@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/deps-sort/-/deps-sort-2.0.0.tgz#091724902e84658260eb910748cccd1af6e21fb5" + dependencies: + JSONStream "^1.0.3" + shasum "^1.0.0" + subarg "^1.0.0" + through2 "^2.0.0" + +des.js@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.0.tgz#c074d2e2aa6a8a9a07dbd61f9a15c2cd83ec8ecc" + dependencies: + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +detect-file@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-0.1.0.tgz#4935dedfd9488648e006b0129566e9386711ea63" + dependencies: + fs-exists-sync "^0.1.0" + +detective@^4.0.0: + version "4.3.2" + resolved "https://registry.yarnpkg.com/detective/-/detective-4.3.2.tgz#77697e2e7947ac3fe7c8e26a6d6f115235afa91c" + dependencies: + acorn "^3.1.0" + defined "^1.0.0" + +diffie-hellman@^5.0.0: + version "5.0.2" + resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.2.tgz#b5835739270cfe26acf632099fded2a07f209e5e" + dependencies: + bn.js "^4.1.0" + miller-rabin "^4.0.0" + randombytes "^2.0.0" + +doctrine@^1.2.2: + version "1.5.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" + dependencies: + esutils "^2.0.2" + isarray "^1.0.0" + +document-ready@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/document-ready/-/document-ready-1.0.3.tgz#eed81e09b37a687c5e6d02b3f0e5706276e82727" + dependencies: + global "~4.3.0" + +dom-walk@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.1.tgz#672226dc74c8f799ad35307df936aba11acd6018" + +domain-browser@~1.1.0: + version "1.1.7" + resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.1.7.tgz#867aa4b093faa05f1de08c06f4d7b21fdf8698bc" + +duplexer2@^0.1.2, duplexer2@~0.1.0, duplexer2@~0.1.2: + version "0.1.4" + resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.1.4.tgz#8b12dab878c0d69e3e7891051662a32fc6bddcc1" + dependencies: + readable-stream "^2.0.2" + +duplexer2@~0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.0.2.tgz#c614dcf67e2fb14995a91711e5a617e8a60a31db" + dependencies: + readable-stream "~1.1.9" + +ecc-jsbn@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" + dependencies: + jsbn "~0.1.0" + +elliptic@^6.0.0: + version "6.3.2" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.3.2.tgz#e4c81e0829cf0a65ab70e998b8232723b5c1bc48" + dependencies: + bn.js "^4.4.0" + brorand "^1.0.1" + hash.js "^1.0.0" + inherits "^2.0.1" + +end-of-stream@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.1.0.tgz#e9353258baa9108965efc41cb0ef8ade2f3cfb07" + dependencies: + once "~1.3.0" + +envobj@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/envobj/-/envobj-1.0.3.tgz#846556a4180c5f06840d8670eb538806c43f62d4" + dependencies: + combine-errors "3.0.1" + component-type "1.2.1" + envvar "1.1.0" + localenv "0.2.2" + object-assign "4.0.1" + +envvar@1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/envvar/-/envvar-1.1.0.tgz#c25a0866edae87046d976c8db037489551639b94" + +es5-ext@^0.10.7, es5-ext@^0.10.8, es5-ext@~0.10.11, es5-ext@~0.10.2, es5-ext@~0.10.7: + version "0.10.12" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.12.tgz#aa84641d4db76b62abba5e45fd805ecbab140047" + dependencies: + es6-iterator "2" + es6-symbol "~3.1" + +es6-iterator@2: + version "2.0.0" + resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.0.tgz#bd968567d61635e33c0b80727613c9cb4b096bac" + dependencies: + d "^0.1.1" + es5-ext "^0.10.7" + es6-symbol "3" + +es6-map@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/es6-map/-/es6-map-0.1.4.tgz#a34b147be224773a4d7da8072794cefa3632b897" + dependencies: + d "~0.1.1" + es5-ext "~0.10.11" + es6-iterator "2" + es6-set "~0.1.3" + es6-symbol "~3.1.0" + event-emitter "~0.3.4" + +es6-set@~0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.4.tgz#9516b6761c2964b92ff479456233a247dc707ce8" + dependencies: + d "~0.1.1" + es5-ext "~0.10.11" + es6-iterator "2" + es6-symbol "3" + event-emitter "~0.3.4" + +es6-symbol@3, es6-symbol@~3.1, es6-symbol@~3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.0.tgz#94481c655e7a7cad82eba832d97d5433496d7ffa" + dependencies: + d "~0.1.1" + es5-ext "~0.10.11" + +es6-weak-map@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.1.tgz#0d2bbd8827eb5fb4ba8f97fbfea50d43db21ea81" + dependencies: + d "^0.1.1" + es5-ext "^0.10.8" + es6-iterator "2" + es6-symbol "3" + +escape-string-regexp@^1.0.0, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + +escodegen@^1.6.1, escodegen@^1.8.1: + version "1.8.1" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.8.1.tgz#5a5b53af4693110bebb0867aa3430dd3b70a1018" + dependencies: + esprima "^2.7.1" + estraverse "^1.9.1" + esutils "^2.0.2" + optionator "^0.8.1" + optionalDependencies: + source-map "~0.2.0" + +escodegen@~0.0.24: + version "0.0.28" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-0.0.28.tgz#0e4ff1715f328775d6cab51ac44a406cd7abffd3" + dependencies: + esprima "~1.0.2" + estraverse "~1.3.0" + optionalDependencies: + source-map ">= 0.1.2" + +escodegen@~1.3.2: + version "1.3.3" + resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.3.3.tgz#f024016f5a88e046fd12005055e939802e6c5f23" + dependencies: + esprima "~1.1.1" + estraverse "~1.5.0" + esutils "~1.0.0" + optionalDependencies: + source-map "~0.1.33" + +escope@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/escope/-/escope-3.6.0.tgz#e01975e812781a163a6dadfdd80398dc64c889c3" + dependencies: + es6-map "^0.1.3" + es6-weak-map "^2.0.1" + esrecurse "^4.1.0" + estraverse "^4.1.1" + +eslint-config-standard-jsx@3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/eslint-config-standard-jsx/-/eslint-config-standard-jsx-3.2.0.tgz#c240e26ed919a11a42aa4de8059472b38268d620" + +eslint-config-standard@6.2.1: + version "6.2.1" + resolved "https://registry.yarnpkg.com/eslint-config-standard/-/eslint-config-standard-6.2.1.tgz#d3a68aafc7191639e7ee441e7348739026354292" + +eslint-plugin-promise@~3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-promise/-/eslint-plugin-promise-3.4.0.tgz#6ba9048c2df57be77d036e0c68918bc9b4fc4195" + +eslint-plugin-react@~6.7.1: + version "6.7.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-react/-/eslint-plugin-react-6.7.1.tgz#1af96aea545856825157d97c1b50d5a8fb64a5a7" + dependencies: + doctrine "^1.2.2" + jsx-ast-utils "^1.3.3" + +eslint-plugin-standard@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/eslint-plugin-standard/-/eslint-plugin-standard-2.0.1.tgz#3589699ff9c917f2c25f76a916687f641c369ff3" + +eslint@~3.10.2: + version "3.10.2" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-3.10.2.tgz#c9a10e8bf6e9d65651204778c503341f1eac3ce7" + dependencies: + babel-code-frame "^6.16.0" + chalk "^1.1.3" + concat-stream "^1.4.6" + debug "^2.1.1" + doctrine "^1.2.2" + escope "^3.6.0" + espree "^3.3.1" + estraverse "^4.2.0" + esutils "^2.0.2" + file-entry-cache "^2.0.0" + glob "^7.0.3" + globals "^9.2.0" + ignore "^3.2.0" + imurmurhash "^0.1.4" + inquirer "^0.12.0" + is-my-json-valid "^2.10.0" + is-resolvable "^1.0.0" + js-yaml "^3.5.1" + json-stable-stringify "^1.0.0" + levn "^0.3.0" + lodash "^4.0.0" + mkdirp "^0.5.0" + natural-compare "^1.4.0" + optionator "^0.8.2" + path-is-inside "^1.0.1" + pluralize "^1.2.1" + progress "^1.1.8" + require-uncached "^1.0.2" + shelljs "^0.7.5" + strip-bom "^3.0.0" + strip-json-comments "~1.0.1" + table "^3.7.8" + text-table "~0.2.0" + user-home "^2.0.0" + +espree@^3.3.1: + version "3.3.2" + resolved "https://registry.yarnpkg.com/espree/-/espree-3.3.2.tgz#dbf3fadeb4ecb4d4778303e50103b3d36c88b89c" + dependencies: + acorn "^4.0.1" + acorn-jsx "^3.0.0" + +esprima@^2.6.0, esprima@^2.7.1: + version "2.7.3" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" + +esprima@~1.0.2: + version "1.0.4" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-1.0.4.tgz#9f557e08fc3b4d26ece9dd34f8fbf476b62585ad" + +esprima@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-1.1.1.tgz#5b6f1547f4d102e670e140c509be6771d6aeb549" + +espurify@^1.3.0, espurify@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/espurify/-/espurify-1.6.0.tgz#6cb993582d9422bd6f2d4b258aadb14833f394f0" + dependencies: + core-js "^2.0.0" + +esrecurse@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.1.0.tgz#4713b6536adf7f2ac4f327d559e7756bff648220" + dependencies: + estraverse "~4.1.0" + object-assign "^4.0.1" + +estraverse@^1.9.1: + version "1.9.3" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-1.9.3.tgz#af67f2dc922582415950926091a4005d29c9bb44" + +estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" + +estraverse@~1.3.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-1.3.2.tgz#37c2b893ef13d723f276d878d60d8535152a6c42" + +estraverse@~1.5.0: + version "1.5.1" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-1.5.1.tgz#867a3e8e58a9f84618afb6c2ddbcd916b7cbaf71" + +estraverse@~4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.1.1.tgz#f6caca728933a850ef90661d0e17982ba47111a2" + +esutils@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" + +esutils@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-1.0.0.tgz#8151d358e20c8acc7fb745e7472c0025fe496570" + +event-emitter@~0.3.4: + version "0.3.4" + resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.4.tgz#8d63ddfb4cfe1fae3b32ca265c4c720222080bb5" + dependencies: + d "~0.1.1" + es5-ext "~0.10.7" + +events@^1.0.2, events@~1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" + +evp_bytestokey@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.0.tgz#497b66ad9fef65cd7c08a6180824ba1476b66e53" + dependencies: + create-hash "^1.1.1" + +exit-hook@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" + +exit@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + +expand-brackets@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" + dependencies: + is-posix-bracket "^0.1.0" + +expand-range@^1.8.1: + version "1.8.2" + resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" + dependencies: + fill-range "^2.1.0" + +expand-tilde@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-1.2.2.tgz#0b81eba897e5a3d31d1c3d102f8f01441e559449" + dependencies: + os-homedir "^1.0.1" + +explain-error@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/explain-error/-/explain-error-1.0.3.tgz#f4e2b21152120d94db36d93bef03a5c42bfedce9" + +extend@^1.2.1: + version "1.3.0" + resolved "https://registry.yarnpkg.com/extend/-/extend-1.3.0.tgz#d1516fb0ff5624d2ebf9123ea1dac5a1994004f8" + +extend@^3.0.0, extend@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.0.tgz#5a474353b9f3353ddd8176dfd37b91c83a46f1d4" + +extglob@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" + dependencies: + is-extglob "^1.0.0" + +extsprintf@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.0.2.tgz#e1080e0658e300b06294990cc70e1502235fd550" + +falafel@^1.0.0, falafel@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/falafel/-/falafel-1.2.0.tgz#c18d24ef5091174a497f318cd24b026a25cddab4" + dependencies: + acorn "^1.0.3" + foreach "^2.0.5" + isarray "0.0.1" + object-keys "^1.0.6" + +fast-json-parse@^1.0.0, fast-json-parse@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/fast-json-parse/-/fast-json-parse-1.0.2.tgz#3fb1ca12db68a85933612cc3fab4d7060cfff1d7" + +fast-levenshtein@~2.0.4: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + +fast-safe-stringify@^1.0.8, fast-safe-stringify@^1.1.3, fast-safe-stringify@~1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-1.1.3.tgz#f23370808fe5ab243fa1fdee2e9ab3041c8cb884" + +figures@^1.3.5: + version "1.7.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" + dependencies: + escape-string-regexp "^1.0.5" + object-assign "^4.1.0" + +file-entry-cache@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-2.0.0.tgz#c392990c3e684783d838b8c84a45d8a048458361" + dependencies: + flat-cache "^1.2.1" + object-assign "^4.0.1" + +filename-regex@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.0.tgz#996e3e80479b98b9897f15a8a58b3d084e926775" + +fill-range@^2.1.0: + version "2.2.3" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723" + dependencies: + is-number "^2.1.0" + isobject "^2.0.0" + randomatic "^1.1.3" + repeat-element "^1.1.2" + repeat-string "^1.5.2" + +find-root@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.0.0.tgz#962ff211aab25c6520feeeb8d6287f8f6e95807a" + +findup-sync@^0.4.2: + version "0.4.3" + resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-0.4.3.tgz#40043929e7bc60adf0b7f4827c4c6e75a0deca12" + dependencies: + detect-file "^0.1.0" + is-glob "^2.0.1" + micromatch "^2.3.7" + resolve-dir "^0.1.0" + +flagged-respawn@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/flagged-respawn/-/flagged-respawn-0.3.2.tgz#ff191eddcd7088a675b2610fffc976be9b8074b5" + +flat-cache@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.2.2.tgz#fa86714e72c21db88601761ecf2f555d1abc6b96" + dependencies: + circular-json "^0.3.1" + del "^2.0.2" + graceful-fs "^4.1.2" + write "^0.2.1" + +flatstr@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/flatstr/-/flatstr-1.0.4.tgz#b4477b7cb3377f2b63b0ede78824eb5f99ffcd74" + +flatten@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782" + +for-in@^0.1.5: + version "0.1.6" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.6.tgz#c9f96e89bfad18a545af5ec3ed352a1d9e5b4dc8" + +for-own@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.4.tgz#0149b41a39088c7515f51ebe1c1386d45f935072" + dependencies: + for-in "^0.1.5" + +foreach@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" + +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + +form-data@~2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.2.tgz#89c3534008b97eada4cbb157d58f6f5df025eae4" + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.5" + mime-types "^2.1.12" + +from2-string@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/from2-string/-/from2-string-1.1.0.tgz#18282b27d08a267cb3030cd2b8b4b0f212af752a" + dependencies: + from2 "^2.0.3" + +from2@^2.0.3, from2@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" + dependencies: + inherits "^2.0.1" + readable-stream "^2.0.0" + +fs-exists-sync@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz#982d6893af918e72d08dec9e8673ff2b5a8d6add" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + +fsevents@^1.0.0: + version "1.0.17" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.0.17.tgz#8537f3f12272678765b4fd6528c0f1f66f8f4558" + dependencies: + nan "^2.3.0" + node-pre-gyp "^0.6.29" + +fstream-ignore@~1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105" + dependencies: + fstream "^1.0.0" + inherits "2" + minimatch "^3.0.0" + +fstream@^1.0.0, fstream@^1.0.2, fstream@~1.0.10: + version "1.0.10" + resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.10.tgz#604e8a92fe26ffd9f6fae30399d4984e1ab22822" + dependencies: + graceful-fs "^4.1.2" + inherits "~2.0.0" + mkdirp ">=0.5 0" + rimraf "2" + +function-bind@^1.0.2: + version "1.1.0" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.0.tgz#16176714c801798e4e8f2cf7f7529467bb4a5771" + +garnish@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/garnish/-/garnish-5.2.0.tgz#bed43659382e4b198e33c793897be7c701e65577" + dependencies: + chalk "^0.5.1" + minimist "^1.1.0" + pad-left "^2.0.0" + pad-right "^0.2.2" + prettier-bytes "^1.0.3" + pretty-ms "^2.1.0" + right-now "^1.0.0" + split2 "^0.2.1" + stdout-stream "^1.4.0" + url-trim "^1.0.0" + +gauge@~2.7.1: + version "2.7.2" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.2.tgz#15cecc31b02d05345a5d6b0e171cdb3ad2307774" + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + supports-color "^0.2.0" + wide-align "^1.1.0" + +generate-function@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.0.0.tgz#6858fe7c0969b7d4e9093337647ac79f60dfbe74" + +generate-object-property@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0" + dependencies: + is-property "^1.0.0" + +generic-pool@^2.4.2: + version "2.5.0" + resolved "https://registry.yarnpkg.com/generic-pool/-/generic-pool-2.5.0.tgz#3527229cf4bca1fc40853570dd30541b92442cbe" + +get-stdin@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-5.0.1.tgz#122e161591e21ff4c52530305693f20e6393a398" + +getpass@^0.1.1: + version "0.1.6" + resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.6.tgz#283ffd9fc1256840875311c1b60e8c40187110e6" + dependencies: + assert-plus "^1.0.0" + +glob-base@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" + dependencies: + glob-parent "^2.0.0" + is-glob "^2.0.0" + +glob-parent@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" + dependencies: + is-glob "^2.0.0" + +glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.0: + version "7.1.1" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.2" + once "^1.3.0" + path-is-absolute "^1.0.0" + +global-modules@^0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-0.2.3.tgz#ea5a3bed42c6d6ce995a4f8a1269b5dae223828d" + dependencies: + global-prefix "^0.1.4" + is-windows "^0.2.0" + +global-prefix@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-0.1.5.tgz#8d3bc6b8da3ca8112a160d8d496ff0462bfef78f" + dependencies: + homedir-polyfill "^1.0.0" + ini "^1.3.4" + is-windows "^0.2.0" + which "^1.2.12" + +global@^4.3.0, global@~4.3.0: + version "4.3.1" + resolved "https://registry.yarnpkg.com/global/-/global-4.3.1.tgz#5f757908c7cbabce54f386ae440e11e26b7916df" + dependencies: + min-document "^2.19.0" + process "~0.5.1" + +globals@^9.2.0: + version "9.14.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-9.14.0.tgz#8859936af0038741263053b39d0e76ca241e4034" + +globby@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" + dependencies: + array-union "^1.0.1" + arrify "^1.0.0" + glob "^7.0.3" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + +graceful-fs@^4.1.2: + version "4.1.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" + +"graceful-readlink@>= 1.0.0": + version "1.0.1" + resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" + +har-validator@~2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-2.0.6.tgz#cdcbc08188265ad119b6a5a7c8ab70eecfb5d27d" + dependencies: + chalk "^1.1.1" + commander "^2.9.0" + is-my-json-valid "^2.12.4" + pinkie-promise "^2.0.0" + +has-ansi@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-0.1.0.tgz#84f265aae8c0e6a88a12d7022894b7568894c62e" + dependencies: + ansi-regex "^0.2.0" + +has-ansi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + dependencies: + ansi-regex "^2.0.0" + +has-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" + +has-unicode@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + +has@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.1.tgz#8461733f538b0837c9361e39a9ab9e9704dc2f28" + dependencies: + function-bind "^1.0.2" + +hash.js@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.0.3.tgz#1332ff00156c0a0ffdd8236013d07b77a0451573" + dependencies: + inherits "^2.0.1" + +hawk@~3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" + dependencies: + boom "2.x.x" + cryptiles "2.x.x" + hoek "2.x.x" + sntp "1.x.x" + +hoek@2.x.x: + version "2.16.3" + resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" + +hoek@4.x.x: + version "4.1.0" + resolved "https://registry.yarnpkg.com/hoek/-/hoek-4.1.0.tgz#4a4557460f69842ed463aa00628cc26d2683afa7" + +home-or-tmp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.1" + +homedir-polyfill@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz#4c2bbc8a758998feebf5ed68580f76d46768b4bc" + dependencies: + parse-passwd "^1.0.0" + +htmlescape@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/htmlescape/-/htmlescape-1.1.1.tgz#3a03edc2214bca3b66424a3e7959349509cb0351" + +http-methods@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/http-methods/-/http-methods-0.1.0.tgz#29691b6fc58f4f7e81a3605dca82682b068e4430" + dependencies: + body "~0.1.0" + content-types "~0.1.0" + +http-ndjson@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/http-ndjson/-/http-ndjson-3.0.0.tgz#d21654c0b770417275528b900af589283f2d07fb" + dependencies: + end-of-stream "^1.1.0" + xtend "^4.0.0" + +http-signature@~1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" + dependencies: + assert-plus "^0.2.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + +https-browserify@~0.0.0: + version "0.0.1" + resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-0.0.1.tgz#3f91365cabe60b77ed0ebba24b454e3e09d95a82" + +hyperscript-attribute-to-property@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/hyperscript-attribute-to-property/-/hyperscript-attribute-to-property-1.0.0.tgz#825308d49bb8e2957923f731981bcc811cad7aff" + +hyperx@^2.0.2, hyperx@^2.0.3: + version "2.0.5" + resolved "https://registry.yarnpkg.com/hyperx/-/hyperx-2.0.5.tgz#fedef890d7203f36339b243b27d38e3a424225ab" + dependencies: + hyperscript-attribute-to-property "^1.0.0" + +iconv-lite@~0.4.11: + version "0.4.15" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb" + +ieee754@^1.1.4: + version "1.1.8" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4" + +ignore@^3.0.9, ignore@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.2.0.tgz#8d88f03c3002a0ac52114db25d2c673b0bf1e435" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + +indexes-of@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607" + +indexof@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" + +individual@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/individual/-/individual-3.0.0.tgz#e7ca4f85f8957b018734f285750dc22ec2f9862d" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + +inherits@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" + +ini@^1.3.4, ini@~1.3.0: + version "1.3.4" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e" + +inline-source-map@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/inline-source-map/-/inline-source-map-0.5.0.tgz#4a4c5dd8e4fb5e9b3cda60c822dfadcaee66e0af" + dependencies: + source-map "~0.4.0" + +inline-source-map@~0.6.0: + version "0.6.2" + resolved "https://registry.yarnpkg.com/inline-source-map/-/inline-source-map-0.6.2.tgz#f9393471c18a79d1724f863fa38b586370ade2a5" + dependencies: + source-map "~0.5.3" + +inquirer@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-0.12.0.tgz#1ef2bfd63504df0bc75785fff8c2c41df12f077e" + dependencies: + ansi-escapes "^1.1.0" + ansi-regex "^2.0.0" + chalk "^1.0.0" + cli-cursor "^1.0.1" + cli-width "^2.0.0" + figures "^1.3.5" + lodash "^4.3.0" + readline2 "^1.0.1" + run-async "^0.1.0" + rx-lite "^3.1.2" + string-width "^1.0.1" + strip-ansi "^3.0.0" + through "^2.3.6" + +insert-css@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/insert-css/-/insert-css-2.0.0.tgz#eb5d1097b7542f4c79ea3060d3aee07d053880f4" + +insert-module-globals@^7.0.0: + version "7.0.1" + resolved "https://registry.yarnpkg.com/insert-module-globals/-/insert-module-globals-7.0.1.tgz#c03bf4e01cb086d5b5e5ace8ad0afe7889d638c3" + dependencies: + JSONStream "^1.0.3" + combine-source-map "~0.7.1" + concat-stream "~1.5.1" + is-buffer "^1.1.0" + lexical-scope "^1.2.0" + process "~0.11.0" + through2 "^2.0.0" + xtend "^4.0.0" + +interpret@^0.6.5: + version "0.6.6" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-0.6.6.tgz#fecd7a18e7ce5ca6abfb953e1f86213a49f1625b" + +interpret@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.1.tgz#d579fb7f693b858004947af39fa0db49f795602c" + +is-binary-path@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" + dependencies: + binary-extensions "^1.0.0" + +is-buffer@^1.0.2, is-buffer@^1.1.0: + version "1.1.4" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.4.tgz#cfc86ccd5dc5a52fa80489111c6920c457e2d98b" + +is-dotfile@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.2.tgz#2c132383f39199f8edc268ca01b9b007d205cc4d" + +is-equal-shallow@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" + dependencies: + is-primitive "^2.0.0" + +is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + +is-extglob@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" + +is-finite@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + +is-glob@^2.0.0, is-glob@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" + dependencies: + is-extglob "^1.0.0" + +is-my-json-valid@^2.10.0, is-my-json-valid@^2.12.4, is-my-json-valid@^2.15.0: + version "2.15.0" + resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.15.0.tgz#936edda3ca3c211fd98f3b2d3e08da43f7b2915b" + dependencies: + generate-function "^2.0.0" + generate-object-property "^1.1.0" + jsonpointer "^4.0.0" + xtend "^4.0.0" + +is-number@^2.0.2, is-number@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" + dependencies: + kind-of "^3.0.2" + +is-path-cwd@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" + +is-path-in-cwd@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz#6477582b8214d602346094567003be8a9eac04dc" + dependencies: + is-path-inside "^1.0.0" + +is-path-inside@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.0.tgz#fc06e5a1683fbda13de667aff717bbc10a48f37f" + dependencies: + path-is-inside "^1.0.1" + +is-posix-bracket@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" + +is-primitive@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" + +is-property@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" + +is-resolvable@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.0.0.tgz#8df57c61ea2e3c501408d100fb013cf8d6e0cc62" + dependencies: + tryit "^1.0.1" + +is-stream@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + +is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + +is-windows@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-0.2.0.tgz#de1aa6d63ea29dd248737b69f1ff8b8002d2108c" + +isarray@0.0.1, isarray@~0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + +isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + +isexe@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-1.1.2.tgz#36f3e22e60750920f5e7241a476a8c6a42275ad0" + +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + dependencies: + isarray "1.0.0" + +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + +iterators@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/iterators/-/iterators-0.1.0.tgz#d03f666ca4e6130138565997cacea54164203156" + dependencies: + ap "~0.1.0" + +jodid25519@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/jodid25519/-/jodid25519-1.0.2.tgz#06d4912255093419477d425633606e0e90782967" + dependencies: + jsbn "~0.1.0" + +js-base64@^2.1.9: + version "2.1.9" + resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.1.9.tgz#f0e80ae039a4bd654b5f281fc93f04a914a7fcce" + +js-tokens@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-2.0.0.tgz#79903f5563ee778cc1162e6dcf1a0027c97f9cb5" + +js-yaml@^3.5.1: + version "3.7.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.7.0.tgz#5c967ddd837a9bfdca5f2de84253abe8a1c03b80" + dependencies: + argparse "^1.0.7" + esprima "^2.6.0" + +jsbn@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.0.tgz#650987da0dd74f4ebf5a11377a2aa2d273e97dfd" + +json-schema@0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + +json-stable-stringify@^1.0.0, json-stable-stringify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" + dependencies: + jsonify "~0.0.0" + +json-stable-stringify@~0.0.0: + version "0.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-0.0.1.tgz#611c23e814db375527df851193db59dd2af27f45" + dependencies: + jsonify "~0.0.0" + +json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + +jsonify@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" + +jsonparse@^1.2.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.0.tgz#85fc245b1d9259acc6941960b905adf64e7de0e8" + +jsonpointer@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9" + +jsprim@^1.2.2: + version "1.3.1" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.3.1.tgz#2a7256f70412a29ee3670aaca625994c4dcff252" + dependencies: + extsprintf "1.0.2" + json-schema "0.2.3" + verror "1.3.6" + +jsx-ast-utils@^1.3.3: + version "1.3.5" + resolved "https://registry.yarnpkg.com/jsx-ast-utils/-/jsx-ast-utils-1.3.5.tgz#9ba6297198d9f754594d62e59496ffb923778dd4" + dependencies: + acorn-jsx "^3.0.1" + object-assign "^4.1.0" + +kind-of@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.1.0.tgz#475d698a5e49ff5e53d14e3e732429dc8bf4cf47" + dependencies: + is-buffer "^1.0.2" + +knex@^0.12.6: + version "0.12.6" + resolved "https://registry.yarnpkg.com/knex/-/knex-0.12.6.tgz#a255f0ea03af2c2c94687a622c08acc1a9463c0e" + dependencies: + babel-runtime "^6.11.6" + bluebird "^3.4.6" + chalk "^1.0.0" + commander "^2.2.0" + debug "^2.1.3" + generic-pool "^2.4.2" + inherits "~2.0.1" + interpret "^0.6.5" + liftoff "~2.2.0" + lodash "^4.6.0" + minimist "~1.1.0" + mkdirp "^0.5.0" + node-uuid "^1.4.7" + pg-connection-string "^0.1.3" + readable-stream "^1.1.12" + tildify "~1.0.0" + v8flags "^2.0.2" + +labeled-stream-splicer@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/labeled-stream-splicer/-/labeled-stream-splicer-2.0.0.tgz#a52e1d138024c00b86b1c0c91f677918b8ae0a59" + dependencies: + inherits "^2.0.1" + isarray "~0.0.1" + stream-splicer "^2.0.0" + +lazy-cache@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" + +levn@^0.3.0, levn@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + +lexical-scope@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/lexical-scope/-/lexical-scope-1.2.0.tgz#fcea5edc704a4b3a8796cdca419c3a0afaf22df4" + dependencies: + astw "^2.0.0" + +liftoff@~2.2.0: + version "2.2.5" + resolved "https://registry.yarnpkg.com/liftoff/-/liftoff-2.2.5.tgz#998c2876cff484b103e4423b93d356da44734c91" + dependencies: + extend "^3.0.0" + findup-sync "^0.4.2" + flagged-respawn "^0.3.2" + rechoir "^0.6.2" + resolve "^1.1.7" + +localenv@0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/localenv/-/localenv-0.2.2.tgz#c508f29d3485bdc9341d3ead17f61c5abd1b0bab" + dependencies: + commander "2.5.0" + +lodash.memoize@~3.0.3: + version "3.0.4" + resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-3.0.4.tgz#2dcbd2c287cbc0a55cc42328bd0c736150d53e3f" + +lodash@^4.0.0, lodash@^4.3.0, lodash@^4.6.0: + version "4.17.4" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" + +longest@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" + +map-limit@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/map-limit/-/map-limit-0.0.1.tgz#eb7961031c0f0e8d001bf2d56fab685d58822f38" + dependencies: + once "~1.3.0" + +merry@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/merry/-/merry-4.1.0.tgz#a6a6c138770c79c68f8cb75a0cd1ceb97b18bb3c" + dependencies: + boom "^4.2.0" + concat-stream "^1.6.0" + corsify "^2.1.0" + envobj "^1.0.2" + explain-error "^1.0.3" + fast-json-parse "^1.0.2" + fast-safe-stringify "^1.1.3" + from2-string "^1.1.0" + is-my-json-valid "^2.15.0" + is-stream "^1.1.0" + map-limit "0.0.1" + pino "^3.0.5" + pump "^1.0.1" + server-router "^4.0.0" + server-sink "^1.0.0" + xtend "^4.0.1" + +methods@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + +micromatch@^2.1.5, micromatch@^2.3.7: + version "2.3.11" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" + dependencies: + arr-diff "^2.0.0" + array-unique "^0.2.1" + braces "^1.8.2" + expand-brackets "^0.1.4" + extglob "^0.3.1" + filename-regex "^2.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.1" + kind-of "^3.0.2" + normalize-path "^2.0.1" + object.omit "^2.0.0" + parse-glob "^3.0.4" + regex-cache "^0.4.2" + +miller-rabin@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.0.tgz#4a62fb1d42933c05583982f4c716f6fb9e6c6d3d" + dependencies: + bn.js "^4.0.0" + brorand "^1.0.1" + +mime-db@~1.26.0: + version "1.26.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.26.0.tgz#eaffcd0e4fc6935cf8134da246e2e6c35305adff" + +mime-types@^2.1.12, mime-types@~2.1.7: + version "2.1.14" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.14.tgz#f7ef7d97583fcaf3b7d282b6f8b5679dab1e94ee" + dependencies: + mime-db "~1.26.0" + +min-document@^2.19.0: + version "2.19.0" + resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685" + dependencies: + dom-walk "^0.1.0" + +minimalistic-assert@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz#702be2dda6b37f4836bcb3f5db56641b64a1d3d3" + +minimatch@^3.0.0, minimatch@^3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774" + dependencies: + brace-expansion "^1.0.0" + +minimist@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + +minimist@^1.1.0, minimist@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + +minimist@^1.1.1, minimist@~1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.1.3.tgz#3bedfd91a92d39016fcfaa1c681e8faa1a1efda8" + +"mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + dependencies: + minimist "0.0.8" + +module-deps@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/module-deps/-/module-deps-4.0.8.tgz#55fd70623399706c3288bef7a609ff1e8c0ed2bb" + dependencies: + JSONStream "^1.0.3" + browser-resolve "^1.7.0" + cached-path-relative "^1.0.0" + concat-stream "~1.5.0" + defined "^1.0.0" + detective "^4.0.0" + duplexer2 "^0.1.2" + inherits "^2.0.1" + parents "^1.0.0" + readable-stream "^2.0.2" + resolve "^1.1.3" + stream-combiner2 "^1.1.1" + subarg "^1.0.0" + through2 "^2.0.0" + xtend "^4.0.0" + +morphdom@~2.1.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/morphdom/-/morphdom-2.1.2.tgz#e07d0a61cda5cbed43389372d78c5c84d0154b0a" + +ms@0.7.1: + version "0.7.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098" + +ms@0.7.2: + version "0.7.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765" + +multi-stage-sourcemap@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/multi-stage-sourcemap/-/multi-stage-sourcemap-0.2.1.tgz#b09fc8586eaa17f81d575c4ad02e0f7a3f6b1105" + dependencies: + source-map "^0.1.34" + +mute-stream@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0" + +nan@^2.3.0: + version "2.5.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.5.0.tgz#aa8f1e34531d807e9e27755b234b4a6ec0c152a8" + +nanoraf@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/nanoraf/-/nanoraf-2.1.2.tgz#3c9a041582c4c6cd9fb3ececbe5c5b0a81b75565" + dependencies: + global "^4.3.0" + +nanotick@^1.1.2: + version "1.1.4" + resolved "https://registry.yarnpkg.com/nanotick/-/nanotick-1.1.4.tgz#0e8a72309488448409462ab1256ab1fe2783ea17" + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + +node-pre-gyp@^0.6.29: + version "0.6.32" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.32.tgz#fc452b376e7319b3d255f5f34853ef6fd8fe1fd5" + dependencies: + mkdirp "~0.5.1" + nopt "~3.0.6" + npmlog "^4.0.1" + rc "~1.1.6" + request "^2.79.0" + rimraf "~2.5.4" + semver "~5.3.0" + tar "~2.2.1" + tar-pack "~3.3.0" + +node-uuid@^1.4.7: + version "1.4.7" + resolved "https://registry.yarnpkg.com/node-uuid/-/node-uuid-1.4.7.tgz#6da5a17668c4b3dd59623bda11cf7fa4c1f60a6f" + +nopt@~3.0.6: + version "3.0.6" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" + dependencies: + abbrev "1" + +normalize-path@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.0.1.tgz#47886ac1662760d4261b7d979d241709d3ce3f7a" + +npmlog@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.0.2.tgz#d03950e0e78ce1527ba26d2a7592e9348ac3e75f" + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.1" + set-blocking "~2.0.0" + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + +oauth-sign@~0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" + +object-assign@4.0.1, object-assign@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.0.1.tgz#99504456c3598b5cad4fc59c26e8a9bb107fe0bd" + +object-assign@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + +object-inspect@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-0.4.0.tgz#f5157c116c1455b243b06ee97703392c5ad89fec" + +object-keys@^1.0.6: + version "1.0.11" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.11.tgz#c54601778ad560f1142ce0e01bcca8b56d13426d" + +object-keys@~0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-0.4.0.tgz#28a6aae7428dd2c3a92f3d95f21335dd204e0336" + +object.omit@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" + dependencies: + for-own "^0.1.4" + is-extendable "^0.1.1" + +on-load@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/on-load/-/on-load-3.2.0.tgz#dd3145d3a5c2faa5666920d1df674b69f0c2f66f" + dependencies: + global "^4.3.0" + +once@^1.3.0, once@^1.3.1, once@^1.3.3, once@~1.3.0, once@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/once/-/once-1.3.3.tgz#b2e261557ce4c314ec8304f3fa82663e4297ca20" + dependencies: + wrappy "1" + +onetime@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" + +opn@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/opn/-/opn-4.0.2.tgz#7abc22e644dff63b0a96d5ab7f2790c0f01abc95" + dependencies: + object-assign "^4.0.1" + pinkie-promise "^2.0.0" + +optionator@^0.8.1, optionator@^0.8.2: + version "0.8.2" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.4" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + wordwrap "~1.0.0" + +os-browserify@~0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.1.2.tgz#49ca0293e0b19590a5f5de10c7f265a617d8fe54" + +os-homedir@^1.0.0, os-homedir@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + +os-tmpdir@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + +outpipe@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/outpipe/-/outpipe-1.1.1.tgz#50cf8616365e87e031e29a5ec9339a3da4725fa2" + dependencies: + shell-quote "^1.4.2" + +pad-left@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/pad-left/-/pad-left-2.1.0.tgz#16e6a3b2d44a8e138cb0838cc7cb403a4fc9e994" + dependencies: + repeat-string "^1.5.4" + +pad-right@^0.2.2: + version "0.2.2" + resolved "https://registry.yarnpkg.com/pad-right/-/pad-right-0.2.2.tgz#6fbc924045d244f2a2a244503060d3bfc6009774" + dependencies: + repeat-string "^1.5.2" + +pako@~0.2.0: + version "0.2.9" + resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75" + +parents@^1.0.0, parents@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parents/-/parents-1.0.1.tgz#fedd4d2bf193a77745fe71e371d73c3307d9c751" + dependencies: + path-platform "~0.11.15" + +parse-asn1@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.0.0.tgz#35060f6d5015d37628c770f4e091a0b5a278bc23" + dependencies: + asn1.js "^4.0.0" + browserify-aes "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.0" + pbkdf2 "^3.0.3" + +parse-glob@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" + dependencies: + glob-base "^0.3.0" + is-dotfile "^1.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.0" + +parse-ms@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/parse-ms/-/parse-ms-1.0.1.tgz#56346d4749d78f23430ca0c713850aef91aa361d" + +parse-passwd@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" + +path-browserify@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.0.tgz#a0b870729aae214005b7d5032ec2cbbb0fb4451a" + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + +path-is-inside@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + +path-platform@~0.11.15: + version "0.11.15" + resolved "https://registry.yarnpkg.com/path-platform/-/path-platform-0.11.15.tgz#e864217f74c36850f0852b78dc7bf7d4a5721bf2" + +pathname-match@^1.1.3: + version "1.2.0" + resolved "https://registry.yarnpkg.com/pathname-match/-/pathname-match-1.2.0.tgz#77cb8e3db1e41e4771c4942a9e4fecb610cc2d19" + +pbkdf2@^3.0.3: + version "3.0.9" + resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.9.tgz#f2c4b25a600058b3c3773c086c37dbbee1ffe693" + dependencies: + create-hmac "^1.1.2" + +pg-connection-string@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-0.1.3.tgz#da1847b20940e42ee1492beaf65d49d91b245df7" + +pify@^2.0.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + +pinkie-promise@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + dependencies: + pinkie "^2.0.0" + +pinkie@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + +pino@^3.0.5: + version "3.1.1" + resolved "https://registry.yarnpkg.com/pino/-/pino-3.1.1.tgz#092ac6f427cd4a770090c44cc9edbe5feb74cd40" + dependencies: + chalk "^1.1.1" + fast-json-parse "^1.0.0" + fast-safe-stringify "^1.1.3" + flatstr "^1.0.4" + once "^1.3.3" + quick-format-unescaped "^1.0.0" + split2 "^2.0.1" + +pkg-config@^1.0.1, pkg-config@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/pkg-config/-/pkg-config-1.1.1.tgz#557ef22d73da3c8837107766c52eadabde298fe4" + dependencies: + debug-log "^1.0.0" + find-root "^1.0.0" + xtend "^4.0.1" + +plur@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/plur/-/plur-1.0.0.tgz#db85c6814f5e5e5a3b49efc28d604fec62975156" + +pluralize@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-1.2.1.tgz#d1a21483fd22bb41e58a12fa3421823140897c45" + +postcss-prefix@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-prefix/-/postcss-prefix-2.0.0.tgz#2139e8fba64ed71b93e3a8b1d4c5976e2a949c6f" + dependencies: + postcss "^5.0.8" + postcss-selector-parser "^1.3.0" + +postcss-selector-parser@^1.3.0: + version "1.3.3" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-1.3.3.tgz#d2ee19df7a64f8ef21c1a71c86f7d4835c88c281" + dependencies: + flatten "^1.0.2" + indexes-of "^1.0.1" + uniq "^1.0.1" + +postcss@^5.0.10, postcss@^5.0.8: + version "5.2.10" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-5.2.10.tgz#b58b64e04f66f838b7bc7cb41f7dac168568a945" + dependencies: + chalk "^1.1.3" + js-base64 "^2.1.9" + source-map "^0.5.6" + supports-color "^3.1.2" + +prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + +preserve@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" + +prettier-bytes@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/prettier-bytes/-/prettier-bytes-1.0.3.tgz#932b31c23efddb36fc66a82dcef362af3122982f" + +pretty-ms@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/pretty-ms/-/pretty-ms-2.1.0.tgz#4257c256df3fb0b451d6affaab021884126981dc" + dependencies: + is-finite "^1.0.1" + parse-ms "^1.0.0" + plur "^1.0.0" + +process-nextick-args@~1.0.6: + version "1.0.7" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" + +process@~0.11.0: + version "0.11.9" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.9.tgz#7bd5ad21aa6253e7da8682264f1e11d11c0318c1" + +process@~0.5.1: + version "0.5.2" + resolved "https://registry.yarnpkg.com/process/-/process-0.5.2.tgz#1638d8a8e34c2f440a91db95ab9aeb677fc185cf" + +progress@^1.1.8: + version "1.1.8" + resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be" + +public-encrypt@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.0.tgz#39f699f3a46560dd5ebacbca693caf7c65c18cc6" + dependencies: + bn.js "^4.1.0" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + parse-asn1 "^5.0.0" + randombytes "^2.0.1" + +pump@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pump/-/pump-1.0.2.tgz#3b3ee6512f94f0e575538c17995f9f16990a5d51" + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + +punycode@1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" + +punycode@^1.3.2, punycode@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + +qs@~6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.3.0.tgz#f403b264f23bc01228c74131b407f18d5ea5d442" + +querystring-es3@~0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" + +querystring@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" + +quick-format-unescaped@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/quick-format-unescaped/-/quick-format-unescaped-1.0.0.tgz#d4779757a39d04e31a7f033b9e941ba1c5bde069" + dependencies: + fast-safe-stringify "^1.0.8" + +quote-stream@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/quote-stream/-/quote-stream-0.0.0.tgz#cde29e94c409b16e19dc7098b89b6658f9721d3b" + dependencies: + minimist "0.0.8" + through2 "~0.4.1" + +randomatic@^1.1.3: + version "1.1.6" + resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.6.tgz#110dcabff397e9dcff7c0789ccc0a49adf1ec5bb" + dependencies: + is-number "^2.0.2" + kind-of "^3.0.2" + +randombytes@^2.0.0, randombytes@^2.0.1: + version "2.0.3" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.3.tgz#674c99760901c3c4112771a31e521dc349cc09ec" + +rc@~1.1.6: + version "1.1.6" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.1.6.tgz#43651b76b6ae53b5c802f1151fa3fc3b059969c9" + dependencies: + deep-extend "~0.4.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~1.0.4" + +read-only-stream@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/read-only-stream/-/read-only-stream-2.0.0.tgz#2724fd6a8113d73764ac288d4386270c1dbf17f0" + dependencies: + readable-stream "^2.0.2" + +"readable-stream@>=1.0.33-1 <1.1.0-0", readable-stream@~1.0.17, readable-stream@~1.0.26, readable-stream@~1.0.27-1: + version "1.0.34" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + +"readable-stream@>=1.1.13-1 <1.2.0-0", readable-stream@^1.1.12, readable-stream@~1.1.9: + version "1.1.14" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + +readable-stream@^2.0.0, "readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.3, readable-stream@^2.0.5, readable-stream@^2.1.0, readable-stream@^2.1.5, readable-stream@^2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.2.tgz#a9e6fec3c7dda85f8bb1b3ba7028604556fc825e" + dependencies: + buffer-shims "^1.0.0" + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "~1.0.0" + process-nextick-args "~1.0.6" + string_decoder "~0.10.x" + util-deprecate "~1.0.1" + +readable-stream@~2.0.0: + version "2.0.6" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "~1.0.0" + process-nextick-args "~1.0.6" + string_decoder "~0.10.x" + util-deprecate "~1.0.1" + +readable-stream@~2.1.4: + version "2.1.5" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.1.5.tgz#66fa8b720e1438b364681f2ad1a63c618448c9d0" + dependencies: + buffer-shims "^1.0.0" + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "~1.0.0" + process-nextick-args "~1.0.6" + string_decoder "~0.10.x" + util-deprecate "~1.0.1" + +readdirp@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78" + dependencies: + graceful-fs "^4.1.2" + minimatch "^3.0.2" + readable-stream "^2.0.2" + set-immediate-shim "^1.0.1" + +readline2@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/readline2/-/readline2-1.0.1.tgz#41059608ffc154757b715d9989d199ffbf372e35" + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + mute-stream "0.0.5" + +rechoir@^0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" + dependencies: + resolve "^1.1.6" + +regenerator-runtime@^0.10.0: + version "0.10.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.1.tgz#257f41961ce44558b18f7814af48c17559f9faeb" + +regex-cache@^0.4.2: + version "0.4.3" + resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.3.tgz#9b1a6c35d4d0dfcef5711ae651e8e9d3d7114145" + dependencies: + is-equal-shallow "^0.1.3" + is-primitive "^2.0.0" + +repeat-element@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" + +repeat-string@^1.5.2, repeat-string@^1.5.4: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + +request@^2.79.0: + version "2.79.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.79.0.tgz#4dfe5bf6be8b8cdc37fcf93e04b65577722710de" + dependencies: + aws-sign2 "~0.6.0" + aws4 "^1.2.1" + caseless "~0.11.0" + combined-stream "~1.0.5" + extend "~3.0.0" + forever-agent "~0.6.1" + form-data "~2.1.1" + har-validator "~2.0.6" + hawk "~3.1.3" + http-signature "~1.1.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.7" + oauth-sign "~0.8.1" + qs "~6.3.0" + stringstream "~0.0.4" + tough-cookie "~2.3.0" + tunnel-agent "~0.4.1" + uuid "^3.0.0" + +require-uncached@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" + dependencies: + caller-path "^0.1.0" + resolve-from "^1.0.0" + +resolve-dir@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-0.1.1.tgz#b219259a5602fac5c5c496ad894a6e8cc430261e" + dependencies: + expand-tilde "^1.2.2" + global-modules "^0.2.3" + +resolve-from@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" + +resolve@1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" + +resolve@^1.1.3, resolve@^1.1.4, resolve@^1.1.6, resolve@^1.1.7: + version "1.2.0" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.2.0.tgz#9589c3f2f6149d1417a40becc1663db6ec6bc26c" + +restore-cursor@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" + dependencies: + exit-hook "^1.0.0" + onetime "^1.0.0" + +right-align@^0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" + dependencies: + align-text "^0.1.1" + +right-now@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/right-now/-/right-now-1.0.0.tgz#6e89609deebd7dcdaf8daecc9aea39cf585a0918" + +rimraf@2, rimraf@^2.2.8, rimraf@~2.5.1, rimraf@~2.5.4: + version "2.5.4" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.5.4.tgz#96800093cbf1a0c86bd95b4625467535c29dfa04" + dependencies: + glob "^7.0.5" + +ripemd160@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-1.0.1.tgz#93a4bbd4942bc574b69a8fa57c71de10ecca7d6e" + +run-async@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-0.1.0.tgz#c8ad4a5e110661e402a7d21b530e009f25f8e389" + dependencies: + once "^1.3.0" + +run-parallel@^1.1.2: + version "1.1.6" + resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.6.tgz#29003c9a2163e01e2d2dfc90575f2c6c1d61a039" + +rx-lite@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102" + +semver@~5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" + +server-router@^4.0.0: + version "4.0.2" + resolved "https://registry.yarnpkg.com/server-router/-/server-router-4.0.2.tgz#2a1354d3654ad1a3254d41499f41dcb232fd0507" + dependencies: + methods "^1.1.1" + pathname-match "^1.1.3" + urlencode "^1.1.0" + wayfarer "^6.1.4" + +server-sink@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/server-sink/-/server-sink-1.0.0.tgz#b3f6e3098c99799dfeadb71cbbab14d599f7a4b8" + dependencies: + http-ndjson "^3.0.0" + size-stream "^1.0.1" + +set-blocking@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + +set-immediate-shim@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" + +sha.js@^2.3.6, sha.js@~2.4.4: + version "2.4.8" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.8.tgz#37068c2c476b6baf402d14a49c67f597921f634f" + dependencies: + inherits "^2.0.1" + +shallow-copy@~0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/shallow-copy/-/shallow-copy-0.0.1.tgz#415f42702d73d810330292cc5ee86eae1a11a170" + +shasum@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/shasum/-/shasum-1.0.2.tgz#e7012310d8f417f4deb5712150e5678b87ae565f" + dependencies: + json-stable-stringify "~0.0.0" + sha.js "~2.4.4" + +sheet-router@^4.0.1: + version "4.2.0" + resolved "https://registry.yarnpkg.com/sheet-router/-/sheet-router-4.2.0.tgz#f16091a4abdba3faa2eaf1fdc97e2f963e5794b7" + dependencies: + global "^4.3.0" + wayfarer "^6.2.1" + xtend "^4.0.1" + +sheetify@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/sheetify/-/sheetify-6.0.1.tgz#b11851aca2f0a149cbc97c7833bd599988d42da5" + dependencies: + falafel "^1.2.0" + insert-css "^2.0.0" + map-limit "0.0.1" + postcss "^5.0.10" + postcss-prefix "^2.0.0" + resolve "^1.1.7" + stack-trace "0.0.9" + static-eval "^1.1.0" + style-resolve "^1.0.0" + through2 "^2.0.0" + xtend "^4.0.1" + +shell-quote@^1.4.2, shell-quote@^1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.6.1.tgz#f4781949cce402697127430ea3b3c5476f481767" + dependencies: + array-filter "~0.0.0" + array-map "~0.0.0" + array-reduce "~0.0.0" + jsonify "~0.0.0" + +shelljs@^0.7.5: + version "0.7.6" + resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.7.6.tgz#379cccfb56b91c8601e4793356eb5382924de9ad" + dependencies: + glob "^7.0.0" + interpret "^1.0.0" + rechoir "^0.6.2" + +signal-exit@^3.0.0: + version "3.0.2" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" + +size-stream@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/size-stream/-/size-stream-1.0.1.tgz#6f31429547c951ea5dddbb385325ea7ac132a6d9" + dependencies: + readable-stream "^2.0.3" + +slice-ansi@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" + +sntp@1.x.x: + version "1.0.9" + resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" + dependencies: + hoek "2.x.x" + +"source-map@>= 0.1.2", source-map@^0.5.6, source-map@~0.5.1, source-map@~0.5.3: + version "0.5.6" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" + +source-map@^0.1.34, source-map@~0.1.33: + version "0.1.43" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.1.43.tgz#c24bc146ca517c1471f5dacbe2571b2b7f9e3346" + dependencies: + amdefine ">=0.0.4" + +source-map@~0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.2.0.tgz#dab73fbcfc2ba819b4de03bd6f6eaa48164b3f9d" + dependencies: + amdefine ">=0.0.4" + +source-map@~0.4.0, source-map@~0.4.2: + version "0.4.4" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" + dependencies: + amdefine ">=0.0.4" + +split2@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/split2/-/split2-0.2.1.tgz#02ddac9adc03ec0bb78c1282ec079ca6e85ae900" + dependencies: + through2 "~0.6.1" + +split2@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/split2/-/split2-2.1.1.tgz#7a1f551e176a90ecd3345f7246a0cfe175ef4fd0" + dependencies: + through2 "^2.0.2" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + +sshpk@^1.7.0: + version "1.10.2" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.10.2.tgz#d5a804ce22695515638e798dbe23273de070a5fa" + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + dashdash "^1.12.0" + getpass "^0.1.1" + optionalDependencies: + bcrypt-pbkdf "^1.0.0" + ecc-jsbn "~0.1.1" + jodid25519 "^1.0.0" + jsbn "~0.1.0" + tweetnacl "~0.14.0" + +stack-trace@0.0.9: + version "0.0.9" + resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.9.tgz#a8f6eaeca90674c333e7c43953f275b451510695" + +standard-engine@~5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/standard-engine/-/standard-engine-5.2.0.tgz#400660ae5acce8afd4db60ff2214a9190ad790a3" + dependencies: + deglob "^2.0.0" + find-root "^1.0.0" + get-stdin "^5.0.1" + home-or-tmp "^2.0.0" + minimist "^1.1.0" + pkg-config "^1.0.1" + +standard@^8.6.0: + version "8.6.0" + resolved "https://registry.yarnpkg.com/standard/-/standard-8.6.0.tgz#635132be7bfb567c2921005f30f9e350e4752aad" + dependencies: + eslint "~3.10.2" + eslint-config-standard "6.2.1" + eslint-config-standard-jsx "3.2.0" + eslint-plugin-promise "~3.4.0" + eslint-plugin-react "~6.7.1" + eslint-plugin-standard "~2.0.1" + standard-engine "~5.2.0" + +static-eval@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/static-eval/-/static-eval-1.1.1.tgz#ca8130210354cf13d9a722bc7e923778457bb192" + dependencies: + escodegen "^1.8.1" + +static-eval@~0.2.0: + version "0.2.4" + resolved "https://registry.yarnpkg.com/static-eval/-/static-eval-0.2.4.tgz#b7d34d838937b969f9641ca07d48f8ede263ea7b" + dependencies: + escodegen "~0.0.24" + +static-module@^1.3.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/static-module/-/static-module-1.3.1.tgz#79071d340e4419e4ab5ce87976a9eb67250c8493" + dependencies: + concat-stream "~1.4.5" + duplexer2 "~0.0.2" + escodegen "~1.3.2" + falafel "^1.0.0" + has "^1.0.0" + object-inspect "~0.4.0" + quote-stream "~0.0.0" + readable-stream "~1.0.27-1" + shallow-copy "~0.0.1" + static-eval "~0.2.0" + through2 "~0.4.1" + +stdout-stream@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/stdout-stream/-/stdout-stream-1.4.0.tgz#a2c7c8587e54d9427ea9edb3ac3f2cd522df378b" + dependencies: + readable-stream "^2.0.1" + +stream-browserify@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db" + dependencies: + inherits "~2.0.1" + readable-stream "^2.0.2" + +stream-combiner2@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/stream-combiner2/-/stream-combiner2-1.1.1.tgz#fb4d8a1420ea362764e21ad4780397bebcb41cbe" + dependencies: + duplexer2 "~0.1.0" + readable-stream "^2.0.2" + +stream-http@^2.0.0: + version "2.6.2" + resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.6.2.tgz#bdfe40d2ee9262eb6bf2255bb3ad0ec0cdd6526d" + dependencies: + builtin-status-codes "^3.0.0" + inherits "^2.0.1" + readable-stream "^2.1.0" + to-arraybuffer "^1.0.0" + xtend "^4.0.0" + +stream-splicer@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/stream-splicer/-/stream-splicer-2.0.0.tgz#1b63be438a133e4b671cc1935197600175910d83" + dependencies: + inherits "^2.0.1" + readable-stream "^2.0.2" + +string-width@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +string-width@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.0.0.tgz#635c5436cc72a6e0c387ceca278d4e2eec52687e" + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^3.0.0" + +string_decoder@~0.10.0, string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + +stringstream@~0.0.4: + version "0.0.5" + resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" + +strip-ansi@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-0.3.0.tgz#25f48ea22ca79187f3174a4db8759347bb126220" + dependencies: + ansi-regex "^0.2.1" + +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + dependencies: + ansi-regex "^2.0.0" + +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + +strip-json-comments@~1.0.1, strip-json-comments@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-1.0.4.tgz#1e15fbcac97d3ee99bf2d73b4c656b082bbafb91" + +style-resolve@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/style-resolve/-/style-resolve-1.0.1.tgz#2d2067c944d5fb7f553ca75c4e7947df43796fae" + dependencies: + resolve "^1.1.7" + xtend "^4.0.1" + +subarg@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/subarg/-/subarg-1.0.0.tgz#f62cf17581e996b48fc965699f54c06ae268b8d2" + dependencies: + minimist "^1.1.0" + +supports-color@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-0.2.0.tgz#d92de2694eb3f67323973d7ae3d8b55b4c22190a" + +supports-color@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + +supports-color@^3.1.2: + version "3.2.3" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6" + dependencies: + has-flag "^1.0.0" + +syntax-error@^1.1.1: + version "1.1.6" + resolved "https://registry.yarnpkg.com/syntax-error/-/syntax-error-1.1.6.tgz#b4549706d386cc1c1dc7c2423f18579b6cade710" + dependencies: + acorn "^2.7.0" + +table@^3.7.8: + version "3.8.3" + resolved "https://registry.yarnpkg.com/table/-/table-3.8.3.tgz#2bbc542f0fda9861a755d3947fefd8b3f513855f" + dependencies: + ajv "^4.7.0" + ajv-keywords "^1.0.0" + chalk "^1.1.1" + lodash "^4.0.0" + slice-ansi "0.0.4" + string-width "^2.0.0" + +tar-pack@~3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.3.0.tgz#30931816418f55afc4d21775afdd6720cee45dae" + dependencies: + debug "~2.2.0" + fstream "~1.0.10" + fstream-ignore "~1.0.5" + once "~1.3.3" + readable-stream "~2.1.4" + rimraf "~2.5.1" + tar "~2.2.1" + uid-number "~0.0.6" + +tar@~2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" + dependencies: + block-stream "*" + fstream "^1.0.2" + inherits "2" + +text-table@~0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + +through2@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/through2/-/through2-1.1.1.tgz#0847cbc4449f3405574dbdccd9bb841b83ac3545" + dependencies: + readable-stream ">=1.1.13-1 <1.2.0-0" + xtend ">=4.0.0 <4.1.0-0" + +through2@^2.0.0, through2@^2.0.1, through2@^2.0.2: + version "2.0.3" + resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.3.tgz#0004569b37c7c74ba39c43f3ced78d1ad94140be" + dependencies: + readable-stream "^2.1.5" + xtend "~4.0.1" + +through2@~0.4.1: + version "0.4.2" + resolved "https://registry.yarnpkg.com/through2/-/through2-0.4.2.tgz#dbf5866031151ec8352bb6c4db64a2292a840b9b" + dependencies: + readable-stream "~1.0.17" + xtend "~2.1.1" + +through2@~0.6.1: + version "0.6.5" + resolved "https://registry.yarnpkg.com/through2/-/through2-0.6.5.tgz#41ab9c67b29d57209071410e1d7a7a968cd3ad48" + dependencies: + readable-stream ">=1.0.33-1 <1.1.0-0" + xtend ">=4.0.0 <4.1.0-0" + +"through@>=2.2.7 <3", through@^2.3.6, through@^2.3.7, through@~2.3.4: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + +tildify@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/tildify/-/tildify-1.0.0.tgz#2a021db5e8fbde0a8f8b4df37adaa8fb1d39d7dd" + dependencies: + user-home "^1.0.0" + +timers-browserify@^1.0.1: + version "1.4.2" + resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-1.4.2.tgz#c9c58b575be8407375cb5e2462dacee74359f41d" + dependencies: + process "~0.11.0" + +to-arraybuffer@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" + +tough-cookie@~2.3.0: + version "2.3.2" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.2.tgz#f081f76e4c85720e6c37a5faced737150d84072a" + dependencies: + punycode "^1.4.1" + +tryit@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/tryit/-/tryit-1.0.3.tgz#393be730a9446fd1ead6da59a014308f36c289cb" + +tty-browserify@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" + +tunnel-agent@~0.4.1: + version "0.4.3" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb" + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + +type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + dependencies: + prelude-ls "~1.1.2" + +typedarray@^0.0.6, typedarray@~0.0.5: + version "0.0.6" + resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + +uglify-js@2.x.x: + version "2.7.5" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.7.5.tgz#4612c0c7baaee2ba7c487de4904ae122079f2ca8" + dependencies: + async "~0.2.6" + source-map "~0.5.1" + uglify-to-browserify "~1.0.0" + yargs "~3.10.0" + +uglify-to-browserify@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" + +uglifyify@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/uglifyify/-/uglifyify-3.0.4.tgz#487e080a5a7798880e68e90def9b06681fb13bd2" + dependencies: + convert-source-map "~1.1.0" + extend "^1.2.1" + minimatch "^3.0.2" + through "~2.3.4" + uglify-js "2.x.x" + +uid-number@~0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" + +umd@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/umd/-/umd-3.0.1.tgz#8ae556e11011f63c2596708a8837259f01b3d60e" + +unassert@^1.3.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/unassert/-/unassert-1.5.1.tgz#cbc88ec387417c5a5e4c02d3cd07be98bd75ff76" + dependencies: + acorn "^4.0.0" + call-matcher "^1.0.1" + deep-equal "^1.0.0" + espurify "^1.3.0" + estraverse "^4.1.0" + esutils "^2.0.2" + object-assign "^4.1.0" + +unassertify@^2.0.3: + version "2.0.4" + resolved "https://registry.yarnpkg.com/unassertify/-/unassertify-2.0.4.tgz#b3ca2ba5f29b4836e35a6dd77e5b20f6dbbf8e52" + dependencies: + acorn "^4.0.0" + convert-source-map "^1.1.1" + escodegen "^1.6.1" + multi-stage-sourcemap "^0.2.1" + through "^2.3.7" + unassert "^1.3.1" + +uniq@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" + +url-trim@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/url-trim/-/url-trim-1.0.0.tgz#40057e2f164b88e5daca7269da47e6d1dd837adc" + +url@~0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" + dependencies: + punycode "1.3.2" + querystring "0.2.0" + +urlencode@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/urlencode/-/urlencode-1.1.0.tgz#1f2ba26f013c85f0133f7a3ad6ff2730adf7cbb7" + dependencies: + iconv-lite "~0.4.11" + +user-home@^1.0.0, user-home@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/user-home/-/user-home-1.1.1.tgz#2b5be23a32b63a7c9deb8d0f28d485724a3df190" + +user-home@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/user-home/-/user-home-2.0.0.tgz#9c70bfd8169bc1dcbf48604e0f04b8b49cde9e9f" + dependencies: + os-homedir "^1.0.0" + +util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + +util@0.10.3, util@~0.10.1: + version "0.10.3" + resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" + dependencies: + inherits "2.0.1" + +uuid@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.1.tgz#6544bba2dfda8c1cf17e629a3a305e2bb1fee6c1" + +v8flags@^2.0.2: + version "2.0.11" + resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-2.0.11.tgz#bca8f30f0d6d60612cc2c00641e6962d42ae6881" + dependencies: + user-home "^1.1.1" + +verror@1.3.6: + version "1.3.6" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.3.6.tgz#cff5df12946d297d2baaefaa2689e25be01c005c" + dependencies: + extsprintf "1.0.2" + +vm-browserify@~0.0.1: + version "0.0.4" + resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-0.0.4.tgz#5d7ea45bbef9e4a6ff65f95438e0a87c357d5a73" + dependencies: + indexof "0.0.1" + +watchify-request@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/watchify-request/-/watchify-request-2.1.0.tgz#ddd5d96abfc54d43952b0e543d6feea775e7fff3" + dependencies: + bl "^0.9.3" + events "^1.0.2" + +watchify@^3.7.0: + version "3.8.0" + resolved "https://registry.yarnpkg.com/watchify/-/watchify-3.8.0.tgz#a5cacc3517ca1e637d7b0af745375cafb597d6bb" + dependencies: + anymatch "^1.3.0" + browserify "^13.0.0" + chokidar "^1.0.0" + defined "^1.0.0" + outpipe "^1.1.0" + through2 "^2.0.0" + xtend "^4.0.0" + +wayfarer@^6.1.4, wayfarer@^6.2.1: + version "6.3.0" + resolved "https://registry.yarnpkg.com/wayfarer/-/wayfarer-6.3.0.tgz#47bf3cca0191d429b2819d46ef69145dd6178b85" + dependencies: + xtend "^4.0.1" + +which@^1.2.12: + version "1.2.12" + resolved "https://registry.yarnpkg.com/which/-/which-1.2.12.tgz#de67b5e450269f194909ef23ece4ebe416fa1192" + dependencies: + isexe "^1.1.1" + +wide-align@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.0.tgz#40edde802a71fea1f070da3e62dcda2e7add96ad" + dependencies: + string-width "^1.0.1" + +window-size@0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" + +wordwrap@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" + +wordwrap@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + +write@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" + dependencies: + mkdirp "^0.5.1" + +"xtend@>=4.0.0 <4.1.0-0", xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" + +xtend@~2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-2.1.2.tgz#6efecc2a4dad8e6962c4901b337ce7ba87b5d28b" + dependencies: + object-keys "~0.4.0" + +yargs@~3.10.0: + version "3.10.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1" + dependencies: + camelcase "^1.0.2" + cliui "^2.1.0" + decamelize "^1.0.0" + window-size "0.1.0" + +yo-yo@^1.2.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/yo-yo/-/yo-yo-1.3.2.tgz#73b253cc8e24f058ed5c765a3a234c4ab0112393" + dependencies: + bel "^4.0.0" + morphdom "~2.1.0" + +yo-yoify@^3.5.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/yo-yoify/-/yo-yoify-3.5.0.tgz#b8469e94affdb87dbb61adfb24a8e0ce30c59351" + dependencies: + falafel "^1.2.0" + hyperx "^2.0.3" + on-load "^3.2.0" + through2 "^2.0.1" From 8b07ca14b1f5dc19b918fb5521fda9011ffe9453 Mon Sep 17 00:00:00 2001 From: Frederic Gingras Date: Mon, 16 Jan 2017 18:51:12 -0500 Subject: [PATCH 05/27] database: create migrations --- README.md | 7 +- knexfile.js | 13 +++ migrations/20170116181958_add_taxes_table.js | 15 ++++ ...0116182027_add_expense_categories_table.js | 10 +++ .../20170116182035_add_employees_table.js | 11 +++ .../20170116182042_add_expenses_table.js | 15 ++++ package.json | 3 +- server.js | 6 +- yarn.lock | 87 ++++++++++++++++++- 9 files changed, 161 insertions(+), 6 deletions(-) create mode 100644 knexfile.js create mode 100644 migrations/20170116181958_add_taxes_table.js create mode 100644 migrations/20170116182027_add_expense_categories_table.js create mode 100644 migrations/20170116182035_add_employees_table.js create mode 100644 migrations/20170116182042_add_expenses_table.js diff --git a/README.md b/README.md index 8016e6740..3e3b9c93c 100644 --- a/README.md +++ b/README.md @@ -59,7 +59,7 @@ actually run these. ## Production TODO Overview of what's discussed in this section and how some subject where simplified for the -exercise but could be expanded upon. +exercise but could be expanded upon. Note lack of Nginx but obvious need for it. ### Deploying changes @@ -92,3 +92,8 @@ case but can be automated with Ansible/Tower | Chef/Server | Puppet/Server. ## Footnotes ### What I am proud of + +### Questions + +- Is the only line in the example data, taxed in NY, using 7.5% not 8.875% an error? +- It's not clear as to whether we where supposed to assume the expenses and expense categories from a single file where linked to a specific client of just global. diff --git a/knexfile.js b/knexfile.js new file mode 100644 index 000000000..7bd5d4683 --- /dev/null +++ b/knexfile.js @@ -0,0 +1,13 @@ +module.exports = { + client: "postgresql", + connection: process.env.DATABASE_URL || { + database: "wave_challenge", + user: "wave_challenge", + password: "wave_challenge", + }, + pool: {min: 2, max: 10}, + migrations: { + tableName: "migrations", + directory: "./migrations", + }, +}; diff --git a/migrations/20170116181958_add_taxes_table.js b/migrations/20170116181958_add_taxes_table.js new file mode 100644 index 000000000..b46a93fbf --- /dev/null +++ b/migrations/20170116181958_add_taxes_table.js @@ -0,0 +1,15 @@ +exports.up = function (knex, Promise) { + return knex.schema.createTable('taxes', function (t) { + t.string('id', 26).notNullable().primary() + t.text('name').notNullable() + t.integer('year').notNullable() + t.decimal('percentage', 7, 5).notNullable() // e.g. 99.99999 + + t.index(['name', 'year']) + t.unique(['name', 'year']) + }); +}; + +exports.down = function (knex, Promise) { + return knex.schema.dropTable('taxes'); +}; diff --git a/migrations/20170116182027_add_expense_categories_table.js b/migrations/20170116182027_add_expense_categories_table.js new file mode 100644 index 000000000..fa73e349c --- /dev/null +++ b/migrations/20170116182027_add_expense_categories_table.js @@ -0,0 +1,10 @@ +exports.up = function (knex, Promise) { + return knex.schema.createTable('expense_categories', function (t) { + t.string('id', 26).notNullable().primary() + t.text('name').notNullable() + }); +}; + +exports.down = function (knex, Promise) { + return knex.schema.dropTable('expense_categories'); +}; diff --git a/migrations/20170116182035_add_employees_table.js b/migrations/20170116182035_add_employees_table.js new file mode 100644 index 000000000..fa9958d77 --- /dev/null +++ b/migrations/20170116182035_add_employees_table.js @@ -0,0 +1,11 @@ +exports.up = function (knex, Promise) { + return knex.schema.createTable('employees', function (t) { + t.string('id', 26).notNullable().primary() + t.text('name').notNullable() + t.text('address').notNullable() + }); +}; + +exports.down = function (knex, Promise) { + return knex.schema.dropTable('employees'); +}; diff --git a/migrations/20170116182042_add_expenses_table.js b/migrations/20170116182042_add_expenses_table.js new file mode 100644 index 000000000..b624739c4 --- /dev/null +++ b/migrations/20170116182042_add_expenses_table.js @@ -0,0 +1,15 @@ +exports.up = function (knex, Promise) { + return knex.schema.createTable('expenses', function (t) { + t.string('id', 26).notNullable().primary() + t.timestamp('date').notNullable().index() + t.string('category_id', 26).notNullable().references('id').inTable('expense_categories') + t.string('employee_id', 26).notNullable().references('id').inTable('employees') + t.string('tax_id', 26).notNullable().references('id').inTable('taxes') + t.text('description').notNullable() + t.integer('amount').notNullable() + }); +}; + +exports.down = function (knex, Promise) { + return knex.schema.dropTable('expenses'); +}; diff --git a/package.json b/package.json index b842d06b5..3b7a6ae2b 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,8 @@ "bankai": "^5.2.1", "choo": "^4.0.3", "knex": "^0.12.6", - "merry": "^4.1.0" + "merry": "^4.1.0", + "pg": "^6.1.2" }, "devDependencies": { "standard": "^8.6.0" diff --git a/server.js b/server.js index 8fe99bfd9..8b36c3914 100644 --- a/server.js +++ b/server.js @@ -5,6 +5,7 @@ var merry = require('merry') var bankai = require('bankai') var env = merry.env({PORT: 8000}) +var production = env.NODE_ENV === 'production' var app = merry() app.router([ @@ -15,7 +16,7 @@ app.router([ ['/tachyons.min.css', serveStaticFile('tachyons.min.css', 'text/css')], // API - ['/upload', {get: handleUpload}], + ['/upload', {post: handleUpload}], // Error and Not found handlers ['/404', serveStaticFile('not-found.html', 'text/html')] @@ -31,7 +32,8 @@ function handleUpload (req, res, ctx, done) { function serveClientJs (req, res, ctx, done) { var clientPath = path.join(__dirname, 'client', 'app.js') - done(null, bankai(clientPath).js(req, res)) + var assets = bankai(clientPath, {optimize: production, cssDisabled: true}) + done(null, assets.js(req, res)) } function serveStaticFile (filename, contentType) { diff --git a/yarn.lock b/yarn.lock index e0987647b..a1f1a8c79 100644 --- a/yarn.lock +++ b/yarn.lock @@ -89,6 +89,10 @@ ap@~0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/ap/-/ap-0.1.0.tgz#d8a3f26615379398a1b53ca6cc1a666a0fbfe150" +ap@~0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/ap/-/ap-0.2.0.tgz#ae0942600b29912f0d2b14ec60c45e8f330b6110" + aproba@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.0.4.tgz#2713680775e7614c8ba186c065d4e2e52d1072c0" @@ -485,6 +489,10 @@ buffer-shims@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/buffer-shims/-/buffer-shims-1.0.0.tgz#9978ce317388c649ad8793028c3477ef044a8b51" +buffer-writer@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/buffer-writer/-/buffer-writer-1.0.1.tgz#22a936901e3029afcd7547eb4487ceb697a3bf08" + buffer-xor@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" @@ -1474,6 +1482,10 @@ generate-object-property@^1.1.0: dependencies: is-property "^1.0.0" +generic-pool@2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/generic-pool/-/generic-pool-2.4.2.tgz#886bc5bf0beb7db96e81bcbba078818de5a62683" + generic-pool@^2.4.2: version "2.5.0" resolved "https://registry.yarnpkg.com/generic-pool/-/generic-pool-2.5.0.tgz#3527229cf4bca1fc40853570dd30541b92442cbe" @@ -2272,6 +2284,10 @@ object-assign@4.0.1, object-assign@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.0.1.tgz#99504456c3598b5cad4fc59c26e8a9bb107fe0bd" +object-assign@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.0.tgz#7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0" + object-assign@^4.1.0: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" @@ -2347,6 +2363,10 @@ outpipe@^1.1.0: dependencies: shell-quote "^1.4.2" +packet-reader@0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/packet-reader/-/packet-reader-0.2.0.tgz#819df4d010b82d5ea5671f8a1a3acf039bcd7700" + pad-left@^2.0.0: version "2.1.0" resolved "https://registry.yarnpkg.com/pad-left/-/pad-left-2.1.0.tgz#16e6a3b2d44a8e138cb0838cc7cb403a4fc9e994" @@ -2422,10 +2442,45 @@ pbkdf2@^3.0.3: dependencies: create-hmac "^1.1.2" -pg-connection-string@^0.1.3: +pg-connection-string@0.1.3, pg-connection-string@^0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-0.1.3.tgz#da1847b20940e42ee1492beaf65d49d91b245df7" +pg-pool@1.*: + version "1.6.0" + resolved "https://registry.yarnpkg.com/pg-pool/-/pg-pool-1.6.0.tgz#2e300199927b6d7db6be71e2e3435dddddf07b41" + dependencies: + generic-pool "2.4.2" + object-assign "4.1.0" + +pg-types@1.*: + version "1.11.0" + resolved "https://registry.yarnpkg.com/pg-types/-/pg-types-1.11.0.tgz#aae91a82d952b633bb88d006350a166daaf6ea90" + dependencies: + ap "~0.2.0" + postgres-array "~1.0.0" + postgres-bytea "~1.0.0" + postgres-date "~1.0.0" + postgres-interval "~1.0.0" + +pg@^6.1.2: + version "6.1.2" + resolved "https://registry.yarnpkg.com/pg/-/pg-6.1.2.tgz#2c896a7434502e2b938c100fc085b4e974a186db" + dependencies: + buffer-writer "1.0.1" + packet-reader "0.2.0" + pg-connection-string "0.1.3" + pg-pool "1.*" + pg-types "1.*" + pgpass "1.x" + semver "4.3.2" + +pgpass@1.x: + version "1.0.1" + resolved "https://registry.yarnpkg.com/pgpass/-/pgpass-1.0.1.tgz#0de8b5bef993295d90a7e17d976f568dcd25d49f" + dependencies: + split "^1.0.0" + pify@^2.0.0: version "2.3.0" resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" @@ -2492,6 +2547,24 @@ postcss@^5.0.10, postcss@^5.0.8: source-map "^0.5.6" supports-color "^3.1.2" +postgres-array@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/postgres-array/-/postgres-array-1.0.2.tgz#8e0b32eb03bf77a5c0a7851e0441c169a256a238" + +postgres-bytea@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/postgres-bytea/-/postgres-bytea-1.0.0.tgz#027b533c0aa890e26d172d47cf9ccecc521acd35" + +postgres-date@~1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/postgres-date/-/postgres-date-1.0.3.tgz#e2d89702efdb258ff9d9cee0fe91bd06975257a8" + +postgres-interval@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/postgres-interval/-/postgres-interval-1.0.2.tgz#7261438d862b412921c6fdb7617668424b73a6ed" + dependencies: + xtend "^4.0.0" + prelude-ls@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" @@ -2791,6 +2864,10 @@ rx-lite@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102" +semver@4.3.2: + version "4.3.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.2.tgz#c7a07158a80bedd052355b770d82d6640f803be7" + semver@~5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" @@ -2931,6 +3008,12 @@ split2@^2.0.1: dependencies: through2 "^2.0.2" +split@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/split/-/split-1.0.0.tgz#c4395ce683abcd254bc28fe1dabb6e5c27dcffae" + dependencies: + through "2" + sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" @@ -3182,7 +3265,7 @@ through2@~0.6.1: readable-stream ">=1.0.33-1 <1.1.0-0" xtend ">=4.0.0 <4.1.0-0" -"through@>=2.2.7 <3", through@^2.3.6, through@^2.3.7, through@~2.3.4: +through@2, "through@>=2.2.7 <3", through@^2.3.6, through@^2.3.7, through@~2.3.4: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" From e42194c2cc05ec0ba696ff84ba659218b8cfa978 Mon Sep 17 00:00:00 2001 From: Frederic Gingras Date: Mon, 16 Jan 2017 21:59:38 -0500 Subject: [PATCH 06/27] client: design container and 1st page content --- client/app.css | 5 ----- client/app.js | 42 +++++++++++++++++++++++++++++++++++++----- client/index.html | 5 ++++- server.js | 1 - 4 files changed, 41 insertions(+), 12 deletions(-) delete mode 100644 client/app.css diff --git a/client/app.css b/client/app.css deleted file mode 100644 index 53e4161c0..000000000 --- a/client/app.css +++ /dev/null @@ -1,5 +0,0 @@ -html, body { - font-family: sans-serif; - margin: 0; - background: #fafafa; -} diff --git a/client/app.js b/client/app.js index 1ac458996..f033d5f06 100644 --- a/client/app.js +++ b/client/app.js @@ -13,10 +13,40 @@ app.model({ function mainView (state, prev, send) { return html` -
-

Title: ${state.title}

- -
+
+
+ Wave +

+ Data Import +

+
+
+
+ +

+ Step 1: Select data file +

+ +

+ The first step in the import process is selecting a CSV file containing expense data. + Once it's uploaded and saved in the database you'll be able to visualize your per-month + expense report. +

+ +

+ The file needs to include header line and include the following fields: + date, category, employee name, employee address, expense description, pre-tax amount, tax name, tax amount +

+ + + + + +
+
+
` function update (e) { @@ -27,4 +57,6 @@ function mainView (state, prev, send) { app.router(['/', mainView]) var tree = app.start() -document.body.appendChild(tree) +var appEl = document.getElementById('app'); +appEl.innerHTML = ''; +appEl.appendChild(tree) diff --git a/client/index.html b/client/index.html index 5d71e7ab6..1bfc9aaac 100644 --- a/client/index.html +++ b/client/index.html @@ -8,9 +8,12 @@ Data Import | Wave - + +
+
Loading...
+
diff --git a/server.js b/server.js index 8b36c3914..40b2b218b 100644 --- a/server.js +++ b/server.js @@ -12,7 +12,6 @@ app.router([ // Static assets ['/', serveStaticFile('index.html', 'text/html')], ['/app.js', serveClientJs], - ['/app.css', serveStaticFile('app.css', 'text/css')], ['/tachyons.min.css', serveStaticFile('tachyons.min.css', 'text/css')], // API From 237a2f7e5e797eca0508ed1428ab648c42102fd0 Mon Sep 17 00:00:00 2001 From: Frederic Gingras Date: Tue, 17 Jan 2017 18:42:45 -0500 Subject: [PATCH 07/27] meta: add some folder structure in clien & server --- client/app.js | 25 ++++++++++++++++------ client/elements/layout.js | 0 client/index.html | 2 +- client/models/app.js | 0 client/pages/import.js | 0 client/pages/report.js | 0 server/helpers/csv.js | 0 server/library/container.js | 0 server/models/employee.js | 0 server/models/expense.js | 0 server/models/expense_category.js | 0 server/models/tax.js | 0 server/repositories/employees.js | 0 server/repositories/expense_categories.js | 0 server/repositories/expenses.js | 0 server/repositories/taxes.js | 0 server/services/import.js | 0 server/services/report.js | 0 support/screenshot1.png | Bin 0 -> 58530 bytes 19 files changed, 19 insertions(+), 8 deletions(-) create mode 100644 client/elements/layout.js create mode 100644 client/models/app.js create mode 100644 client/pages/import.js create mode 100644 client/pages/report.js create mode 100644 server/helpers/csv.js create mode 100644 server/library/container.js create mode 100644 server/models/employee.js create mode 100644 server/models/expense.js create mode 100644 server/models/expense_category.js create mode 100644 server/models/tax.js create mode 100644 server/repositories/employees.js create mode 100644 server/repositories/expense_categories.js create mode 100644 server/repositories/expenses.js create mode 100644 server/repositories/taxes.js create mode 100644 server/services/import.js create mode 100644 server/services/report.js create mode 100644 support/screenshot1.png diff --git a/client/app.js b/client/app.js index f033d5f06..34ba55ca5 100644 --- a/client/app.js +++ b/client/app.js @@ -14,14 +14,25 @@ app.model({ function mainView (state, prev, send) { return html`
-
- Wave -

- Data Import -

+ +
+
+

+ Data Import +

+
-
-
+
+

Step 1: Select data file diff --git a/client/elements/layout.js b/client/elements/layout.js new file mode 100644 index 000000000..e69de29bb diff --git a/client/index.html b/client/index.html index 1bfc9aaac..e37fe123d 100644 --- a/client/index.html +++ b/client/index.html @@ -12,7 +12,7 @@
-
Loading...
+
Loading...
diff --git a/client/models/app.js b/client/models/app.js new file mode 100644 index 000000000..e69de29bb diff --git a/client/pages/import.js b/client/pages/import.js new file mode 100644 index 000000000..e69de29bb diff --git a/client/pages/report.js b/client/pages/report.js new file mode 100644 index 000000000..e69de29bb diff --git a/server/helpers/csv.js b/server/helpers/csv.js new file mode 100644 index 000000000..e69de29bb diff --git a/server/library/container.js b/server/library/container.js new file mode 100644 index 000000000..e69de29bb diff --git a/server/models/employee.js b/server/models/employee.js new file mode 100644 index 000000000..e69de29bb diff --git a/server/models/expense.js b/server/models/expense.js new file mode 100644 index 000000000..e69de29bb diff --git a/server/models/expense_category.js b/server/models/expense_category.js new file mode 100644 index 000000000..e69de29bb diff --git a/server/models/tax.js b/server/models/tax.js new file mode 100644 index 000000000..e69de29bb diff --git a/server/repositories/employees.js b/server/repositories/employees.js new file mode 100644 index 000000000..e69de29bb diff --git a/server/repositories/expense_categories.js b/server/repositories/expense_categories.js new file mode 100644 index 000000000..e69de29bb diff --git a/server/repositories/expenses.js b/server/repositories/expenses.js new file mode 100644 index 000000000..e69de29bb diff --git a/server/repositories/taxes.js b/server/repositories/taxes.js new file mode 100644 index 000000000..e69de29bb diff --git a/server/services/import.js b/server/services/import.js new file mode 100644 index 000000000..e69de29bb diff --git a/server/services/report.js b/server/services/report.js new file mode 100644 index 000000000..e69de29bb diff --git a/support/screenshot1.png b/support/screenshot1.png new file mode 100644 index 0000000000000000000000000000000000000000..5c1c61f8fcfe3d96c134c21c5d8b47ad520d5ace GIT binary patch literal 58530 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%0ANP865N&7q)H&un`vW>tz0`p${g$8)R$=xF zry*nyT8l-U3xp#c(EF*xVrT$IN96828L~Z#T*~*1R8&xY%N)WY`(vpt8keZTL98rT zGc)+bb=De z(w}Xq@gHCp*ZVFA9qczE==Km1pb=vQ3tG}$3`4lbbDkD&r#g-509p_7nRpmB#w$qe zmekJ<$V%O3NEBrJRRHq$ZouLne9kijElPkHV^CicDzGucx!tPQij!M+Xn29W)~jkz z7dqjADh*W0E2gZ4`r1!&!O;(i_WV`$erU@u^BbYcLX2YLt(u-c+x5RHK(1D1$)0}% zO(`uVd_I(n$I$~;l=#5@+I!E;L44~ysbs<9Mfn2ZJ3g`}Wrv$Z1=Ml;I^qqv!O986 zKzpY{UtRxn=jpy{j9pU&0}})2Typp{=d3HTh3VH1zXnR? zCI*~fT7EN{pgio$O{BmnwjT~hCQe7A!N!))+Rp(xc^yi8cH<3yybIkKnd}EDJK&8c zR+^Ehwl~3h}E5rj|J)9qe7# z7hc(#j-?Pl-kil==>N0X}?x}B3CntAq(8Y*dN!xdd*|NAVN)A`uL!5rLF zqKdal1dDY&UksjwJ&5`;o$Sj5Kb6z{v~$E91ab=5?9cwuD?xU)+`t6%;RtS0imbU* zQAr$Sj273dTec8S{YliOoWN}S`DRlK>-R+&t_(_}J}MW@KQC~S@{ z6C#(lI32I}>IT{@t7f4^?mX0XE#TL2y^{l%Yw+m+Z}4PgFpEEq`9m9b!CTD~x$R## zu{pk>K{|vCEjgstafXDBdIUZnpp#J9l>C<3GTn@^H-EJDvoQdM-~!r~7)M;-q`{># z`CEyjwWlW>CkmNNB~2hLXn9z-J8!=X>unNRAK(7?dUznB z_Ml?Up5b(XP7=i(e7&{bLrzrN!anlnoYM=JE0AfWPoey&tChe6_jp;uk4}*@pIu!> zPfpdp#ESIk0J`JBP7B`gDNerHv3xuruP?6qW-?|0nZ>_#-u5?80~hj|%m@+wB6PtUWH^2z(+q(2F20e>r z(7B`;DPvWobenmh2|gcsu_B`Djy`s~n;FM`tPo*ggR{yoVl?Rw6yL)emN#ROCZ|*Q zY!O~m)!O#7r8r_|Tat{ry!)ER3jEiq3Xo^>gn*h|4?k}xtqdbYYQL}t7CWh}Uc^gG zwAf$n;{Cd{tSVvgle}%RoEELn?qT zF~pqFlkxQs`vkLu5>>^7?-~R3hn28KtB&f|W%R=P7a%a@rG95_JQ?)^6ni?a*X-h* zuvO(Vkt_ED0aKae%6QxD9!j!+by0N1Al+eJ0UiYtaw=uP;KZ=@jJIS& z*S~o$D6EEA5}p{b+H_L$fg6MbRUoj1f$jbweTxB@XZc{rOm2}BbEZQPZ4V7D?yukj zuEx5!M}aJxjw25}EAeU0hTz%@i{$rCo;8E4N>h%OSpe?T?bnT|sRQOZj5FndMmB2$ zmTmJ@p=Z_eB1z`z2BTUp&W0lo zuZP(6IFjzff$FRgW#Kjt%isC~6IClwEW*o%ZsR+q%F?2)^lXUJPIluJNjY@AW3mV8 z&)mGJZg&dR0K&M`Tmw#}y8Ey=y5xQMPDNf>N)QpPNyW6n3r9Ue&UNn1Ur3}8Z3#(f z@g938#or!Y|Ik2^u!HM1oH}?2Td8wd~56ME_7VZ-qXSBQBtU&z$(71FTAyXwc zEY~HrFKIwg@RH?R8tct|+WjYz15xru<%Lg`>|AkALQhHYu+?0IvZ!yYMm>iZSfE;( z2$q$sA2$J-;SA_sJVf^-T3DHgOP+KumGd;EhWc+9*4tCYzEt)8loegqxH(!*Z6(3&IrB6}=v7jO570>GxkxQuwJ7 zi*C{tYi17|V>lF)h?Os=0v>sKS}yc{$?g64_1r5pk(0_z-(|bJlV>!==*)=WQFnYU zHR|Z=gDCp##Fsj!Lm;n7jLfSjE?S9xN|wLRWOXKQ3FKvfs#CRULS;m7kl!5KepXBY zc`LhK<&)V+zffj|Ag4{U5`DXL)IsLXuC~Qb9^w_TtH5VvZQQ;52U+7YamS0jmbA3N z>OwWrZ#NB=9T!STMR9fEg94_#cM2_2nR?S=@Q(THeA)rg6ct<#MXeCvqy%A-FIRAA z2`LEF6+Y$E+^%zCJ&ogF&!!2orRD7_I_K!EqQI#KKYCOG7rODfN72#c6f%3DdVZYu zXv$>g_Kr&8Uc&k&z^IoOjBTLy*-eu5)k}zLShnFK-WxV*(FcmS3|0>x{L$bNYp-ve zDck_8O1VS_9W;Ihda`>LE47AdI5%-FTx3&od6YROMG6>D*m*vc8X6p$_Fzh&y!*4x?tRsos zqH`s(28b74{`=brp*>D#?>Yb}EMKu)=wW^Qk@)N&NL}ifG}IzD6|1w(ZYpx0^nbopSKA{ zJbQk6rS>UXv)^jC&8gZdm%5FbmCnQL9|gPF6wTiTx%j?Lh<8}!pdEU!jBan!%$DD^x2~gdz>!N*j8tC-tOgf4W~C}p zXY`BJ8G(4FSXm^-iwx_m8 zFNzCpS3pc&L_|u6QBBd$l%J!pF6woTg~$ST^hXXglP|XFiT3?9 zFq-9GKb&kdFS5q(>mnvYyL`4UC33v1fxS;POWh}bg$OOQ>vxJGV7uE*}`qTY8oq6lIxSJXLF1K<(qCg=*QakD*?dE_7-( z*V#?v&fT=k4BUSs{C*0{`uAd>-CqoRrdylDfg(p@yE_x>;NZaK45cPJ>6zj_j(%|+ z?B)*;QD7Dy-t{3nT~1!MVR2Bdnk9z-FmKDsS0*{B4UTnu)hUpmSyljYBOC` z4->9AU%^JcxuL^k_tnb#(@u1G!4^1Ist$-z?}~x#{w|r0H{d!wN(fLgObtLhGq3nf z=@gZ495|?2Y;T0*pyoJ!Az)x0yB9sOc5y>0K2k zf#=20Uu27a2m;#minlWTCn(8?V4T{G7PCF1K4Ef17+z4oPeP(bcRhbp<*|-iG5`3^ znfq{#Y>z=VYJoy)`+JCNNpaIIn#WHW!7}A~wPb8a+WveopWz@*ylNzjd` zKo#n3Vzk@y0~Qju6OgsI?a?9PfQ=#23E%Ucd7)~oheGetMu6;mNssP|A*~HbsWbAB zdnKbrEXeRviVS$t(qrd{rd;(hs_h7DFTbuhzq9ig;pnT{IWD?HtHGc@r0Y_)x$~29 zy&>dgI6Q1*9{C{`5-bm+)!ZM=tD5D`yccSE6KP zg0~M?<3;;%zblVV4C?#QiYr(D?eQ&fLtPKB;NXk)K7H+y3iT4GgH9H-7`YnkpUd=N z%VetLK(ak$d-Lmb?_qLNhB?TgOD3$B%e7ddHmFM!J0!+$PvjhJx<*3Y{tFCxkyUSr((f= zg?b|62YI5?PjtGr_qTUbG6g;j-SrZ2LZY=^q2kN+0SaZbEMe6{a8S2pLz`JntUc~2 zf=C)&xRp!i#{^m3Tpd-xRg4zP!b=^ZanLamozjuH+e^qQA z;+Kt)@KOn=Z~fM~Pv)@uAs!5_R)Z?&Tjf550uMh_5be$JEhs&wYjQ#!wcfwMzdpwN zzc}{(tmk@8i-4vT9KOoUn^N(MG3gv6MQ2dElKg`QkJWg)=jJr}R+*|sS@Bg3*e55J zId^M%ahxka@r#|-2?9iqE!a^LNC{OZP15RY3#T1bc^2*b+s#227 z-cA>np80D`qUM!VbQFr6_bZGaNKx>b)ePz(9ThZ}*GEaWB?Sl2#TL=b-@ub;`L<`> zKi^_Xg~@ar*k7_}R@SeSo_NzD%%R70YoD9iB*1e(x>he2zdF?l9y5EVykoq`D*i~j z!2teGs>uEe=$!4xmyZ!F8cR=K^=ZPgKjZsI6SO`18`}P7+1dYqjCOp1r^|%O{SDG( zE}3tW;!E2a)Mqb4{r&}}&Jy3fzLM3xL0Hq8S05AMXNZRjDVq$zI=MLepEs*%i2UEp7*{}!PB zx5R%x#6Nrc4`ASbg7zP|ZdR**B|U!JaO7OUp2G{D8)v^s0lbS6%S^uNz1~4W4{|4h z_MY68J8i8A-Iv_vKJQdZBEA>u?(WV`_IJxPzr*}1Qq}gW<%oMu=Zvoja^B(VU|z*b z?oX0hXT1E-L;U$BVZh(Ly1HuH6GN5ZB(T|!!fG*oS&&2mFMctGcD{OzZ$O}%*7@!i zTDD-EX9-IpGR|xqh~Kr39K3975obaFTEkNe*7Ydw1USIYl%em*L*81E$DrIwPW?Wjm+^Z zXi2fl5E;rlXV1l#q`I!-;r|Zu{sy^E_s(v=R$vn7exlrO0UELgA*@roP>H>}32^7e zwR^K{A!5&y<{;GZPKnu`a-&*rm);sKx#F)kqr>J!mU?G#rE&;STwr3<-AnreLNX#H z@@Tf?mqwN_V=LISrBBnUcfhLmlx4aYtRJb`wX@CM-zq%rKRQW0E2$< zTa;{6&;)p^*)E6j+HG?3bmnwRf%HPjm8zRc-6cxo^T|?sP0+maF5ShoS+@QDmR`X2 zbK(6U&6!KLAgVIZhj*tB&ucLt{dA-_EATY-uHNo^`P#%A%l6U>06k#e8TqYV)2pne zUNw8SLSmxDU|;y9y%Kk!{k9&&^L|*6*Yq?uz!1V_aH_6|s+TTXefjhU=34tqe0B4*QkJG}|MUiTg=T%Fa z^k}~3!d$UB$ci&9s>Fpu$H=c}(rK#LM>bF%RKLocM1(XaX|o1Z1jq*%Ym}~Eu$VP@ znoBR#m7&IcU`}RX6vm}_4f<+Jww25^S?2X^*QP&+A=R+OW>`U!<9$yW2y?=^u)ePOl`-*(dZT-}le4Ka;DF~Els7{ zXYisD&YRiIoYbG_XQ*A-vw=x{%k)Gm2xLN%2}rqxGF>6%%3(?F{`?Sp(qLI{*4jpr zs)TrWOF@uNlY8e0}|@v z#XQIpZ{@AA04~Dz>&4tW))s2@x;AkPJ~n>GG>U$(sRGxQi!3Z06=6;}?` z%Wp?36u(KG&h&9`@X(5#`Ajq^;j;8oOZl!8#ifOdN)K9;>>;90WKB?$Gl5n$kCgZq zGG<&P!%Bn&v>{bkj3p`Kc=W6Im6lArm)bg+-9g`_T2j-PBxuSpkt3aV{bX&9=#P1= z?^TKmH2IQ0pIH}7akE(1J2@NRhkGne4y{twZ#G4_bu&dw%yXqvroaUb_?;$4fxVV` zGV!XJnN5N&#@}x1$|bbUz+|53{9dQKD(a+eq@T+cH!m2pj#exF(j;MmI5vl5+zzgI z@MV=jE1aTP7ljf~$TUH))KKu!n2zw=k-3AcxlS-bxu$TXyk)0w2G|Ugeikg*N!bVX z`W8F7#QWn-KmVcaSr|7-$qqg>_I1mFnw-X|D-KZ*{_d?zrCFk-H2 ze7}3ejpd2cbd6Q|;1(jU!W{7jn{vHlro0A(8N+F40C^W!-Y8ja9B<%K&kE2xY&i)$ zs~Bc`s=}P85{N63nXOh^(}T=I(F2q;m(DAO?iIHEP^cVVT)Y^{F0Nky0^7{dm?@G0W zNeY+?vS6{H+i~so$)r!lK9o3QG%$`>qzFRZI)vs?KT*}>Me_bi9 zX{mpBoA*_7bH^^B`TYT|B;+=@j;30B7lU0N^7EWtFnaRwY=6eJb3f z!Wj6f(^c>Aa0B(M%wQ-WTc^|bO#T+4Vb{RqL``2Da!Dkj*H_NFTY+`xLn-ODR_mQl zY#f<8Z3<4I?EV~RuY09aa@(t`<)m&!N8K!ph#5ma4UKTp7oP=y%di}eqS#Ydh`R$} z_O|N%rt{z4eK)6%z^Ker^>2Nxf6jj0#8g&qgn5{!eJ}T$y#p4k`T!s7C$>+s%pjtf zGa-txu^40PWQj`*^=S+f71UsNPeWP3c$>7WYErsXc+A3MKzBtq)F;d2!OAVf*?3Yo z;1rLwNkAvKl7=eI728FO0)$OZgd6S2ZA(*n?UJlsZCCWK>47S>+f-^M5bQw4V6zCH z8m#QRvq~%8>%ixoPu_!iDaUfwx%4cPCuX2)b1vJUq4r;0a8==63s9Ht3*g4N%df7h zkJBtX$CI`V7auVC{Z`3j5A8SVjoDo)eEv#z;z3X7m#OJ+KGEX$h71fb$IBMGv|s91 z^=ys$_ziyt2y-4Uv4SY6iu6*AGv~)oDl#$AAgsgd9A%Lb1K8E~w%pJHqSG#wvR66N zoKq3A%?df3^+e2G;hzhrWiyG-5x+U8QUQ=2X|<9M%?1FCf@C6&XBs38ZL#*LmfV%v zt=LJg2=zbi5Mfj}(cnqRpXA>g046nRJ=+(i4N@9ZART71w)-CjTu!cfx7H@O@b+lt z?uX!nem4=ntx)uYB014La^f)Z$S>q^o?uZ#(Ij3;_*Kfn(`J``l97~*J4zY8NOfp9 ztcdi4IB`O4)y~Zage6hl#78<2Cc~c%CZ@>&Vu{I)_15=Hle)p%@&2q+tukRPn5cU+ zeIusg=y^MExKc97@YF(SZ%?K%4R}Uuq!l zYpGR!jNe>IL4%@ln8R*TOV$f81gz_ks;Ac|&$Gaq{Fee5329mjcrsyAFuUa;R`$wS z@n0OZaIb0rpi~H}^ti#lf17hd5bPX9hO76A3!-|J(gL}lhEjC2JQQ#;4$n*}z_6#7 z${X_5+1`naP5bO94#7AFsBy)n{*0yP4iagtuGC<-GwJ=MHE=M}H}LfISv-f#M2tbg zN9q~f#6}&=)fShKHYwCy)Kx|_;Ccm^CR${U_ki#~TnC@!)X5?Ni(I{T1N zTsz8H=f9=v@xwBKjG`AFE!u5bmCXH)KExRleU{aI>>TN8#4~i$MyOFaWqWK{-E)cM zST8|=S>OzLDJk(|%P02bq@{qw(IwD~_k$X{Wwd|ShZv&Bzdm;wrhI%1T42zKcoA(D z$JJ#=2L`K*yqhI21(^B%9HYfl8O|6YS4=0Xcp!7{7WPQ zG;6}6>GdiBPQ#pUU+xCstm!GQcWz)YRusFol#6_`#uh9*!SeLZm2AQ@rczdfp%o%a z+`|%c+B3PFP7ImOYz|ppqUnZs_17)QNKmQ31BR9aDkcb84D}k^Jddvr?@|0u$|Cl zUa|OX+XQkBQ%ID6H4m_8%DZYUs{WKiBmDu=?9WUr>t~pY$n1#O-KC8Nwg6^;CUapx zfF3H|v`n(!Pzy$1Ij@msMK8GBh~oS@(QE(%JS6I^%&}qC;;F|vbq}q*pa0DpF~`nP zj2A}Fpw_%g&6rG`O1urnBZ*FF%t`);`HP%7Xow+Pb)DU%=cRh4h`gVN3JgtIY3mZ8 zB1lo@u2et`H3Ijof>V6*3ZbpW?Hx?fL#&zjYYqZ2>Se0u!y8}0bVSkG?lvs2lQ^B5 z!ia}8-Fi@aa{x2lg!^>>FZm78!xvJI)`#Tbj?^}(f{#=%8z=HxAR~C)-HAo|ZQq54 z3ug!#jUJQrpr4${PD~!ltH1&;ucb1f-#3Ak<>|-eQJf1m0t|9VaM=O5qiFF>2`d5A<`uA|;xDJ@ zK(FEVlYiFr>!K2kIAG2|4oG(f^hhK#3%2C;`}$1~(;(a!XBKjz|eNs zG6_h5IKKZh*mKO&IBNPW49;2W4JQerjs#atA6~Lpsc9exv9>eQ?mXQ598*(e!^0Y0 zJgKBoQrf;hGj^JJs$Du+rYwX2!BjeZGf4tZ!|Tc+zpAU5$kT+ZoL@q0mjnUj z0p|Pke{nuJAZhi6A}YdN)queb>f4+tMR1v^qQd_C{OaRvpPl;1*H%sYg|KN9tlzq=E}rdb?&K^X-5o7jk-CR*!j>5qsd^(63Lf<=V>%;O0tXnF2wN zva_QeZjc1xHCRKFpU@UQpV#p-a}tU4iL^+2c8T9}IJ|(d`o6!FpKrZCylxZzwt_bK z1~+6)&&i>uBECmtaT^~Z;t6;^@o$Lge}FLY#Ezd9KOpyie!20sJF-9BuVkg?X}@WW z2P^-+{pXNgL(-hWrv5 zH(;wP+c(tT{{j5ZIsPZ08h)A`*CX?nclzy$q8F~gTazb^ql>l;2@RvJFP7dqGK)N+ zNvDa7{mCj@lhBYbwOFw==xB*2;z^1YFRBvUm_^(r1!?XpDMp4tOj)d-&VLKAZVI@< z#4y9Fb2R~k)WWV;QW0xQS;b+GN2&$^}a~0e*d3lJ|-%^{I z*$NjvFr&kI|IEUd&FnX;hze=xyuDd)R$EAo*O_*}Qg%-V4)PO8<~@CRd%(jyhIkb! z=XZDC>^O!FK)pPDuc=r|rHh~Lg1uxDx$s-Jx7CvH;yP;!UBG&4ziw`R<>{kvyU))g|Z&q6E z!`hhKgRW-nXAkAq5+b3B=XJ${FS4w^IWZC619$Y`w*R_xQSb)0YX~ zIG9X*8tKf{MOVN0Gj^!!A-Nysa}eKR{%mSnQCA14l;ifQ5N|n!gQzcFtS-j-t8LsA zUO17j7)hvbc*0qr=i~eK512-JeodfBTAqFtq2w`g_-lyfVuYc6`JfwkHdKZ}X2Nqa z``%DJR{$-~z)_y?BBwj*6pLvR8BJBDQ8wa#C=k{%*L5hKJ#zRSPbFnx{2cFDJ$c7-scjt@nw)NO(PSP&Tn$=Thj%l$rOs-zm_ zvE>P~)U+^oraS}>_Y}a@AYSLnl^pIrNyY)&& zw&(qh%JPcHB)?;B;nwg@^zRyhV-(JFyi;=uaB zaTP)-(m*R>(ua26uX19FWB8Mm1N(!*pelcwKF~#`tW0?xBxR_MNJPi1GAwvJvNnm_ zSN^eiN+QwmYg|ZP6ccSzSMhO?;-z2z38hXrXNkYtQ$E+>IVE!2*;7pJ+1df{VzX-; zIA;Vr3Dj5%+&%r5J~|b5SUWwUXB#dXAO@Nou*ou-H1E+{h(+AAwGF89<{wG& z_BT?cshi5K9}yA`p6nl`ra+kl;SEJG&-E)j5N2uYTpy6rx?CJWg9#nH$I|RjnAYqtEA4LSQDAI^mvMzXGGW z<@biIXRnT@z%6uP?JbNu?hLs4``J{90Aax64_^0kp5~|!k--1@UZK57?ca`6CZ2A6;lY*s{GQI7~5cFZeBfj#g z{Fv&&`^R@f(DG4N<Giyv09>+T`&q9F;@+k_dDkLVWF&rE<&b|B8;X8L^Mz?ipWFkq+K;g9<1bM5z19iHi)XKQpoet`NOvHhXxjm=~d_WO;M8EDm9 z`K5nL^&O+w2*-C8lQ!WV@dvxd2g5sA5;arw_|yltkXW|8A1cplWtWVgxeMNj?g4Bb3Bx*ddk z7KEQcCVm{rN`F2EO$H~}rE`uN_QZO8cf?z2*sFJ=hH(5=!1&yXm>D^4^Kx@-XY#l| zbv@Yz=^K1z*;GGL8?xVjb{OOw(~?C$XOx~iV_GGBshdX@Zhci zg44KbaCg@Z5Zv7z8i(Lchaer?T^e_5+!}7P*4}5I_dWO9Jztv1(_Qt>RmW@DO}-FB2-VNbATDRb6Y_Hf5(OnWWE7Hnl z_%(h*;AK??vm{OFt0gM|5miWyvt9y=Z=5p6(viHejr1PgU6Wty&0o|@J+-+dcto|D zYy&-GoC^aEsJ);TPp=_a>xEfsJmugH@VBkaqWP=Wl~y+Q3+%Y~=#|aBZ?Hv$p%_Jm z-3v4kzb~!pa&v8yO)80);ol=Y7?vo0nwOm-cY{@FOd za+}8BT&*tSlc`ksHme)9+eCy8lPTqGS~H+kKc z{jrG3YyV@>B!;Qc_IV}>1L55sf0FX;nWCw8@heg&|7=H`glG0BZ8N#&zqeyD1YY|| zwmd8EImnJ?v;SM~jI~rk&@=tr!=>oM-3zn{0XTe!gg!i8jUO3s%m4fC0(jV>r&>*n$ zJGpj6QKN78+($@&1vzbYc3lVVb0QN#`mM_3cL&qZqG&E=)Zmq+j|hff;x?0f=N%#L`fi0wz)pHH`uOKH{h4&g=DSnihnFaL0zpdzRqz*YG{l(D}9! z7Gk{`*vBGk7k@fxt#qEF{ej~;f~bJb?Bf1cR?(^*YZe?IoDClo8O8@tg+*;ADdF1G!FYqm641EF2=P`?uuryEBo0fMQ zB(TtP%hGyW-qIHB104T}V*-wyRPz|RN{cjl-rrlD`}uTev)4yznK*CZQVwrf-KKH> zs?pDesHm~1kmmij7Vg^`y~=ioy2)_!%^Nv0=2! z?EJPru#^A7Eov+m^#lcN#ObFq2}eVM#W0vXz4?_hfv|{LzFGv|LVk`@OIPe?XW5tc+WS495EAOHbfzHWcVofi<}DG+L>eYGo2-F zT<|mzzP8zqOd@P3?G1QTRNj#PMT_BZo7#bH!@-=RLtVtjKIEFelwDNLzI)UT9MT4S zVA5z31UfPh3U#{yoH@oDIZX5vtemt){3?GnDkto(Hea4*EHs@)uEAs)+!XkiW6;)&%l(|{-K zuYc_1(kogT9%nBcDFp<}k-*10sP{=H(l{pAoTS7Ci|Ccns+3ckFu-^%fzc&73#Kc$YX>{4 z3;BGo2-;&M{&a{qfzT%={f-TF@NFV{Hy4Mx(krW6IJVQ8104!Q_p!qlU3ekV9d3k@- zCr^TmIOvI9#cZhm8;JeCHxYF0zF7Rdn21ut%%blHH{5=D{K__)&??%4x_Dc6CY?sG zRzD@VKB|xs57K*&A9m?GX(F^FU5?1LX}~ALD(x`$woz|5?uBJ<1 z9}ttby(3hB+}M|OP&^T<-j|ivvyXQ`_gJxX zp8JBzvWgJPcTz|wDIKsa48_kJR zEfM`yrBah7;9avuOOO&F2wSO6!b$3LsLe?*6FSfR-SPDZ5m%GL`fDu(l4Ocg5(ZHT zWfTCHgMY*javNJxwd%998p+bI?nV~&z;V=r570E11wHYF*m;!AZT1@}_}>iXP%V$1 zLPtiwA$Id!GTL0F%+KH;go}x4&3e&Y8Hw0`E0xpCrDP@=J3~j{)xJhoosOF;EP3%f3F8cDCN}lGnEF!+*p*BKQ6ODnZz`SY}Vm7C- z2>502(ilOtxG3Q>frBxPv7OkV}UXY|3nX3y!rVsa+8h3lER7QRAV!9GSP>Kl| z*{$FaQ&k)!Y4P|{!`;>v8=UsXA%xC;`<1G0?CUT(=aVROL-CDJ(d1V@rhd*d^vd%c zP*OKcE0uL6G02iLnBVzThK=rH&M-|g7I^jl>Ww5i|DfBjy=Xw=y_hrGwz8ai802_k z_uqKVDkaJ8|9~<|`YH7h?A76XcFeycN*Sf#v6Imj4ZKx$+U#5(`(*Z7K8DM-O!f%0 zSWf+i@eqvsJq}U7XY_=68$Mg6;juA5ySUHL2rG}7`K*gM=^W>{H7~Nk2SP)c$|@Wt zS(qsly1+=mj?tcVr7Ns3_Frux3~iNN9UsE9@4bbE&e=nIKDxrj!?SQlV?EHp14su= zIi=D{@`?~fM3wBfoP8YEl$b;gmqfNkBorvQ)=2m5b0}P(XD23sLzUEM`knB!gZmWB zClQ|M)MZe_dhE?;EhUgFq=Ld!QCt?GK>sH1^ppryS8ioUb7#Qe;a@-patHR#pw0Nz zwIg#{af+cT$AN$C=Tmq|Qu+omvNL$SK}>SjnwhV^UW>3M-Ci3{Ystoitsd0pYU%vQ zhfkn|FP+<++2>&|qp{7K->2?xyijz3_{Y(1-psD$YGV_2cQl-GDd@@HuHywQE4nIz z&sFSBRLMu(oD5s1`JB6Z*2}yDKRCB=v~u{|Zo*=VB;1l0$jG*L;TF+YK6FPdq9WgD&nsWXI=Gu5kLlAFtvlfDy}L^?&>Pl zb{W_*_x^8;!`J>;Yk08ISsR(+{%|tPZqyDQ4qXd&iZ^)_@a|Y(=EgPR^K`UJ zV@W>}X#Nl<^yuEwXWepkvOpghuRcO5%QcsNB-oOJ-g*h+Sypjq=#bD6uVjd+R2 zQ|BAY%XMzYeGYK&{l+)L~@=8Dj=WM4C zJ1me4j}<|>Dzni<-c+|9cihQ2=D6L*r9$=Z>+D2T$s7mX+E2c!)rLa5FSx+9#m&!- z9<*_RB5b+)q_8WAI04)q=wqq4TA|l z=sv(*Y&Wx{fObV565Zh3!{~()+h3;*rq{A~BN@6%C0Q*x-$_elE?2y_w zyuMjZ+2D7xg1{b%fdDpBTo+=y@PhIT#s{yveLIbT=9 z=tCm*Yh%YX5ovBw?8EHr>mXFx)f(cp3jOV?R-V|rs%p9r2;{h&H+;5(mA z186%OpN~V|M>jb-zM*{giugH{+l@(mZ=GvrT*Dpv(z-2Dxa6k*k&Sur!r6TOYR|H( z7mYP^bH!e`o%2qR!4Z+Tn5mJEogE7r_#@n5pY(0tj^r?8nI!BUro-0iweV@O$d~Ek?jOd{1O(XFMTH)p1M%@kxi8)q=39;0eRffi z)@4(~FQ!0ZvS9h0kf--kgF$1`$rd5QA)gqPBk_btpwiY~3~z#?F?di>zk@6mB)-lt zRn0IHJ6?^tfS5(2l!Nl(Gjx_JGEp`^f6baM(4H84omwv6T zLXpoaj4TC#cceiTzOChl>`eKd8~Kd{t9C*gV4+dwrJZZ9(skz1Gkr6p?5~H*rkPQ5EQ*XYxkgRbrM#R8vaprb zFt>3p3<;2K+I{e&la3gp^PNc!Cy$&>)k&Y`gP1ST;|j))`eLVOUB-fN-XxGkB#f>{ z70u#=NbtUDiVd^$sDFL%{6%>+NW%o|qpA?i+35gkHM%3s%$LuMaT%1MKPUXxT%6Wz z>+=F6)Pw7EF)}iHXl*m!Xzk5@C8yh*A5q;VR#Qs?$9PV6=*5h0%|Nc_0@Rk46nr`gS4ELC1nfqpjuXJIgN zVHefL)ii1_i{(JR+|?7??NuduMlVSlfYX~LrW^B>#jl8Y;ib&PsOdj&h(5}BxK-XB z#|UmuN53qag2!W0hONRgHm?-eK?(j?tWYhM?F@_Dl3Ggc|=E<0Ax}3_oC?_DS zRn5+F!`L3Wf)RxUo}GoT)xcqcU)O#L>0UYP?2d6CC*)hqvm(#i)^-?itKgTRwXzm< z=KsOwKip^#9ca2-TG({xHAvMcjm+h=ZnsN@weLR+_xZTdovF%M3^edwl$SUd&l&{( zPvW$WvOai%e2`L1v-={LwW_o4B*LnWi8-QZWGukA6mj>f8E;)B%OQG7s-MWSy@i3W zELUi%)i*1}xpc*P2L`RvQy68#O*^`9?UEt-g$6ov;Pb-`jh{3FLz{s%Vsm<~g~jVl z?-}Uc_jj{5>IFHl%CIGT6&_vzCAdf#HWv7Li$mMEr^tLXM~Mj`10;YEVKO|G3g6ol zkROcqiXkCtQ=BsQm97jQ1GcclzQx|NE`D8kQSi$5q<{+Ey_N-8lKrqqv#AK?yirb2 zy=Q3+PvT$2Q-S<;Y`qCGI7>lHSikSjNpI;4AFhs@3A(Rur(A7#&~L9eJeD)>vbdHY zW>EwC-M@L(e~sn}`Nk}l%A}>SWlK2EDkQ+SB7d}Pc@6dQm=Toi@*V*7?QFQlad02g zG`Y)&FxR;m&CWR;3&QdqdaZiSM>Fi?FcwtW zJWr}FpBd$YZmwCUPGZKZxAFzy488KmxA(C-6rYPaEVCvidOtNC-+mWl39CHLLPU>< z!0-O+&b8Fw;lqf#+!rmCNtb%>Qfn0kY=I#oQYh##Jep`z#RZTU*tDuoU55^M4-h&A-|Wzoo+-%-uv6DWonE9&swembkZmWp0CbaaJVbV0>BJ~!mP8S^(R^Z}-vi|`V&z%; z)#zH=5Kv34u^KbV#VDv;uqK5?aN8pfyiHoMBy}*aNkQtqI4#l+5)u$3A^wExna;p^8P``w2i)?YA+@w|dcqBJ_{tnGW5T8Gb--i$Ntf2sQjV}b6K zo3FE6BQH7Lto>Dyh7Cf4H(BRXrcC@nYX4g~(gPEV!Bw7#Mx;Y6c3?y^6tZ;U>pQI$ zDD;)ZWS$B=?v>$OcB5?)ld2Iek%N;_Y=YIEN+YXX7((5tGvDQ6k_U%^Mkf{00<-D! zyrVe0t_};D30&SWV1I*jW~=XvAWn{eIc} zJ*FC=a8@QiCge>YTQaPQeD&6PT9$fHIfIkjUbn4D_>4>u_n|i;GyrD`P|M{Dc4*dgJ%YxK`l-ZO#YyDj!#jqK!iLsu0 zJRO4->8p9m43F;3ka!i9eXb7&KUmN3mGN|GQO$;b_x))o+IGp#>$kssDWPs2Bq1&N zUMn5e&~@E0{(wk|k_@!5#TS>SXutjF#qk~`(qk`QUkTrYJ7wLUA04)+zkcmR=S`}5 zV;R_mJF=N3vvLGmOUFBC70hx)B;*~rXkAuWOi6%*Zuk zE#kI<`Fh@*egfZ4RTYpglY6WrV)9Y9aO`^f9ckgG86FUw8V^G`qNzK`51*J8BE)_o zO{g@ld^-74CeYSTg@xq)#C!XCre^*9E#?}v*#8ZCy{P)(6^`Yd|aa_whAxkfmPb?e9#&+Y#<%1@ zu6b@SES@9&7CK0#1tv&6fj=+}>)GAgnXj+O9(L)`_3s0ri%p%82=Zj`)k;RoFPHo+ zF)ARJ{RQ72&5X3ty^@K)Ad_PWB5Y4IXvsj@N@wFolt+!OlEdwmuY6{ZdqXor@V^j? z=@1>+As2A9XH^{`B~jH)0L&jX!NqfV`)7N`ITFUJ7ei`@s?eI zHn^&-(Fex6*fG6fve};rt)jp5(vNkYrke(2oRn(_<)hdLZ_Je$?WD+knMcLD)Hfu$ zUkw*Ue|+G3aN@YE%V`nG&g4uGOsknr!XkUbXfDb<_;FdR-!W{A-qP2s5XTdqM(>$ROJkgW|(8^&1WH ze*D9W-pIJzDrXRktf{H2&g0~jb3&5msftBy1iL1^t9>Ep+fqJoR!Pb3w)ikh9^P%X z+&mZ_RvN<6iV6)a4xj^%Yl4tr;&ry%4du3FID(A(s?y0|HLX@||rMpSy_I557C3cg`e^oG56IsEy?G`2B8=0Z@H|g=F zc-JJO4Hoy-Ereq5)qKcnFgh&-$rAUjT{S)QK=A)Bf+gf^DV1q&Pp{sCBhe1uhm7qJ za3LUbW{+(M?W8WLW>)(5ZCoB$@4n-6yI~Ri-j&*xkMhrDIdpuaE@vmAI3M`) zi>*oxqsr(+xN@5M<5atf%)wjxRq}fJf-R7tIn)VO#VTx~7KsfDc8}gIAO9c*{TvVS zjt*k^@a~=)QDj>YO;w!GE`~ve2%B2H z`v0L&%832H8$ojqkcsVuM;Lv+{k=dt8WGn z1S-8&dxBbD&-oxAw7qqr7xdp4NZ=EYdi1l#5S4yT{7|6??VJ(LU1h8 zMxo3OJ>dRKHlWe0c6Zopr0VBC;-QHL_*+ZZ-mWt+dv^<7G%;`i2Hu(9n%g0CMDCq1 zJ;BtYL%WNS0my`eSMBa}kwhU-(8tw`bI8_*)u*}svDHhKOX$H{b=qtqAiZ`M!Hy~d z_*0LD7-=Er2oViex-D7b(7^84(j5EU4$L%DE)fW6@Qu8lZ-! zFUKS%mJhxiB9?!+tEaP@-P%g$`N5RgDfRP)$7#9Q zry?@T?*3*OaVZF}ctMFsO%Wi#W#-10yT;#js5@S_Q{@ucGtO+m zza|ipH{vJsGvsl`L;{##LBJMHRrHQlpeMRrEVc(Hs4}-?la=?;4$9VWD2K7%(tios zwi%8|CGB_xSR!UZz)v7=QsG%%1S~$Ibaz-IPe%zn3qjN2q|$fB8wmn+tQbh9$!rkS zX%3H3nyMSCr(NcWB*K?fV&a&NtJhm}-Tgxk|$n@0@uhO}*0_M%BFuZV! z%tjnJRfevJ-JdngXUw?>#5*YJ`)uvj-^#AOB=yvfBO9@HOYnFh_e%}C5_hIo>FxLj z%FmYX;rk4DBo^WLP!<-1DaVm^x*6aKb`G}^ob$8}X^&BQg(K!p%!IHA{piT$S*&Gh z>y9~t(y!Sl`S%9J0B3N34v>wJo$J@qV-~1oxovF_k$TRAMsD(2Pb#>bR0@cjrV!l` z5kUM5G}?QIIQh@}x3()MC&w>awDfjJ+u5_h zJ{Vp0%kxWq27eXqTk9k31r1wM$Pb@n#9#$;R~6$uNok(gjGIQ9N8zEF`Mhf=J3AV_ z+VPSF5QVzJ9V_kJy5kW$NKNk$_2u7VG@`jkkeB?mOGd>nOCPIO-e)op#qJV0PyLipok~ zs{$tP4Cv;$nylJ1!+XS4#6@G6&Ulx)$iKTT$OLGa5{1rM^}MDM-eFcFFu`yha4-(0 zmg#~Rd|QcVQs8ZQ4YwZ}%eOFBcW>pTc%RVnfIl`ZzXyo8$RF6@-6=AtJqq!u) zX|b7TPq6Usl0ed-`Ox)9UYnylgzC!`yRkTAsFu<5;tc!!Uu++ovGU4uCJ1ZPAo4S& z#%g$TOPUwE5~lNgJte&R^A5z&)1LLse~mgB`he!gGiS##g85fcgAv+_V()g$Tt4)2 zVCN&=f|YTAC&Vl@kzr}ia_X<9xvP@)a4I?W`#? z3C+5DW+yOmsy-Fk+1(SfI>Xf%7@{Akdf%vhg$?S{7hS&Y7^%v&VB1ONvgFKbI(`-i zddhU)?;w)0IdwCwl57Gs@Um@M&(S_lta`N zamCpH6gj4!)Xaxs`ZY_|=%j2Lw~#1%y) zND<05jXIp3EF?_MiZ0Tac;`X#JLS58^hA)LhCf`%(92IAP9e4nWgD`P(cEKBGh7JB z)ZyB7{kW!~!`EB4KD#5AaX->wH2Kw#Vn)_n33^t(`TpzS9ifR)rVOywR=l>6-L_!s zhisU4dG1Fh`qLU+#)&1KISqk#dovXy5$2ZmIY1RhlV$)w!&?$b#qsu^;4Z zdKpAq|K;@=I^XBMVGZhg-sAH87L`|1;Q|Ni zRX^I6U=wORrVMqTHi-x+XkH97R7dMmRb?kLLIw?#65r!*h7=78wyk z{S=zGrW&RdA6uQ4gESd5>fni31}2b#jyzQ2d+wrgtG$+jKiDEnO((l`YV4504=8Ff zevl|Sl(~mjSQ8G+L1FB=z7U%OtMLyYQnU1de6+XmQM~lU>94|jSo;<|?((hH$RStQ z{VlnS%HB+-xk%l94uPi(k~+!EeY9n1pc2}NkOD0mj2sWj(1Dm{gmg@C3ZZV+H1773 z(a`HCS8@{dhSPUkZ-?Lpr9-iMKBOSw+k|abTTbct+z8Ngph1?yZPo<6 zewBTQOkM?3ct?4KK6OXs^zmJUNeCX^Bmj{3%6&{o;V9z|@8ecL_F(k_PZW0Cdt4V? zxD7()d^+)<_}96ub8=}A{tmz+9vN4E$zB@WTZb+%>vB|R^f3)$YV*-PbuT;L=0Pu;D-}Y zLFagS!2$`$fYn~NY4O&}%JBWbZi^xF77e_m)ft~Kx~^SpV%=Np0<{db8LO?1fPHEPL@HlS-gLxu zK09jD+}T8Ar7SZv8wq^)>Mr)X zXH;)}K-gQfa_N{&jCzYX_Yx|Bz}0al6EPKla89FfZ1jH1OGS|}%ci5A&IY<9$=8j5O{TB81l)Kvr7`Z-Da^j(~Nev}aN0&-n zyF{+c&0P@WVbL_VjZkHyqj?@V&NiA5M53l)A!n|`64MfN>E#ZK7CPB~ydirqJ2ZJM z0k(q^Ry*i?!+>V6w31-X7sVU>Pu^DO8v&~&rU<=B>ix5jceinY{jrt;O-F}|a{u#| zyp^Loc=}9Ni#MTim+9VDCh^kTS|S+6Eqp0j<(6j~0nGH1-#N z)f^S6b3Pq@dAcd%dr_t@CE6x>`iq`?S>0&FaBTcNi>4Wt^csCPZjk&yo=r*o58xiD zypI&)Q|Z}L)tL|={N?cs5CjDWrf&>>w!k8Ho!WdhO!gSc+cZ$*5mr_JK$wt_Y(9ic z2^~>W^klmck{SZzxibXCY{PnDKmXi}PoMug&A5TbGo;{1Hvl>6b4@oF?tSOMKiyWTh|h*flND*Io> zO)HwO)0E7gDu+-PkVpt?MtfM<6O?v9GAT^>Gs}*3;2JsPgM7H=wMBa~7y(1n?phpP z6cVIF$v0>KmE|*EbAx=_$et>JWC+b@>=SwUyXc~fp{B0qEG9W-DFjvA9kmE{+en3L6B}rOe_Jpu86=w_N(xLfK1~bdybv|zm~+wQFO)p&XZIL->KC0+YZWe6mRN0USBAptdu0MAvPOP zR?2w4J1B$4F7^|vp!;_Fdj(gp`xNnkDvDtuR;`i!&JV&;EKwDmpDi6fml-H68QbP{ zn)>~fH-A?=M=pC6yz^Z@PxSe8r-8ay%vANR8brp^xa)x;I7wOty7aEVd6K9d&(XTi z6|2w6&XsEf>1&8U+6_F*!<0YT7fhguW61lU4-$@!9X6Kixlh^6UY{|-DM!?N+#6=y zgp%Sw=!ANor) zd#45%4++W6w4s$EEJr=qej4QRvw(d^3!zlQ=ipm+AG+;FjSpKMZ91V%Gl0p&ybM-_ znMX3GB3kN;%+^$lb-|?W3%yv`(Pqs6Gk^Dp=YHO2w~froJHy$rS6~SiY~%GMwV)iU zm~ugR@{(G`$K-hYBTUnBNzRRVci{9LpY+`5*4==Vv)dbbElMI=2D2t#aq<)Lo*zI8 zkSXu?JC)au6j$o2Zv-JaMs5yv#)E z_^NTEm+2__e{r>}_R<;8rSO#RcE^+J%rWc1Q9c19RFqd+JGXkwHB-Z8PVx{h8R!x3 z%mm>5BI>rUHQ^yKAloSo^;FGsig#!n+owxiA_%!MVr zu;3b*a5yR3%J)T;7G*YYdbY}6`>GKqZDYci9{v2A^6J}_NtU*l5l;D4wG(R}@I>^g zpSP=zv^%*>$9y2^Nn^LlM8HlI-Hq((?%}(CjFu#fKI<2Qa>KVzM`Ef|Ny*f=(8+#N z8S)a(fSn`4`m`4UIKS$ZQ;RK%wdoC2MZ3D$pUKMBiXUDXENVBD?5S&%r6#0XDXK0h zeY1U5-k!d**3DhG#K+nNkae_8u&g@6NgKxS zx9R#3v!-6B*?GfqPnT;=YWQwZUURZv;*EH?yO9U0c-Hr;?U$mwHwk0B@P;JnL`Lj4 z{0}8kRH=ofyVpy9$=$ag84{parsP;fw{AGEWAwf$ihmg{*1yw)CN%7xCOalII-CD- zJb!&AZljipv1_2V*C0F?0;vq<^Fa3R==Q2NA3Jj8J zR-sI1T#KaUWBSbzpdkw(8i%F7`~8ebZt6Ef@*lJD6!EaH%DEM(7SDsk84e`a&L}@B zq6~l7g%C}n=EcsOJkWiw>_Lma)0To8_i(UAro(4;PGPItq zqsx*EDt}Lo75$A;c69MN^6F2ozx#Ysk2;4TWv~C&d|n70$4=TxzLK|3sT&|p_wT2v z?dL{WR91c!M4jZY!h1GSs3Lxers?Z?S*U*uO}+O}+}|FEyTc!K5&__8-M?I*ADBvi z3%&myIjA%1;SJ9%r<~XOe@4=pdLk=Zh~PgP67>9M4}t&ZChdPV4*1_}B8=cak1Zl( z{NHRo-BpNnX-}r@e0)N`lv+F%%b_ZaQ1aL*U%H^ncTujs+J+)fReD8THH}L*!b34r zm=*easfNp^mZre4d%UMz7C){f%(8&_Du4ZknQ;nG@Kc>$7JF2s4K_~7F%r3l691@W z+_!vL0r#mH;W>%qzP#kR^zyY`m{>2Bs8=dSDeq;ax~Qt=kHVqRMK z&(-C{WPMH(9ot27uLeOF8ox~&eoy`KzqJ4-JUOe5t(`Z|#edPoMToQ1|0Nuq5%ZKH zgwb~>X1Jr}?>>6e82sUF#}BIBTx&Q_tSi=GFtpI~7Z%Ej%ziD2`@E*L<24>!JnuWX zUktH(uF(p05|bp|)6EL~!g{Fb{3kCZ^qYG|acS5@K6YP1Ba^D^JI=Nyc3f4LwM(SX z?QBj(R{3r?*5g&xL%P*Sf z{Vq7I7~48218wXW<0Fw^t(oSfVOyu)eoWw0EY+yHO&6}} zvnE2gOUua)xl#}H_Sf0MHFUd7^9-t-(rfI(X&1=zeVFUoWw7LX*CYAu=H^c*fj9>3 z@A!r`$uUQ4)1NO6bCw&1+5d`$)Mv@aaXozVKLl7b+PyE7jri{71onKvqJ=R6nNW`3 zz$U*x>UCIru$~g=_cJ3A;v-(@`{@TgoFCK_XcIsusVl57vXfXS65s-L2TPi*zih9J zbP=TG`WS?ltSqL=kzxB7HDKc`P?BHDTk`oWjuEMfS;)ckncUB2DDtU^YbyN$p?_uO znvf-j@8iH@yMx|z{FeI36+$8WwCwR?+|c-$696fts4_p~;5OmB8P^Hc2;^?zlI%an zk}~;YiuEJIdqKW zs&$aN!YAxgqdFWZc?J4+Z+mEvur_2&!gevWsD8W~=EN;G85d^qq>N_6r_LOT3A<%c zes=!N^6Yo>QbU6B%k%8`n)~i?P1e3QN7gCd^1fE=8nP0NA%ht1$8hGN1wY1zVZ$sn znc!4DRf3eDbxBV)YS;j zyjyM}zkpS9yboWvQLNYNUmrCKVm@fTOd{|x?frw{} ziU*#J#s2I*^UF<~Rmpciewh-TkJt|J(bhwe_`b&@l1TzTunB5XaY93))aZ^o1t!JT zf`*yc=)}DRj_Ytb?L8M-`1%sjw7#pXy0zufv|a8;PmhdzQhIhse|?9jP7yhXm53&t z+Pv`A%LYDp!1p)vZ@=QXY(lv9A7?LHkuIQZph<`OI^VN!5ZU8}+rqoFhMI}wu6!1)F$nIVOo*$akGR~p)ctR#Ww{xG`f`&N#F=?In`u(jJmoKy8ai<#4 zD8C9#e=xhmjkaofyKbVC{Gc`cv_k@b2fshJueG@Hn!U7revl`gm=gw;WjU(CdYf73Yh6 z!B}WU5f$mJvL}E|W}|tc1}~DH-~=~mK2}G1j&w_WwgH~B&g`Q|!|S2^v+;}f=6OZv zx);?+#+xb8ziy!sI5;!HUF?>bYNz|C4=sC~ zoo)kiMz3q@*Evbgw#d6?zc?fnvblo|`iin~PpF<_dun}gc0O3V zT-!;sWP%Mgc{Vofw19WquBe{Cr8UyZmqGu?0t6lXQhc-+h=S+&o#LNF9f!eBkseZX!KsR-|$e&aoJL*^jxgs(aTfm7ed~w zscK75xO7FT{;9cg8%XQ}yJtsOFqx9{}v0KZ;FSM^Uv`&z32pa zl|CyH9xYQC-sS_hwr0*2)+X5a`ahdlrZ)Lk$kVV`bj14HJ#o4NxVz|l&2n!!;I(A? zvwxq$Ez`P-E;f_{tE#Ffp!m?LR-jPByRR(>XjuD#u~)|*^rytgojltn)3M6k z`QGcMEl+^YH;cbTUsmkR^-@ztq&Bh&V0%w1QYm-VKzm-`k{8vlD}32gVb#&5FVZ?v zJ@UhYkGq;0OFE?P2DvUHha)0~jHq=a(e43?gjmxIHV2btv?PSJhv; zQ7J%uNPJ}8Dm>J}f6t+&{`~iqfHEcevuMO^* z6H(3mB%|1*#0scYOAs+S?bP6AB@eBBDWm+M6+uPz7n$3RxTaHHqC3EZmdt0Gi6@aL+ zR&;Wd<0jGLzZaDQJbXdzuihb|^wdz7}6<~an{nh3L{>_gLIK74nZjlpH3n+J% zpYoKYZGkUn&-vLV=R#htMdVvWtNlWcIqUXg1s9`kC482j{bHx7+_5JkEDY2=1-qMG27!-CE|xdAP;fj?Uu>$WH#nN_WXLO;UemVp3^~=9k8T@AaQM%CAZ;?5mlr^y76r7=dI@9x1JF zkFO%pgox-IfA_}`LhB`p{|XLQ1a$?P|0^CG?J(BXi7ZL&L)E1J-r?{{k22lo^jv;w zx0fv9og6jt`|yOZZ1?KfCesEjrV~{rU#720QYf*rTa(+4X~rEvY%5F2;quYY=reVx zxIQeun6g9oo}&n2!@V!j6t^HvNI)6`SMhITnq`So?~L*1!tuw1atDt(sP&&f}#BUBURmdE#cKRQf$nVffI^ z-z$%GoR@D;7G9p8296y|7?kW|R)5TpX zNcDETjJVEPlmK~Bbibh6&B^{kDaD)qDIE|m-TQ{1Gm`pK}f$qRi}z8!?lDbak_?T;63X74tf@W=^8eVx{s2iWtBJmGC;vG1Xb3 z47w#vYK$iw{5?}1RiGaTVaM{T8%pQ9|)|<6foUD3kk# zDp}nx9HyIMhVP~zlK|~~z@}^k%E%vu+c!i14{L83)mFEC54Y6OwiLIvcyJ32EfgqT z+@W}p;I5?;?VmpP{%nl<Cn%+(;pz=tSKEd@s<=jc^t>WUKZqWGH%Y<(7#|?N>cxWUGsHp-MoyJ zP-6jMo=;MOL%R1W!gF)03&|$~^iTc@dnIAzVl4cygI~Y0blU0bd1UbdE;czzxowRo zfl21&;_R@l@VrNOS?Q|@be<5XDT9Z&?S5l?+UloF{Z%9sCNgC;btM`qsrT%iI z4O73vRSlCLy8)L6`8SLHa~FAc|HaO~I3szQPe1JhtcXATvhr5`zxnk4pS<^v+%b-5 z%6w_Lx!QSp_eHz=!OTvO-X|Prw3zGu`QLKD|6%YQ^&jP4P_=IizccfTOwV~y3u+No zeWkV6sl0I`thf$uPrWaW`8XwJOBHw(=$xcAbDOiu*6HxqKcAuuls+NYA8U#>sen{J9Mzs&}b#X_Tpy9?Iz&Xdi{tSu6Dk@{=D4@Vk*ZagH6X zcq@Uc=LqlzJj9*G9W_^R4ryUiA+5lM_f; z2-Df34K|lP_iafd{1Y>&z;1(}HYO6w@KWb3D6@0Mv@grds8rIZb5Z2OEaQIl5aF!J7jIc zN*G5c_HicYV_VnYX5);cZg)Q~&?iOq!R7=B?Q#ZRCtMD;bV3@kKr88S3ypgcxJy)^ z>D58svf8;_MV~9TOH3Q?zgrO^{2)khiP8Die$y(mw8;1TBscS{Q@H<}ttf%GkJr^!NFNG~K9UVI97348Ge*NX$^}?&Fe$bzcz)`iU#QFVH*I=~qcK zRYQ|(oK5N2zVO}rewWRpz7>V9tIZW6f|@ z$Qe_oI`chRg)N25jNFAB*A!VV@#D5Gs%(?iso^f$rQ;tHw>LvAW9XzmUw!8r=$lkZtqYrEOuzJB#+nrGcRN}}rR%0waFuU3ldwF4 zLEy^$(l17al_G8F+3OqjKg<;KR^g5;uYVdm7h7e`Fs)ji7Bj6-0UAxSt=CTCvEg?F zqMn!q=cm1-RI8s> z29?NC&U4!Hs)=1ZnN*3={~2uq+&@uaQ^^GQs1NIruoP6{}Wzk6E&DiVhy!@AX z*xKnfYu!CQzj;9UnXjha;Bb>zthoxTvH9)zhbZZpmcgqt7_ElmC6jCZ#mSEQ&2?#j zPeBVZ>HYqwD+~Gi-xf(8V%?Lo5yn6~l^ukiUFmnEWT&fT5;N9rR<$Hk-Nd|c{Ew59 z`>dO_H5K$ikfO5a?O-X=Z%pCH@1qteGFGN=E2z?VVKn|zpUyclK_ywuq+KtU*~k7< z4m>kCI{7x90Ey_nZj#43zI2UEMvf8Knj%A#MeSau!N#&agml~>m%aL+K- z(zuGqo%xE7VNTiAb@llzNk;IY5rJ{O1H1Ll{(+ihk#3&*$Cmgl-9Or&cP>6fjO--k zsV7qghZP@`J~VYW`w*hz`579iK^yH%ngij#4vNxHh$~+UOS7o-@($lO@(a0B0g3oUaG4tdU#GX$UWmA{BaM)Hnl%V5=N2XZGkls+0i9rL?XKb@*1W z_n+|=ld1M?9;VwQ4lcIRbXb-2H0^{@s1>ys}EZ;L+_)mqEEX3em(h5vbA`JpR$pzxHfGcp<6dzP^*$EJ(wux&}EU|JOM~I zrLr{B+g6Q78@e69ZYDS{mCx{SiVf$}-+P-5Rc5T!@P0Ol4a92dBo#S?wIL}W-TcAF z_#$}E{I9gqJ7=>mmmIENOG{z-2}0fbxLV|#dA^Fdc-&6AL-vl&#KUt-+qtE`Pm==7 zP}DFn_n~0WJ7H>{Br|V-@A~?df3Wxozku`H*C_^DsUrez?($d#hv2#*L$j&Aq*&|W^t}K^;%f2?*1x~$t_a2S7**`lCdx_ zVZA)2#y^YkT2pqi30J3O>|>oX+(E}nVF3~9{kzy{5xoGwuio7c(pt`DD{4zjjB%Y( z&HfAAm}>&U6R#vJXjwkOZ?5r&Pw+zE9p~5uv{b9ifK{WigLM7vV(*Nh+YI*b`~w2= zHpV-rj^u$WvYgU&U%RH#kN>(HT*%1>b&vwaIM3`U{Jzg=27K^)Jfp#!Z+GI_#=L*_ zG)nm6y!|yY`_=bQ&AtRKVSMeD?GTv~zJ0^K1bE}>{H-7%br$E_zO}vt>ErPmR7N@y zL5BAugjm&Z8p*!R4JSoV+sLqVDgAe}p71?GU;ZtNuNLQX=dUT=h~E`epqou%WT>Sdt?XH*5Nlvoo7|*&^6!o ztM35IIN9JWOw4ztn4{?~emnc>L*G?+J$vrvO;PSi!Z$oe`<4Fu990&SWNDVi08eAA zFZt!|mr*(+@ z%~FnYl&zcAhaNl4Ifeiv`rGi}T0ve~yzTje^LHHi)s2WrrwF3&;cfSUMvMnK+4nK_ zy&oEeH^BAmVRejw9)>2hfOOoSf=2X>#Au(yoD|zJMk^+8?w|Iyqq-KYX-@6%-au-O`cO;k3sD+PC0n zOHI7hqTZ%)S_TUXb!CO@R|sk8eQVf^|7}$j*nOuJ#1pmtwYxnTEWhuTjz?pa61$Cj z@O_n>?o{;>&`0YdJ}&hnb2*%Pp1_2m5F>d)nw$DOjI^q3Xwz913ruD5Q)&Z+Q1el` zkbOgb1Ko&V>smX~dQlZ4SXW}9E%4N8Hu|Y5(?g=`C;-rJ_Tkgmu7?fcR0ycK?(J-_ zr}U&FR|im^Q=OVpKq#Es^yShl4RqCRZgJZl z9u-LxF@>6Q1j3hIsFoPan72&4Bl~JN(@gS=28d0*fDp&90*UH(L!wslO9NX6agg{1+x zO@&Z%-uoO6USi!$8K4{|?TZg(4bgm4!9Mk$Z0-PzqDr&mDvHSsY>o#2afyeWqsF(S zES1qy=CZJmVegQ$_Frih#M(NRW-KaGv=h&w?K|$~C3HD>H`F|o?PhY$oi;A9ft7jY zIf^*q&#-Du2ORt+ZrQePAF`1JD|Og&Q9v+bAp0yLh>J*wQDE{%kUvX`@K6;i($uI6eu@` zgPJj0$X&VBMz`D$KdNo4cJn)r+81>^-z|A0OPa3q!m!O7-?X8+yydX)5dL|C}BNTV&*|u)ctL0YFLCe9lSEd1@R}YKXw*Hg^PVeVuXl7y(x3$OT-WL|Cu0<&a341a`zce+o>JBtlR6rnLOp-D%4geNh)AD?xLK=Y==WTeH$TB z)@^L~zQzVzU+7IvRL&PiFgfK@ybTlq>J@$l}^cBq}ygv(pXw} z8C(zi{ZjsqUV!R{`$In+QmXF%YE$H&<{ z-8Ne7grTd!qL1E$s@~}Zn9dN~9OYlmI{FpDjJlv#6gOuV0H>Lo(FhIC;g+{QRr%<@ ze<|)>KCnu95u^V^XA)}Xr-oOI{mDbsGmLWQ5m zZTL}d#!eHmrG@(03tXD-}uB}C7?SYDp0?AAqHF86Mle4P2wzku7 zL^aHWafdg^CFIcp;RuXi(M^nT*pBU zz6w7&fid0ay%+ySzNQK7=XwSi$j;hF`Z)d=o@o#$Vf|@Tzzib zBHboxE?yq#Cu?3r0%Et6k?Jlvw7xx|l`3f~%MEYMF#ZzmNp)*cJFg(T6@2Y|9UE_8CAJwC;{-9SBrd9r~$*(g1%NJnq zd?nWUt-?&opW7Zd9rjUy)iWMPDzdYuMth&T7q#x@$~~RGg{mYa?0QQkbXYoz-ek!c zczpEip}&xJzwGnkC$SG)fEXF>mIv?zCTjez3{pCD(H2)NTg4??J!WT19CnDr1J5w2q*-y>N-MDU}MZ z>n1k%qCVK#1ybIqae)-Md66EVvt06tGW@m6KEHQ=C?S!DvzeK7YJ`x;D$UmmeFK-O4HmO#| z9_Uf&x~qf{5;Fd5UlOIaXQiB?%++3N$#^Lml%QU6hcJ(NAzZ8{Y@R!1*?&TaA$>VH z#=DB2l%E$bd3uRy?~IAj1ReXOGqOPH8H&n@s&(4XO3DhZX~gr=yQLz8l@{d4X zand1zx8`NP%jZ{7;HJ$V=3ow;Af-3r#~qoeNA(M za1vnfjeMOuXjw#ob^cEi3Du78ljE3fsGsS4PyX;v;q$s|+Z!1d&m59%lcKZN z6LVMF-pmp*U!0r%x4=p7!)$7Nc6a_;)Z9jAxnT-{-Jc<*66x1J8RyT$Ohs16bzNha zsICy?&Al*OI?RB;8QMAniAM3Z(ND4SqmhAt09D;IJ>Lv;-y$BNG1a_Xfr*i!#nw-@ z?s*F2Fs$qwCk&Nk=?93gJSCUaJVj8Un90dOgiYeJn*W5v#Cb~9%n6bSkh0QpXd+&D zqW11TwF0-=2E|wVaEr$z9-2{}rBUcQcykK~!{s|PYdlZ*0*=Tj9vs{CjW@QPExd4B ze|@fiI}z&KwH`l>xC~z4@uRQgqoH2hvQFI&@ow<5d(WV-*kV0;yYf2!hS3!VYWJpp z)~&3(Es>0_igxb7xox%AC#&H6vl<^-O&uJtGUB3mB6pwtBM8s={b#qX|K;KJzb*&U zC3e^Ev8w-d?%D&fk{prZ!Y%Osms9#*JM!0>{8ga;UV0V$fWH>!X}NS;u$FEEJyPQM zmq06&-#q<;^1)_Tra@vt#K`^T{VWNyKf#2J;J_5q0k}?4_M zRMCNZajvHy>Cjh?yKu|U6nohu>hNCLiq~ry*X9V3Ag4I&$o&YC2~m%Lr0E6GP~;=x z$#{M~0oC6VFE+izBjWC57?*7#%=>Z$M7&mSd0pHlW*~5JatiBz{Rtlyjw5G;4o0&m zpum?ICth@oT{Jw*Zh%(0?>3IN6@V#8-M=}~xRxbkQ(5kQ0AD>ICgJz0h_y=;FI%+9 zcu2dlT5u;;pH^}pb1e)65~8T$L(EpncHyb4ctxdm^laV@RiLR6vCpw|>Ys8&Vr{AU z4Ep*V4^O@qSmtDcX3Kl~)C4<@Pc!Kd4z)fY0rF$n2vML&=jQ&%adPgRh)>6Z2K02QsImD$b?ljz3Y%PydEy3g4otpu#t11?^#uQhpE!jRFlfrBcVdUHy_ zInb{$;O)O+?=#pxVsAFrUY5}2L@brlV9xyMd{@^V6M80hiJFHkc4?vt@y`L)$`m>eIBo5-4%Q4}*hLTXoR zKaGp?3AzQ>M&$x92A@h750}-J_Ea&h4D5$z28+cpGf6D=`9Us;p~|F`{m3DkzFTFp^ZTBZ zs)2o1@gp$~qAarM2HS!*xsC^u55xp+ht{Xl#juVPRmFk(b1iL<2Glul-imscHc;ugr zOf*R81TI;M&^T!w@{j_h~|GY7&$*r98J1o0i4QkxhN;y||x~{lh z9V$I)e^eZ_+fPEhlg&`k@=0?C?a@+Rb+T@YPCe%+b;jHvnD3t~G@}YHi-O!sDX-== zo76Sdn|%&Y+v7Y(?4BJIRdd0Yu$KOD1ror~b{EL!?=xm6{p#JSgU-k1veF8i#1qSc zr|M!`X2eW_<<_7r2N7M^fYP8h8tZ}S*T3reTQJf-Fmxqt0PMPze)B}ycpb`76*IQN zaC4K(=qV?vp&o!j_LWAGdfqDzdbzi9lpkmqf02T6Tg*LY0FJ?%cT$?qi=`#(?RNU} z**rxwrTurD#S!x(4ONxDOo9(Wm*;K@g38s)TlSOtuRL}fy_Jo;gJzuTKx|0R%{CSq zdUd#B1U_;qMoal^kQ`-8i|Xs46gCd}k5~Yhk71)l6yR`6HU6 zZP*FWB3qjeGw7ZauhHk@8q$6{&%c3)JBto zXRky(78-UZ*MW1z=S}`QqZf{d^T?7GI@}iSxqG&fuS|59W5&OK@#Eq%8ae1={r+=E z$q+HE)P0mW($}N2q_FY^`d)TK`+GR#lMaYp((Ttc7IS#xbRJixou0mCwK;0oU!x+- z8qmM7{$pjM5Rrq;L6n}0NRD<)<_UpTV9X9TE7=i7&FcE=Hvo znmA#Hik3{sBy=y}Du;gE&NS*eL~68$mD5}7)PY;TpZohBICibd3!TfL#;pO><)x8L z{I~Q;+dt3nwca|#F0*)vnm9i`uVjdH?$u5*1Lc_H_jfyLvh?Igbo3}Hg3^xa=~_Wm zRrETmDE-b+XrMxMpjUQxB$d-jngQ088Wx)8^Z-6BXgT7(m^MCkfe03xRG<3J{1l82 z3t@QDXlW_o`Y0a}n5$G3zwBbCaK37j+F=a^X9($zsd{^B_0keMY8ya3p2CRh&j=lQ zd$m(c?`Mh6Er6>WyjMaIZkAjMPO1evhrA{rxMr(x0A5%6Kthw~1Gs~yU1kM^c2>)o;)2*~wCZB_st z`SiuX?$+96uC|+Ih8Jf%q|+6zF^-ZIRlG)-N?|-tLNbf8$k3!Ik!tf_(>x`YJ9P2*+f@s21I>X#Z`^^^=1W7r%ga;h1BWn#3?f99E$aYNf|gLMexR3zt%3{A;{g*atT{Y*qyj&0YRe9M?T_Q(cCM9IWvJ<86n8~uQktM5N} zjYXQfzt`e~q^8A6F>?DSJg3VEJ^oZO`4x54_62}3T$nzXb`}k^ciP#Si^4h5c-ZBU zWZ_wC%*s8R5{m!^vU&M`I`9?@kct*x8FWYA09cFha1!Ux8~GqJ9|e(lEdwJHxvjMV z+g@mIO?EG0@Fy21(8QbD)w?{rqTU-js!+@)DB~Hyo@`$qZ>o#*ulK!l2{U#gDz48T zqiP}!S9tK=JnPpI`nPz0cbY-`okMZRH}3J(sj)$BdJ+}Sqx`SgI%$A7P|fPvdLfvP zz4wRAYfRnP@tj>AeVJ=f6^$;1QC_n>*RsAH61CAW-iu&Q>5YbZT&u9BHj`dequOOb z5rMNupA#7{uXlFubq3;N2J`qol^pTzj)~l+Jo~MP99n7{*J1Rwys^0*FzKEURU7ne+tk~Pr>9MhJS+c$Zg)+!F&J9! zJhaLIy6aX0}J{s=qx@1+F zeuVEZ&MM-*i`TLmvXoh$SwU+aFkQc8VX{HCCat@f53YRD)%GVDo_YEl6ld$znIL+~L(PpEmsZ5I7nD+NXMl1UUo^#&j zYnaN|SlZ7SgEsG@KzZ6%J8TpRPLChveIi&OJP~`>kIw-W-RAUk=Mz$M#$v)r%*LO& z3ykYa?GyN6gvd*N^nF9f7uZ_mgk(M{8JH_M8CIlC{i|xW+18Pt$S$<0+$#|g#&)G9 za@!->XPayA4?RsK;u_mdk6yFH2z-l;|20=^p);mGF!REehBdHeuL0Ac7+Su5tBuuf z&Fv%7BewkBYV)tTXLDpWcq<0mG&W`R1QGT%62cw1gS0vHtFz`CEWPgT)B0P*C!0ou znsI*MNQ^8jR^Pn+z^$Nu!v?hepENGJf6086Ec+FoRVayOQ&gyX>rd&{`OV7 zNAKq4@sS&20h$+cN5G2a)^`?1m;kBxY4@}_IqkJM9KKcDh7d)_I;<;PtbE;WrpJl1 zO9l+K7mi=;RT((z>Q%db8O6{FW<1Jk-BVl8Zwd5GLgzf^n?i5E4s4^n8(hIM9Vf&K zX3L2kgFm-cPU`VSae>j1eX(oU!#FQXEgeAx3S#(`JKGq(K*7NxihFlHEJ&M-o29dx zD34Wer0dcr{<0hw8S+I(m5*^?toz2D2U^a9yEpaTHyRpq-pyTRru61FO6Re~)laR^U@rEMm47}-sdJ5O-c`w%=rGh=AhlE`U*FNnBG ziaI(ySTXdxiahr9?;AHBXN%}=s4%&PKXkvjwG_ejJO1O|nTV}gQs&O!$%%lK>A_jw zicy{!WBeQwOj15_KyXQ{^3R?0p~~qf<1_o{RLp!LAB)^QA`F1W!Kl|A-h`4pTMARE zI8y9{PhDS>ggggi^KWD=@^I_u_@=D~vSeC5tt+ThvtG0GV9dzr@yLSrrj~4`D4W$= z13y$DHH&rBA=P7C`Q4lsFC(7vyQjXVKmVAnIa64Y;ifa@tf4mk{av?QFKJ3`Yq?zV zxpsP4tu2Jir_Q)sIeJMLo0?%-wEmPG>Tw!k?cg73*3r>nNSDeuNt$|w!4r*kkPkXk zDIX)ibokY+n{sibIK~N*krkJNF99fZ)kuKDBs61R6O*!1HocJEZIjMuUNL4%9LAG9 z^1@xGsV5t~w0CA*D_VyrdW{9fXG|&(m#S98>HxmE^{xnalP`>hqqYF!mc5w0!1v3 z{^ZK0wNo!E_gg)R9CNf_(T8oI2A2S34hbzT(ZJ5JpSFnJ%v|X7XU#2CRLcWW2bv_V zz=&g@sJ5XgbU26l%t|Y!t$ezR#rJaCZ>e2U><{^S_=awoZc>aLa<|$i;_$l zDoFY4a6xz20P=@ioAI5>>3SMOL^A5$ToEkYbosrDPkelSWMJ0!!W>DmxvA7X!EP2NaTA9zY3i`rb?DF{_IJdk80NnY- zK*Mh*EQ~I{r13Dh$%6xUymF1%c|Od=Ju~=#9bY`gK5DsDGMg!2YsE{+*8Z$;g+f@m z%81TnX1#2t&@W!r8hLkat#4+Q`vhW)vF0ZwaxtK*uqP4GdFKXi#ii-ad#f5%zC2&E@_|{GE*1X=Ed~i15}eV|7CRJQ;>=^TAuUR0Ih9@AJ~} zZu+hd9rQlHi^668zV(|i{^DQx$shhJ{rKac+kfx>J83yDJY#pAyvuR$7E5&GJ}y;x z|CcJJ3 zxg3KwHkz6+Se$N6nN;pid7ZJ{jPBM!5sk*NCMll~M7M7JI|KRSAlF{^dWay8tfH&( zGix}&UNJ}Wza&B*g}1W97LUoPoa*lhAwkD5ZcVE$WM#>ysf%MPgbUwS^h8rnbfHY7?oCC*UwXLY zj}c->#C77K@?i$uQASUhp%@6WYxk7?q}b-^)q0tVuC_MB%ZnHrR%+l|qua3zS96F}XU zW+56wziT&+A{dv@u8}4BAOkYWvjN4x0hKO36%m!nsw+pq((q-u?yRiR#zp2@d1gDy zK$w?J2YU~7aZ#g|XPWdw8FKc&fD0rUknuF8@dK(~bxgs8%oLz`n8-_1I28hor zfn`Og*Q#8qQyPmYRY2tpd=qNQTu_pwdoI25>aVfOp4K@I|51JYGI{q(FYVHwZZi(J zt}X_~%Q+AL>c9nZTts9&2za@Okb?M3a^vzo1kS5NRlLRTJW*1T#scE`qV2yYwzS#E zC*28O0j{1zkZiapC+br58@2>iUq{5-J1hQKoI-G!V8m;S&t=GfBss|~6~?|xPR!bl zdae632SNBAe$TY_>i{|QlKJ^nGmpsZ%S<`UERpLxcehEdt_1h~&U6>pyi`jv^U}{tQn59&6dSi*rSk)xJB9jBS<-M~D#IB8Pu=N*H8 zELEWz7eX?k7BNbeUIm#VwoVsi3G^v}XX_+xCCDXl!QRpUXml`B+`%?cDoHBj*_-6u z4nSh7OgXPf=hX-goIIV(nS|;~QUP++Vyzi06}w94ruYi$)VTJMb*Ng6EsPpb%1ouI zIF946tNSjgVLDPAl%Xcf{=JKWCQDD^v;+)>;ah8mPd1oXGDd5}l?Utn>g@`*qJ;vod=z5)6 zYiNO(dlJaAc8B%gyAXf&1H49qr0$o=L&2`1v+B5|I!@A-=j@q(GVdc9uAN97JzU4x1?dIR(#fe&U2O*MsJN|v>wp-tj> zelbPlW+?SJ(9|!LJ4m$k;t_7oIWJr}NgFRXpE0Sm7PeCeacBFJlhPQ{?c8s{rz|yB zh6SH460BN~j9cHsW2hKLc{}K3r|9aH_OHn*0^T2Q3=16f=opvzi7pv0YTB7L<)}^y zJ2u$)2ZAN|8bdN*GZ{2z?;uqxXd;8vHlHD6#9DtZCPS&e|XWWg5 znE~0;Nx|Z~ipSzUZpIb7$g+VM?E5cL0UsozVaj<9KU?ld8iwr2$}2SCAM9)E&$;$v z1iIPIt}MF7=x`e(^qZ={X>%NHQe z#;5Rd|Kcji+A6+q9BxzzEo+f^mxVVz`iA*SDBmmOSp$$E;@sZB70%psHSyiE?&}0o7|K6Ij2LZ*R z{cgfzWi=x_-Ozzf3o@XeRby1exKUnAY#4G1ZjWY%+NLM*1($B#kSyjLTl$!()( z-O3R?%=P0u>R7c@DPNHJ=(FUnl%5~-tYK4P;+QqBUV$-IZ*SvbeDDI|{2GX<~5L?0sLNH57P^5-9 z2SIA04p_MgqDL1SJB4X5G8y;VpvAg%OyId;#>(Jet=wEEWYe`G0@O04bf7((`Za3n zo}p7MdlSlVvP6DqNw`N~Yfha-R5OR)a})xZs>}+rv6YfUU+#c^K-PWH7u`B)^cd) z+ND87boTc4qT+i;I?$aNPj!w};KPABN+$NHLSDI$02*zRKa}L3#dMO*zUdl;AkvA5 zl1-ZJ(762wvq%w-%HKXR@0~3Oe~LEtt%<7T)^V#*j*GIlHpSelW-CU?sWKD$uGh1% zGRhi+6+>ngQW^Wp<-imt-q2psgw01v4P!5cSW1;3(TlsIY#gGddwU!yhO>O-h%FG8 zwpxV(J4QTws*G8V41=t#BL_I!uG9rfPx5orNn%UJE=9OZvLF`eTG{TFR*nBmz~3y- zhDSz7iwL!F4qbXro;=a=Biv~^ndQ>;tfGdc0ZO5-cy>6nUXEacPNxuT+p{K7<^Co_ znZR{dQqCs_y^D5G8{(w z=jT7dE}F#l7{f2{5Q-kgrH(ZI_Q_g4EGFJNz>%ky~C03Ywx z$QynAj6yIN?y;uXpD7UW2?r&JWc>X6KBbu3A08hAUcR*G3EgoHI-oJA(B;yver0ZM zZcKSAgJmF366!tct5B+*KPGuHEqm+!$Lxv!<{%am2VC2@ld-?hGcxkUDc*NMQgZT= zj10>DTyZ^I8;YO*Guz>_ej8l4YCp={`Ys3zz7C+14$6`Fi`+Xf>uYNTT@<%Ukk!?^ z%T|9;|34k_?|1+I-XZ^HA^*3}8x;Es?@|s%lCpaI{(k%D=tv{R&ZaYlO6l#}UzcYG z?DugUjB5=1gM)*Xy!`#JjFPOZtV85rU>vTMf5*`{`e0>{gOX75i(NqA-&?pfO!qI| zgX2|+B+Z}a)&l=2Fs6b@TK<^#ei<(SIs)`7V%Euqvc$bBm$^*}7CpltcH5&!g5E2B z^&xjXXsv)qIY|AaD-%Jz^v$$j6={x7U{o=DGJqJuCA^YIG4s-85Zr^giTX;ma7iu zn)h1{S6{*wH^xFF2chdNH(_F4$fHF=#ZUvTiMc9QVgC`4vMGgn`}ngB$V`(iFj*t9 zmvEgpUZbzjh3fnQ!=rdbVefY}5ICJTw=JK#1JG2$;asod*=5b8alaJZnIf?W1Ad;Q z?mC4;KE7H59}*la!!f>Wrpq{r>dUPgEt22`xqCPErPobfP2@!WTL&ad(7FxZE5KuI zUN&}0?ROM@T+#p?w~hDdb+wlV=h0}MoWOU9M%hO@D3<~7HC1EK_)2XIv<^5_Dw(=u zKf7Bu?ELQWk%wouv)Vf^gjQVipbaj0UuI(nZajIpcsHq%@xNP2H~Q^GGHiU=3j$SK zHj>BH#OzfLZd|8^-UOP1XMtD0p>}Q)D-O*w1u0eAnqA1mja>Jgv76}x{_4H}G%Y*H z#-8N1G9viLQ3Ji2^638A9ju$vX?Wg_gs>aZ92@l|gXd!ZO|heoG51cjbtCA!b*?IX z#C#k#4dD{5P1iwsUB42x_~>U>gg*qmK?FU0xGJ1|1AY1OrM$$lI0FOqF)b}LZ)I`z z09QYi*mX(-!+0L4p7f&c7ddw3dv51m&_;yi<>L*=Xy>R1SB;@{Y?O}X7`c$wc~!N1 zw$g$OS^RqYA3 zNKVPB*P;XK9(xMfD|dePmFr-!vy4>+D}1_`=?C;H={lz9=sKiWBnv}oF_P=zaRt^g zvK3K=PfHiSDIpt^CGy84SIk|1P38}t61iO>fKR1~KXD_+ z!pzCW?Czuci0_J$2S06^D9;iA!H3`S0L@0t`4WYjPsiW=lGtm+A8skznjuKNX|g?n z*>a?k`o1MIdpoY@oll9MU->d{8+X$4eqgvh|0*-@%Ctb&>qb9YD!qaM&9e#9innzh zZt>HFxU9g=J9vUha_6|T?XBKjN4Jg_I~N73F}EaL7y6XuT}{Hyz0wq0rgADb85(%} zx#!F0MrfP^^iF7Eqi)7{4m)X_jRPd$+?vDHOFVIB^nL?Z3##Xv6nXDXYH0&cCiB-O zbHfZLuRhmG>k0B_m|5Qfa`)&cB2*tZ^k96#@=yIt!j$^i^w7Sc2qAcxoqrj- zzh={gn*%eXY^mC?nVQjZ(GNo>^{tJ9o=3Xm?t;%erkJa|9N?6yskA;iI$Q*zQL*Pz z(HT=a`8>wuNc7X7&IHGFAsoFrpHNFwG+S`rDpD zOErAUNysg2Uy<89|w`P{AY^xXl z3hAn@j(Ms?CT7b2w9M4`XDSl@&Y*)kF&MXcE2YE#TE3J07wzC=sqRLXf*%nlo2Fi& zNsGyR8*_(_^N^60?Z|ZG#z*=~TyE#*KJnX$9xnc2rXs%a%@-r3DFPx%BG-AT!)BF3 z(oX*JVJ8&p+@2d<*gTCB6JNizh%o92!^Z7M;dQIwImn+#y;Kd~c$MZ*F_$-}6|?5z z9RL2%2T!Z~cgEj~q{dw~sCX*qt{YWJKrhkUoKLI5SjSgG)>#kjb&I$8VpF->$dJ66 z@`@}65?sa&yML5t=Be?~6oY~KJk>XP5Vni6S6s~}6#Ql)*JSd(N!JmGtHm7;^?^dy zs=?IEMNamisZN>H@jCVjPL1@ua3gfj#!?*nui5baP}y|SB^AML()6l*KsrA(mwMxn z3y6LRl2;_3-1M5{X||wuKbsfxPK6+P3u*&ZQK!j^?RUBMzvxW4GHwN8AWjL@v)6kU{F zA825Gb6#k=CB|pZcJQd_{6JPSAWbvWI3?XI_S5F_(;L2-_mfXVmi=wtq-mTNEMR8dABQCkp< zqdTo+^DbBd1adPw(OpV(@Qz4nc#UJy;YaO<@LJ!g(dFhJD1TH@J5dk4Gkw+D(qVa~ zRmzU`x7W$^XZJ&cjnGD&?MF)WBxbHiegQguudT#h#_p%!&y?kGoH8t)y|jK9vtE$9 zct&ZNk|1IcQQI}a6mR=xPzcwHl_Y*ae3jSN*Bpb#v_SQPAIxU;Mz-h4R`k+}%JSeJ zgp9Tl#MCiKpF%GVdNv5&diQHhgk>i2Y&vaAD6%dc9Ydv8Q`I$nd?v~)3AH99z<3H0 z`^P6xGmgXh8$;Fw?;ANH?6v&OW$DM5gFh+f-gBeU*Zq=Fqu;ObB3jBZLvysA-*4Z; zBUln0s=6*tmn?4$j`^k&%*#eJkTw%MKP@DPh0Se@DCUli1k+W74`mbHEwZY@ooYtW zuAIjV7Pa>?D@~??Aw58A@)*BK;dctrzK1dT0i&ad{ftZ-L*aW zpIcge8V07@8HH#epdt(h%xynnFI#a|>mE zwN032ba$nV%n7K(D!G3zl<{TA&Z43sOIXB%|5w|UhC|u5f2C5Qk|iahg~}tzQbIEd z(IESn5VB<}yJ*H(5+jr(Yt}GhSGFOIp`x;lCFaR4>&(cgSunQ$Jw4AC&-=U`y&wMb z<-X@SuH#&;^ICrA@4V(1VZPn)+B{s4&GvA5q@2{~r_k8(c;5Oh?)tM9wq*wW$x_RY z=XysZg5jfV^T!S6%dPzna<3?st@Gfo#|OD?lTQ^=q3J3r?d5j|6`MB+yvy`|#WN%d zD)XAq7_MLYfN=aG8sB%g@Sfm7U5G%9e&VG0A9Z(&DZRbg`4?l_pAKwVH8O?h)ui(;C zTyH+OdTPKVJzrzc?wq4d+cGeX#rI*tU*)`+g9BQq(!5h%qu8m=G<7ignLVqxICtd`kp~zSn|NrZLmHKnNWF5x57RY9zH;JfIFFyL(YyLU9oFjOG(NXx%rS5m z1C|JRCbyv;WGwU6kix|N0b6EY1TTd1RG$V=WjDf$9?l+*#4<*G-@<<6U%0Yk5A{o{ zF5dn|?gt6zQ+ZLdg;EKMOx!%2!5vcA*Cz7E4H{*^P=?u4PiHiy<@4?cw`4W%M}5bN znXN9P{bu9k$PG^8CS%rk<}?If;hDp`&TO+(34W#h*-gun)tqoxB=#N66#D5^01 zS@g{XnaiO(i-Q>+mw2iGq70rbQ+9%&iC}g#p~!9Wgc-r{WD0+Z%2vH)=DC z#!egG>QMcrs`AGHwc@^>s;gG50j_%HbwMYd+oy|}!QmMF6@IttBG{Vhxx`$642CTi z0egeOV3o_g`{`l|)h#(Wi@@Y$X$9?F(%W0pZ=2wp+;n1$rv{33tkWHR(T+O&>%8~!O`S9RG`5U?`5H2b<%-`h3&jsxReVOojX6?JZlss ztwoeOF^O1&06Yn&aMycgX@4+wkqK#LK_SQqtT4XGdFk2AQq8z)-Nm2~_3cepykoAh zf264ig40rK6aAKxM(3IJaoL zEta}5x2AZ71PGkY=f~vk-dHwau>GL;D^DDPEGeQ3?#+(`X z4{7^?!^oaV(B`-^#)G8e%v6isnU`}}>nQ^us~5CUuUS&)Y*D@s2SD{+ z21nWY)5og8HCOZ7G$KVZk!Xs96>z=wY(x()AU^by&Mw_hcc-PmJWCKS>`yDK-)Lt5 zbLN#uMG9o^G)IZr4LrHYj{aPDh~ecUgT2?D|nCHjYR7?`|IUn1c#eRlm_B1cIc<#FMLR zSz*p<+(}rPeHo&vOUxH#TKeJ|CX|b3dvWelLlz3NZ-zdM^!6gxOZo)`zir9LNzAI% zv|ayvxHMhO%8o)JXWEEgoHXr_p?w0|7x+ibN$iF9pY$+YUHwuK*?Gu$c}osm6Xun5 z#r*|;Mdv(;9I(oslEE?)9%g#E)HZBX*F{UL5}TpMZhD8@o9F{;xi~Y{^tR4nN2AuX zoldfff3zs*X*0=HIC%M5XK~tSX0O_et21CUXA8OS@03@gL+mFz(5T5D!g-&o>15Tl zm3ZoiIhLyBM0#^C=%Y^D30s$LIxv8>3UuWtkHT;E>&req&wpA1rMs6zP&>vY_M)Sxv&OA29U{I$1mS&(Z0$r6 zdK3=0Olfhy-bg=`wvlJ6^Bl&2h8swHrxdCOowbjzhj^p=<| z+l`x0c5MIQdc+JbRV-;Zr~IU-z7CZaI}0rPhW4BSom=xInzc9xvT$k9zj z=2vSnQtLevU~2;#6mrg(40HzBx6otZ54BwVezr9IT-BQT-rWs5di96xQuDVb?W^0H z(L0z{2y2T~xN$uwI0aJg70KwdKzUwYNR(Wp8BkMkZ1vR_9sGSWw6wxT`K(L`=(Bi^ zA{u;O)o(2Qu`9+rcu2_)1X$K68=YyZzk7ZnOwTjkuK`W~k6@VsmDN7MQGOI3%@}@5 zl>m$+!3OCY3+gnbQO6F(*dODI-j!%0!S`WD+hM2DM@9n*;UdI31~U87Y!?{GPv@`D zL#!;VIPe{Xl#>h@(B0}ow5NRZYtiwJZ`?C8R|bSd_%aHOT<5HeINJ*l=^wFh7uOb< zk^{2`k=N%fLI`&UOHYE6Slq%I<$QLftlx;(LmaiU0%{o6tln74FoT!Cgq$2j$7g=*kFKbh zMxJEbuF+yp+6lmborK17KX`by=D5~q$W=x)DY=hT)0^bq<~s6aNRxZG4&O>UT4)$X zho=}(f{dJrdmjuMCFFH)3G8nVn-Ts@ZX$`4RGpI2P_5Z`0BTrL8*6f~zNoW3_k6c6 zq##uC-I#2&cBW?3+tU*3ayt=g+#iIBAb1vfaaS!T0KyB;ZEqlVs!fqz?Ul6Pi^j#` z+wV7PTS#p;SnfO5QW`MVtvxKy{$#PE`3muwpAEX~!gHVUJsFe)N2ArRsmTqu>#h|a zlguE);KWPUtMFR7}FxAm4i?!h~2hyF$5D_jt z++ZIy&wd7T6)+i7Cl)b3C+;~?utq@IV$W$p-Ai;2f*PGW`e$gnO=I&MLN2HU7UyOg zAXlV1KDRny1n_;4E|t;qAcs)a!%Fs))mqPeBjI5%^8Gdwmf>|~*IVg8nG6J+c$l0p zJ%o{Sj&#p=Wo$ia`SOCkbobFJW5Cp*AEK;SYPO-=JS0Ca{T_QRBo)in=}`6i%ALW| zvrGD7sWO`V^2?ekt3?_d>@qjn0$L$Lnw_-@*9B?R?0^LbA)qtq`;ZC@@5hS9sXWcg zRA03iz4xvlgzZ?+kl|@G@H`lg3XT+!Yq<7ZK+%sSUfw`&?OM3Ccr=R@qG|%&b-s^? zvRyG`w7JNia!tJ)<}kxxS^H`;*MqYolRIY>znDwqhv+k9h~(;~mDLlnnK=%gs3X+3 zUnG2niPUC{x~r2xUjL{HTs=@ye?vq(TA>4>aRfVA1 zYMjo7(MjQ9=Wgd0n$_!_VNQz#AB}UKBbW^oDP51%g&e}ZeGL&Fa_&xR@;4w%kmg%@ z*}$L2A?7vr5}qPP;LR*`3NEYSlzTo@MjdqCYs7iQZ$PYz&VyileSUf1B;b+9y`x|- zI7lJ$7#@$0j*3d@akx6f-oW^6uncv`bwar|?sus&JZu-C-s^)7dZ&Ohxe=!NH?m97 zSe^a}NjC$VMx_rA;3+2a@Qs4^@WP)6SuEzCx8eZZobmkm*bMbHgQZ_Vy`;RYC0tzG z6;Q3qX26--Smj?IuPzLT1R(DT7PS81v70yK>HI=}ZEHhsK)MR10Ce+wO3MaNEvMIX z^)z9q?2g5GRF8+fi_Dqt(0b@7aXIBH&G7-pG!GBX@LX;^dk%p_3JVBaJ_ Date: Wed, 18 Jan 2017 10:04:19 -0500 Subject: [PATCH 08/27] meta: add test targets to makefile --- Makefile | 54 +- client/app.js | 4 +- knexfile.js | 16 +- migrations/20170116181958_add_taxes_table.js | 8 +- ...0116182027_add_expense_categories_table.js | 8 +- .../20170116182035_add_employees_table.js | 8 +- .../20170116182042_add_expenses_table.js | 8 +- package.json | 4 +- tests/system/import.js | 12 + tests/unit/csv_helper.js | 0 yarn.lock | 809 +++++++++++++++++- 11 files changed, 844 insertions(+), 87 deletions(-) create mode 100644 tests/system/import.js create mode 100644 tests/unit/csv_helper.js diff --git a/Makefile b/Makefile index 218cf3573..fa59b2fe5 100644 --- a/Makefile +++ b/Makefile @@ -1,31 +1,53 @@ -# Start the application server -run: +PATH := ./node_modules/.bin:$(PATH) + +# Use variables with defaults to allow overriding on system where +# node or yarn are not on $PATH +NODE := node +YARN := yarn +TAP := tap +TAPE := tape +TAPSPEC := tap-spec +STANDARD := standard + +run: ## Start the application server node --harmony server.js | ./node_modules/.bin/merry -# Installs all required dependencies -deps: +help: ## Show available targets + @printf "$(shell tput -Txterm setaf 2)" + @egrep '^(.+)\:\ ##\ (.+)' ${MAKEFILE_LIST} | column -t -c 2 -s ':#' + @printf "$(shell tput -Txterm sgr0)" + +deps: ## Installs all required dependencies yarn -# Ensures your code follows the [standard](https://github.com/feross/standard) -lint: - ./node_modules/.bin/standard --fix +# See https://github.com/feross/standard +lint: ## Ensures your code follows the "standard" + $(STANDARD) --fix + +test-unit: ## Run unit tests + $(TAP) tests/unit/*.js | $(TAPSPEC) -# Creates a new database for the application to use (run once) -db-create: +test-integration: ## Run integration tests + $(TAP) tests/integration/*.js | $(TAPSPEC) + +test-system: ## Run system tests + $(TAPE) tests/system/*.js | $(TAPSPEC) + +test: ## Run all tests including style checks +test: lint test-unit test-integration test-system + +db-create: ## Creates a new database for the application to use (run once) psql -c "CREATE ROLE wave_challenge WITH SUPERUSER LOGIN PASSWORD 'wave_challenge'" psql -c "CREATE DATABASE wave_challenge WITH OWNER wave_challenge" -# Runs all pending migrations againt the database -db-migrate: +db-migrate: ## Runs all pending migrations againt the database ./node_modules/.bin/knex migrate:latest -# Reverts the last migration -db-rollback: +db-rollback: ## Reverts the last migration ./node_modules/.bin/knex migrate:rollback -# Create a new migration file, call passing in a NAME for the file: +# Call passing in a NAME for the migration file, ex: # # make db-create-migration NAME=add-users-table -db-create-migration: +db-create-migration: ## Create a new migration file ./node_modules/.bin/knex migrate:make $(NAME) - diff --git a/client/app.js b/client/app.js index 34ba55ca5..5b2d0a23a 100644 --- a/client/app.js +++ b/client/app.js @@ -68,6 +68,6 @@ function mainView (state, prev, send) { app.router(['/', mainView]) var tree = app.start() -var appEl = document.getElementById('app'); -appEl.innerHTML = ''; +var appEl = document.getElementById('app') +appEl.innerHTML = '' appEl.appendChild(tree) diff --git a/knexfile.js b/knexfile.js index 7bd5d4683..569ecd73c 100644 --- a/knexfile.js +++ b/knexfile.js @@ -1,13 +1,13 @@ module.exports = { - client: "postgresql", + client: 'postgresql', connection: process.env.DATABASE_URL || { - database: "wave_challenge", - user: "wave_challenge", - password: "wave_challenge", + database: 'wave_challenge', + user: 'wave_challenge', + password: 'wave_challenge' }, pool: {min: 2, max: 10}, migrations: { - tableName: "migrations", - directory: "./migrations", - }, -}; + tableName: 'migrations', + directory: './migrations' + } +} diff --git a/migrations/20170116181958_add_taxes_table.js b/migrations/20170116181958_add_taxes_table.js index b46a93fbf..cbf9ca0c0 100644 --- a/migrations/20170116181958_add_taxes_table.js +++ b/migrations/20170116181958_add_taxes_table.js @@ -7,9 +7,9 @@ exports.up = function (knex, Promise) { t.index(['name', 'year']) t.unique(['name', 'year']) - }); -}; + }) +} exports.down = function (knex, Promise) { - return knex.schema.dropTable('taxes'); -}; + return knex.schema.dropTable('taxes') +} diff --git a/migrations/20170116182027_add_expense_categories_table.js b/migrations/20170116182027_add_expense_categories_table.js index fa73e349c..73d8dab89 100644 --- a/migrations/20170116182027_add_expense_categories_table.js +++ b/migrations/20170116182027_add_expense_categories_table.js @@ -2,9 +2,9 @@ exports.up = function (knex, Promise) { return knex.schema.createTable('expense_categories', function (t) { t.string('id', 26).notNullable().primary() t.text('name').notNullable() - }); -}; + }) +} exports.down = function (knex, Promise) { - return knex.schema.dropTable('expense_categories'); -}; + return knex.schema.dropTable('expense_categories') +} diff --git a/migrations/20170116182035_add_employees_table.js b/migrations/20170116182035_add_employees_table.js index fa9958d77..1d01f5344 100644 --- a/migrations/20170116182035_add_employees_table.js +++ b/migrations/20170116182035_add_employees_table.js @@ -3,9 +3,9 @@ exports.up = function (knex, Promise) { t.string('id', 26).notNullable().primary() t.text('name').notNullable() t.text('address').notNullable() - }); -}; + }) +} exports.down = function (knex, Promise) { - return knex.schema.dropTable('employees'); -}; + return knex.schema.dropTable('employees') +} diff --git a/migrations/20170116182042_add_expenses_table.js b/migrations/20170116182042_add_expenses_table.js index b624739c4..c18f7e006 100644 --- a/migrations/20170116182042_add_expenses_table.js +++ b/migrations/20170116182042_add_expenses_table.js @@ -7,9 +7,9 @@ exports.up = function (knex, Promise) { t.string('tax_id', 26).notNullable().references('id').inTable('taxes') t.text('description').notNullable() t.integer('amount').notNullable() - }); -}; + }) +} exports.down = function (knex, Promise) { - return knex.schema.dropTable('expenses'); -}; + return knex.schema.dropTable('expenses') +} diff --git a/package.json b/package.json index 3b7a6ae2b..54647f0b6 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,8 @@ "pg": "^6.1.2" }, "devDependencies": { - "standard": "^8.6.0" + "standard": "^8.6.0", + "tap": "^9.0.3", + "tap-spec": "^4.1.1" } } diff --git a/tests/system/import.js b/tests/system/import.js new file mode 100644 index 000000000..a6a6bc9d6 --- /dev/null +++ b/tests/system/import.js @@ -0,0 +1,12 @@ +var test = require('tape') + +test('timing test', function (t) { + t.plan(2) + + t.equal(typeof Date.now, 'function') + var start = Date.now() + + setTimeout(function () { + t.equal(Date.now() - start, 100) + }, 100) +}) diff --git a/tests/unit/csv_helper.js b/tests/unit/csv_helper.js new file mode 100644 index 000000000..e69de29bb diff --git a/yarn.lock b/yarn.lock index a1f1a8c79..fdce9f1ac 100644 --- a/yarn.lock +++ b/yarn.lock @@ -93,10 +93,20 @@ ap@~0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/ap/-/ap-0.2.0.tgz#ae0942600b29912f0d2b14ec60c45e8f330b6110" +append-transform@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/append-transform/-/append-transform-0.4.0.tgz#d76ebf8ca94d276e247a36bad44a4b74ab611991" + dependencies: + default-require-extensions "^1.0.0" + aproba@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.0.4.tgz#2713680775e7614c8ba186c065d4e2e52d1072c0" +archy@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40" + are-we-there-yet@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.2.tgz#80e470e95a084794fe1899262c5667c6e88de1b3" @@ -146,7 +156,7 @@ array-unique@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" -arrify@^1.0.0: +arrify@^1.0.0, arrify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" @@ -186,6 +196,10 @@ async-each@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" +async@^1.4.0, async@^1.4.2: + version "1.5.2" + resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" + async@~0.2.6: version "0.2.10" resolved "https://registry.yarnpkg.com/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1" @@ -202,7 +216,7 @@ aws4@^1.2.1: version "1.5.0" resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.5.0.tgz#0a29ffb79c31c9e712eeb087e8e7a64b4a56d755" -babel-code-frame@^6.16.0: +babel-code-frame@^6.16.0, babel-code-frame@^6.20.0: version "6.20.0" resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.20.0.tgz#b968f839090f9a8bc6d41938fb96cb84f7387b26" dependencies: @@ -210,13 +224,68 @@ babel-code-frame@^6.16.0: esutils "^2.0.2" js-tokens "^2.0.0" -babel-runtime@^6.11.6: +babel-generator@^6.18.0: + version "6.21.0" + resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.21.0.tgz#605f1269c489a1c75deeca7ea16d43d4656c8494" + dependencies: + babel-messages "^6.8.0" + babel-runtime "^6.20.0" + babel-types "^6.21.0" + detect-indent "^4.0.0" + jsesc "^1.3.0" + lodash "^4.2.0" + source-map "^0.5.0" + +babel-messages@^6.8.0: + version "6.8.0" + resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.8.0.tgz#bf504736ca967e6d65ef0adb5a2a5f947c8e0eb9" + dependencies: + babel-runtime "^6.0.0" + +babel-runtime@^6.0.0, babel-runtime@^6.11.6, babel-runtime@^6.20.0, babel-runtime@^6.9.0: version "6.20.0" resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.20.0.tgz#87300bdcf4cd770f09bf0048c64204e17806d16f" dependencies: core-js "^2.4.0" regenerator-runtime "^0.10.0" +babel-template@^6.16.0: + version "6.16.0" + resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.16.0.tgz#e149dd1a9f03a35f817ddbc4d0481988e7ebc8ca" + dependencies: + babel-runtime "^6.9.0" + babel-traverse "^6.16.0" + babel-types "^6.16.0" + babylon "^6.11.0" + lodash "^4.2.0" + +babel-traverse@^6.16.0, babel-traverse@^6.18.0: + version "6.21.0" + resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.21.0.tgz#69c6365804f1a4f69eb1213f85b00a818b8c21ad" + dependencies: + babel-code-frame "^6.20.0" + babel-messages "^6.8.0" + babel-runtime "^6.20.0" + babel-types "^6.21.0" + babylon "^6.11.0" + debug "^2.2.0" + globals "^9.0.0" + invariant "^2.2.0" + lodash "^4.2.0" + +babel-types@^6.16.0, babel-types@^6.18.0, babel-types@^6.21.0: + version "6.21.0" + resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.21.0.tgz#314b92168891ef6d3806b7f7a917fdf87c11a4b2" + dependencies: + babel-runtime "^6.20.0" + esutils "^2.0.2" + lodash "^4.2.0" + to-fast-properties "^1.0.1" + +babylon@^6.11.0, babylon@^6.13.0: + version "6.15.0" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.15.0.tgz#ba65cfa1a80e1759b0e89fb562e27dccae70348e" + balanced-match@^0.4.1: version "0.4.2" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" @@ -289,13 +358,19 @@ bl@^1.1.2: dependencies: readable-stream "^2.0.5" +bl@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/bl/-/bl-1.1.2.tgz#fdca871a99713aa00d19e3bbba41c44787a65398" + dependencies: + readable-stream "~2.0.5" + block-stream@*: version "0.0.9" resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" dependencies: inherits "~2.0.0" -bluebird@^3.4.6: +bluebird@^3.3.1, bluebird@^3.4.6: version "3.4.7" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.4.7.tgz#f72d760be09b7f76d08ed8fae98b289a8d05fab3" @@ -505,6 +580,10 @@ buffer@^4.1.0: ieee754 "^1.1.4" isarray "^1.0.0" +builtin-modules@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" + builtin-status-codes@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" @@ -524,6 +603,14 @@ cached-path-relative@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/cached-path-relative/-/cached-path-relative-1.0.0.tgz#d1094c577fbd9a8b8bd43c96af6188aa205d05f4" +caching-transform@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/caching-transform/-/caching-transform-1.0.1.tgz#6dbdb2f20f8d8fbce79f3e94e9d1742dcdf5c0a1" + dependencies: + md5-hex "^1.2.0" + mkdirp "^0.5.1" + write-file-atomic "^1.1.4" + call-matcher@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/call-matcher/-/call-matcher-1.0.1.tgz#5134d077984f712a54dad3cbf62de28dce416ca8" @@ -547,6 +634,10 @@ camelcase@^1.0.2: version "1.2.1" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" +camelcase@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" + caseless@~0.11.0: version "0.11.0" resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.11.0.tgz#715b96ea9841593cc33067923f5ec60ebda4f7d7" @@ -615,6 +706,10 @@ circular-json@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.1.tgz#be8b36aefccde8b3ca7aa2d6afc07a37242c0d2d" +clean-yaml-object@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/clean-yaml-object/-/clean-yaml-object-0.1.0.tgz#63fb110dc2ce1a84dc21f6d9334876d010ae8b68" + cli-cursor@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" @@ -633,6 +728,14 @@ cliui@^2.1.0: right-align "^0.1.1" wordwrap "0.0.2" +cliui@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + wrap-ansi "^2.0.0" + co@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" @@ -641,6 +744,10 @@ code-point-at@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" +color-support@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.2.tgz#49cc99b89d1bdef1292e9d9323c66971a33eb89d" + combine-errors@3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/combine-errors/-/combine-errors-3.0.1.tgz#79a04c22db8a6c5846a951dc41e8838f92e1c1e9" @@ -681,6 +788,10 @@ commander@^2.2.0, commander@^2.9.0: dependencies: graceful-readlink ">= 1.0.0" +commondir@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" + component-type@1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/component-type/-/component-type-1.2.1.tgz#8a47901700238e4fc32269771230226f24b415a9" @@ -737,6 +848,10 @@ convert-source-map@^1.1.1, convert-source-map@~1.1.0: version "1.1.3" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.1.3.tgz#4829c877e9fe49b3161f3bf3673888e204699860" +convert-source-map@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.3.0.tgz#e9f3e9c6e2728efc2676696a70eb382f73106a67" + core-js@^2.0.0, core-js@^2.4.0: version "2.4.1" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.4.1.tgz#4de911e667b0eae9124e34254b53aea6fc618d3e" @@ -751,6 +866,16 @@ corsify@^2.1.0: dependencies: http-methods "~0.1.0" +coveralls@^2.11.2: + version "2.11.15" + resolved "https://registry.yarnpkg.com/coveralls/-/coveralls-2.11.15.tgz#37d3474369d66c14f33fa73a9d25cee6e099fca0" + dependencies: + js-yaml "3.6.1" + lcov-parse "0.0.10" + log-driver "1.2.5" + minimist "1.2.0" + request "2.75.0" + create-ecdh@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.0.tgz#888c723596cdf7612f6498233eebd7a35301737d" @@ -781,6 +906,13 @@ create-html@^1.1.0: exit "^0.1.2" minimist "^1.2.0" +cross-spawn@^4: + version "4.0.2" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-4.0.2.tgz#7b9247621c23adfdd3856004a823cbe397424d41" + dependencies: + lru-cache "^4.0.1" + which "^1.2.9" + cryptiles@2.x.x: version "2.0.5" resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" @@ -831,11 +963,11 @@ date-now@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" -debug-log@^1.0.0: +debug-log@^1.0.0, debug-log@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/debug-log/-/debug-log-1.0.1.tgz#2307632d4c04382b8df8a32f70b895046d52745f" -debug@^2.1.1, debug@^2.1.3: +debug@^2.1.1, debug@^2.1.3, debug@^2.2.0: version "2.6.0" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.0.tgz#bc596bcabe7617f11d9fa15361eded5608b8499b" dependencies: @@ -847,7 +979,7 @@ debug@~2.2.0: dependencies: ms "0.7.1" -decamelize@^1.0.0: +decamelize@^1.0.0, decamelize@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" @@ -863,6 +995,16 @@ deep-is@~0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" +deeper@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/deeper/-/deeper-2.1.0.tgz#bc564e5f73174fdf201e08b00030e8a14da74368" + +default-require-extensions@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/default-require-extensions/-/default-require-extensions-1.0.0.tgz#f37ea15d3e13ffd9b437d33e1a75b5fb97874cb8" + dependencies: + strip-bom "^2.0.0" + defined@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" @@ -920,6 +1062,12 @@ detect-file@^0.1.0: dependencies: fs-exists-sync "^0.1.0" +detect-indent@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" + dependencies: + repeating "^2.0.0" + detective@^4.0.0: version "4.3.2" resolved "https://registry.yarnpkg.com/detective/-/detective-4.3.2.tgz#77697e2e7947ac3fe7c8e26a6d6f115235afa91c" @@ -927,6 +1075,10 @@ detective@^4.0.0: acorn "^3.1.0" defined "^1.0.0" +diff@^1.3.2: + version "1.4.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-1.4.0.tgz#7f28d2eb9ee7b15a97efd89ce63dcfdaa3ccbabf" + diffie-hellman@^5.0.0: version "5.0.2" resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.2.tgz#b5835739270cfe26acf632099fded2a07f209e5e" @@ -968,6 +1120,10 @@ duplexer2@~0.0.2: dependencies: readable-stream "~1.1.9" +duplexer@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1" + ecc-jsbn@~0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" @@ -1003,6 +1159,12 @@ envvar@1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/envvar/-/envvar-1.1.0.tgz#c25a0866edae87046d976c8db037489551639b94" +error-ex@^1.2.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.0.tgz#e67b43f3e82c96ea3a584ffee0b9fc3325d802d9" + dependencies: + is-arrayish "^0.2.1" + es5-ext@^0.10.7, es5-ext@^0.10.8, es5-ext@~0.10.11, es5-ext@~0.10.2, es5-ext@~0.10.7: version "0.10.12" resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.12.tgz#aa84641d4db76b62abba5e45fd805ecbab140047" @@ -1055,7 +1217,7 @@ es6-weak-map@^2.0.1: es6-iterator "2" es6-symbol "3" -escape-string-regexp@^1.0.0, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: +escape-string-regexp@^1.0.0, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.3, escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" @@ -1227,6 +1389,10 @@ event-emitter@~0.3.4: d "~0.1.1" es5-ext "~0.10.7" +events-to-array@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/events-to-array/-/events-to-array-1.0.2.tgz#b3484465534fe4ff66fbdd1a83b777713ba404aa" + events@^1.0.2, events@~1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" @@ -1306,7 +1472,7 @@ fast-safe-stringify@^1.0.8, fast-safe-stringify@^1.1.3, fast-safe-stringify@~1.1 version "1.1.3" resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-1.1.3.tgz#f23370808fe5ab243fa1fdee2e9ab3041c8cb884" -figures@^1.3.5: +figures@^1.3.5, figures@^1.4.0: version "1.7.0" resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" dependencies: @@ -1334,10 +1500,25 @@ fill-range@^2.1.0: repeat-element "^1.1.2" repeat-string "^1.5.2" +find-cache-dir@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-0.1.1.tgz#c8defae57c8a52a8a784f9e31c57c742e993a0b9" + dependencies: + commondir "^1.0.1" + mkdirp "^0.5.1" + pkg-dir "^1.0.0" + find-root@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/find-root/-/find-root-1.0.0.tgz#962ff211aab25c6520feeeb8d6287f8f6e95807a" +find-up@^1.0.0, find-up@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" + dependencies: + path-exists "^2.0.0" + pinkie-promise "^2.0.0" + findup-sync@^0.4.2: version "0.4.3" resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-0.4.3.tgz#40043929e7bc60adf0b7f4827c4c6e75a0deca12" @@ -1382,10 +1563,25 @@ foreach@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" +foreground-child@^1.3.3, foreground-child@^1.5.3: + version "1.5.6" + resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-1.5.6.tgz#4fd71ad2dfde96789b980a5c0a295937cb2f5ce9" + dependencies: + cross-spawn "^4" + signal-exit "^3.0.0" + forever-agent@~0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" +form-data@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.0.0.tgz#6f0aebadcc5da16c13e1ecc11137d85f9b883b25" + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.5" + mime-types "^2.1.11" + form-data@~2.1.1: version "2.1.2" resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.2.tgz#89c3534008b97eada4cbb157d58f6f5df025eae4" @@ -1490,6 +1686,10 @@ generic-pool@^2.4.2: version "2.5.0" resolved "https://registry.yarnpkg.com/generic-pool/-/generic-pool-2.5.0.tgz#3527229cf4bca1fc40853570dd30541b92442cbe" +get-caller-file@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5" + get-stdin@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-5.0.1.tgz#122e161591e21ff4c52530305693f20e6393a398" @@ -1513,7 +1713,7 @@ glob-parent@^2.0.0: dependencies: is-glob "^2.0.0" -glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.1.0: +glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.0.6, glob@^7.1.0: version "7.1.1" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" dependencies: @@ -1547,7 +1747,7 @@ global@^4.3.0, global@~4.3.0: min-document "^2.19.0" process "~0.5.1" -globals@^9.2.0: +globals@^9.0.0, globals@^9.2.0: version "9.14.0" resolved "https://registry.yarnpkg.com/globals/-/globals-9.14.0.tgz#8859936af0038741263053b39d0e76ca241e4034" @@ -1562,7 +1762,7 @@ globby@^5.0.0: pify "^2.0.0" pinkie-promise "^2.0.0" -graceful-fs@^4.1.2: +graceful-fs@^4.1.11, graceful-fs@^4.1.2: version "4.1.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" @@ -1570,6 +1770,16 @@ graceful-fs@^4.1.2: version "1.0.1" resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" +handlebars@^4.0.3: + version "4.0.6" + resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.6.tgz#2ce4484850537f9c97a8026d5399b935c4ed4ed7" + dependencies: + async "^1.4.0" + optimist "^0.6.1" + source-map "^0.4.4" + optionalDependencies: + uglify-js "^2.6" + har-validator@~2.0.6: version "2.0.6" resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-2.0.6.tgz#cdcbc08188265ad119b6a5a7c8ab70eecfb5d27d" @@ -1641,6 +1851,10 @@ homedir-polyfill@^1.0.0: dependencies: parse-passwd "^1.0.0" +hosted-git-info@^2.1.4: + version "2.1.5" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.1.5.tgz#0ba81d90da2e25ab34a332e6ec77936e1598118b" + htmlescape@^1.1.0: version "1.1.1" resolved "https://registry.yarnpkg.com/htmlescape/-/htmlescape-1.1.1.tgz#3a03edc2214bca3b66424a3e7959349509cb0351" @@ -1783,6 +1997,20 @@ interpret@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.1.tgz#d579fb7f693b858004947af39fa0db49f795602c" +invariant@^2.2.0: + version "2.2.2" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360" + dependencies: + loose-envify "^1.0.0" + +invert-kv@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + is-binary-path@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" @@ -1793,6 +2021,12 @@ is-buffer@^1.0.2, is-buffer@^1.1.0: version "1.1.4" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.4.tgz#cfc86ccd5dc5a52fa80489111c6920c457e2d98b" +is-builtin-module@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" + dependencies: + builtin-modules "^1.0.0" + is-dotfile@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.2.tgz#2c132383f39199f8edc268ca01b9b007d205cc4d" @@ -1811,7 +2045,7 @@ is-extglob@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" -is-finite@^1.0.1: +is-finite@^1.0.0, is-finite@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" dependencies: @@ -1890,6 +2124,10 @@ is-typedarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" +is-utf8@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" + is-windows@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-0.2.0.tgz#de1aa6d63ea29dd248737b69f1ff8b8002d2108c" @@ -1902,7 +2140,7 @@ isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" -isexe@^1.1.1: +isexe@^1.0.0, isexe@^1.1.1: version "1.1.2" resolved "https://registry.yarnpkg.com/isexe/-/isexe-1.1.2.tgz#36f3e22e60750920f5e7241a476a8c6a42275ad0" @@ -1916,6 +2154,54 @@ isstream@~0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" +istanbul-lib-coverage@^1.0.0, istanbul-lib-coverage@^1.0.0-alpha, istanbul-lib-coverage@^1.0.0-alpha.0, istanbul-lib-coverage@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-1.0.1.tgz#f263efb519c051c5f1f3343034fc40e7b43ff212" + +istanbul-lib-hook@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-hook/-/istanbul-lib-hook-1.0.0.tgz#fc5367ee27f59268e8f060b0c7aaf051d9c425c5" + dependencies: + append-transform "^0.4.0" + +istanbul-lib-instrument@^1.4.2: + version "1.4.2" + resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-1.4.2.tgz#0e2fdfac93c1dabf2e31578637dc78a19089f43e" + dependencies: + babel-generator "^6.18.0" + babel-template "^6.16.0" + babel-traverse "^6.18.0" + babel-types "^6.18.0" + babylon "^6.13.0" + istanbul-lib-coverage "^1.0.0" + semver "^5.3.0" + +istanbul-lib-report@^1.0.0-alpha.3: + version "1.0.0-alpha.3" + resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-1.0.0-alpha.3.tgz#32d5f6ec7f33ca3a602209e278b2e6ff143498af" + dependencies: + async "^1.4.2" + istanbul-lib-coverage "^1.0.0-alpha" + mkdirp "^0.5.1" + path-parse "^1.0.5" + rimraf "^2.4.3" + supports-color "^3.1.2" + +istanbul-lib-source-maps@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-1.1.0.tgz#9d429218f35b823560ea300a96ff0c3bbdab785f" + dependencies: + istanbul-lib-coverage "^1.0.0-alpha.0" + mkdirp "^0.5.1" + rimraf "^2.4.4" + source-map "^0.5.3" + +istanbul-reports@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-1.0.0.tgz#24b4eb2b1d29d50f103b369bd422f6e640aa0777" + dependencies: + handlebars "^4.0.3" + iterators@~0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/iterators/-/iterators-0.1.0.tgz#d03f666ca4e6130138565997cacea54164203156" @@ -1936,7 +2222,18 @@ js-tokens@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-2.0.0.tgz#79903f5563ee778cc1162e6dcf1a0027c97f9cb5" -js-yaml@^3.5.1: +js-tokens@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.0.tgz#a2f2a969caae142fb3cd56228358c89366957bd1" + +js-yaml@3.6.1: + version "3.6.1" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.6.1.tgz#6e5fe67d8b205ce4d22fad05b7781e8dadcc4b30" + dependencies: + argparse "^1.0.7" + esprima "^2.6.0" + +js-yaml@^3.2.7, js-yaml@^3.3.1, js-yaml@^3.5.1: version "3.7.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.7.0.tgz#5c967ddd837a9bfdca5f2de84253abe8a1c03b80" dependencies: @@ -1947,6 +2244,10 @@ jsbn@~0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.0.tgz#650987da0dd74f4ebf5a11377a2aa2d273e97dfd" +jsesc@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" + json-schema@0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" @@ -2034,6 +2335,16 @@ lazy-cache@^1.0.3: version "1.0.4" resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" +lcid@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" + dependencies: + invert-kv "^1.0.0" + +lcov-parse@0.0.10: + version "0.0.10" + resolved "https://registry.yarnpkg.com/lcov-parse/-/lcov-parse-0.0.10.tgz#1b0b8ff9ac9c7889250582b70b71315d9da6d9a3" + levn@^0.3.0, levn@~0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" @@ -2057,6 +2368,16 @@ liftoff@~2.2.0: rechoir "^0.6.2" resolve "^1.1.7" +load-json-file@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" + 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" + localenv@0.2.2: version "0.2.2" resolved "https://registry.yarnpkg.com/localenv/-/localenv-0.2.2.tgz#c508f29d3485bdc9341d3ead17f61c5abd1b0bab" @@ -2067,20 +2388,57 @@ lodash.memoize@~3.0.3: version "3.0.4" resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-3.0.4.tgz#2dcbd2c287cbc0a55cc42328bd0c736150d53e3f" -lodash@^4.0.0, lodash@^4.3.0, lodash@^4.6.0: +lodash@^3.6.0: + version "3.10.1" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" + +lodash@^4.0.0, lodash@^4.2.0, lodash@^4.3.0, lodash@^4.6.0: version "4.17.4" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" +log-driver@1.2.5: + version "1.2.5" + resolved "https://registry.yarnpkg.com/log-driver/-/log-driver-1.2.5.tgz#7ae4ec257302fd790d557cb10c97100d857b0056" + longest@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" +loose-envify@^1.0.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848" + dependencies: + js-tokens "^3.0.0" + +lru-cache@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.0.2.tgz#1d17679c069cda5d040991a09dbc2c0db377e55e" + dependencies: + pseudomap "^1.0.1" + yallist "^2.0.0" + map-limit@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/map-limit/-/map-limit-0.0.1.tgz#eb7961031c0f0e8d001bf2d56fab685d58822f38" dependencies: once "~1.3.0" +md5-hex@^1.2.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/md5-hex/-/md5-hex-1.3.0.tgz#d2c4afe983c4370662179b8cad145219135046c4" + dependencies: + md5-o-matic "^0.1.1" + +md5-o-matic@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/md5-o-matic/-/md5-o-matic-0.1.1.tgz#822bccd65e117c514fab176b25945d54100a03c3" + +merge-source-map@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/merge-source-map/-/merge-source-map-1.0.3.tgz#da1415f2722a5119db07b14c4f973410863a2abf" + dependencies: + source-map "^0.5.3" + merry@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/merry/-/merry-4.1.0.tgz#a6a6c138770c79c68f8cb75a0cd1ceb97b18bb3c" @@ -2106,7 +2464,7 @@ methods@^1.1.1: version "1.1.2" resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" -micromatch@^2.1.5, micromatch@^2.3.7: +micromatch@^2.1.5, micromatch@^2.3.11, micromatch@^2.3.7: version "2.3.11" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" dependencies: @@ -2135,7 +2493,7 @@ mime-db@~1.26.0: version "1.26.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.26.0.tgz#eaffcd0e4fc6935cf8134da246e2e6c35305adff" -mime-types@^2.1.12, mime-types@~2.1.7: +mime-types@^2.1.11, mime-types@^2.1.12, mime-types@~2.1.7: version "2.1.14" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.14.tgz#f7ef7d97583fcaf3b7d282b6f8b5679dab1e94ee" dependencies: @@ -2157,11 +2515,11 @@ minimatch@^3.0.0, minimatch@^3.0.2: dependencies: brace-expansion "^1.0.0" -minimist@0.0.8: +minimist@0.0.8, minimist@~0.0.1: version "0.0.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" -minimist@^1.1.0, minimist@^1.2.0: +minimist@1.2.0, minimist@^1.1.0, minimist@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" @@ -2249,7 +2607,7 @@ node-pre-gyp@^0.6.29: tar "~2.2.1" tar-pack "~3.3.0" -node-uuid@^1.4.7: +node-uuid@^1.4.7, node-uuid@~1.4.7: version "1.4.7" resolved "https://registry.yarnpkg.com/node-uuid/-/node-uuid-1.4.7.tgz#6da5a17668c4b3dd59623bda11cf7fa4c1f60a6f" @@ -2259,6 +2617,15 @@ nopt@~3.0.6: dependencies: abbrev "1" +normalize-package-data@^2.3.2: + version "2.3.5" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.3.5.tgz#8d924f142960e1777e7ffe170543631cc7cb02df" + dependencies: + hosted-git-info "^2.1.4" + is-builtin-module "^1.0.0" + semver "2 || 3 || 4 || 5" + validate-npm-package-license "^3.0.1" + normalize-path@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.0.1.tgz#47886ac1662760d4261b7d979d241709d3ce3f7a" @@ -2276,6 +2643,38 @@ number-is-nan@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" +nyc@^10.0.0: + version "10.1.2" + resolved "https://registry.yarnpkg.com/nyc/-/nyc-10.1.2.tgz#ea7acaa20a235210101604f4e7d56d28453b0274" + dependencies: + archy "^1.0.0" + arrify "^1.0.1" + caching-transform "^1.0.0" + convert-source-map "^1.3.0" + debug-log "^1.0.1" + default-require-extensions "^1.0.0" + find-cache-dir "^0.1.1" + find-up "^1.1.2" + foreground-child "^1.5.3" + glob "^7.0.6" + istanbul-lib-coverage "^1.0.1" + istanbul-lib-hook "^1.0.0" + istanbul-lib-instrument "^1.4.2" + istanbul-lib-report "^1.0.0-alpha.3" + istanbul-lib-source-maps "^1.1.0" + istanbul-reports "^1.0.0" + md5-hex "^1.2.0" + merge-source-map "^1.0.2" + micromatch "^2.3.11" + mkdirp "^0.5.0" + resolve-from "^2.0.0" + rimraf "^2.5.4" + signal-exit "^3.0.1" + spawn-wrap "1.2.4" + test-exclude "^3.3.0" + yargs "^6.6.0" + yargs-parser "^4.0.2" + oauth-sign@~0.8.1: version "0.8.2" resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" @@ -2284,14 +2683,10 @@ object-assign@4.0.1, object-assign@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.0.1.tgz#99504456c3598b5cad4fc59c26e8a9bb107fe0bd" -object-assign@4.1.0: +object-assign@4.1.0, object-assign@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.0.tgz#7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0" -object-assign@^4.1.0: - version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" - object-inspect@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-0.4.0.tgz#f5157c116c1455b243b06ee97703392c5ad89fec" @@ -2327,6 +2722,14 @@ onetime@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" +only-shallow@^1.0.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/only-shallow/-/only-shallow-1.2.0.tgz#71cecedba9324bc0518aef10ec080d3249dc2465" + +opener@^1.4.1: + version "1.4.2" + resolved "https://registry.yarnpkg.com/opener/-/opener-1.4.2.tgz#b32582080042af8680c389a499175b4c54fff523" + opn@^4.0.2: version "4.0.2" resolved "https://registry.yarnpkg.com/opn/-/opn-4.0.2.tgz#7abc22e644dff63b0a96d5ab7f2790c0f01abc95" @@ -2334,6 +2737,13 @@ opn@^4.0.2: object-assign "^4.0.1" pinkie-promise "^2.0.0" +optimist@^0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" + dependencies: + minimist "~0.0.1" + wordwrap "~0.0.2" + optionator@^0.8.1, optionator@^0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" @@ -2349,10 +2759,20 @@ os-browserify@~0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.1.2.tgz#49ca0293e0b19590a5f5de10c7f265a617d8fe54" +os-homedir@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.1.tgz#0d62bdf44b916fd3bbdcf2cab191948fb094f007" + os-homedir@^1.0.0, os-homedir@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" +os-locale@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" + dependencies: + lcid "^1.0.0" + os-tmpdir@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" @@ -2408,6 +2828,12 @@ parse-glob@^3.0.4: is-extglob "^1.0.0" is-glob "^2.0.0" +parse-json@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" + dependencies: + error-ex "^1.2.0" + parse-ms@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/parse-ms/-/parse-ms-1.0.1.tgz#56346d4749d78f23430ca0c713850aef91aa361d" @@ -2420,6 +2846,12 @@ path-browserify@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.0.tgz#a0b870729aae214005b7d5032ec2cbbb0fb4451a" +path-exists@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" + dependencies: + pinkie-promise "^2.0.0" + path-is-absolute@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" @@ -2428,10 +2860,22 @@ path-is-inside@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" +path-parse@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" + path-platform@~0.11.15: version "0.11.15" resolved "https://registry.yarnpkg.com/path-platform/-/path-platform-0.11.15.tgz#e864217f74c36850f0852b78dc7bf7d4a5721bf2" +path-type@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" + dependencies: + graceful-fs "^4.1.2" + pify "^2.0.0" + pinkie-promise "^2.0.0" + pathname-match@^1.1.3: version "1.2.0" resolved "https://registry.yarnpkg.com/pathname-match/-/pathname-match-1.2.0.tgz#77cb8e3db1e41e4771c4942a9e4fecb610cc2d19" @@ -2515,6 +2959,12 @@ pkg-config@^1.0.1, pkg-config@^1.1.0: find-root "^1.0.0" xtend "^4.0.1" +pkg-dir@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-1.0.0.tgz#7a4b508a8d5bb2d629d447056ff4e9c9314cf3d4" + dependencies: + find-up "^1.0.0" + plur@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/plur/-/plur-1.0.0.tgz#db85c6814f5e5e5a3b49efc28d604fec62975156" @@ -2601,6 +3051,10 @@ progress@^1.1.8: version "1.1.8" resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be" +pseudomap@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + public-encrypt@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.0.tgz#39f699f3a46560dd5ebacbca693caf7c65c18cc6" @@ -2626,6 +3080,10 @@ punycode@^1.3.2, punycode@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" +qs@~6.2.0: + version "6.2.1" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.2.1.tgz#ce03c5ff0935bc1d9d69a9f14cbd18e568d67625" + qs@~6.3.0: version "6.3.0" resolved "https://registry.yarnpkg.com/qs/-/qs-6.3.0.tgz#f403b264f23bc01228c74131b407f18d5ea5d442" @@ -2671,12 +3129,31 @@ rc@~1.1.6: minimist "^1.2.0" strip-json-comments "~1.0.4" +re-emitter@^1.0.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/re-emitter/-/re-emitter-1.1.3.tgz#fa9e319ffdeeeb35b27296ef0f3d374dac2f52a7" + read-only-stream@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/read-only-stream/-/read-only-stream-2.0.0.tgz#2724fd6a8113d73764ac288d4386270c1dbf17f0" dependencies: readable-stream "^2.0.2" +read-pkg-up@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" + dependencies: + find-up "^1.0.0" + read-pkg "^1.0.0" + +read-pkg@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" + dependencies: + load-json-file "^1.0.0" + normalize-package-data "^2.3.2" + path-type "^1.0.0" + "readable-stream@>=1.0.33-1 <1.1.0-0", readable-stream@~1.0.17, readable-stream@~1.0.26, readable-stream@~1.0.27-1: version "1.0.34" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" @@ -2695,7 +3172,7 @@ read-only-stream@^2.0.0: isarray "0.0.1" string_decoder "~0.10.x" -readable-stream@^2.0.0, "readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.3, readable-stream@^2.0.5, readable-stream@^2.1.0, readable-stream@^2.1.5, readable-stream@^2.2.2: +readable-stream@^2, readable-stream@^2.0.0, "readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.3, readable-stream@^2.0.5, readable-stream@^2.1.0, readable-stream@^2.1.5, readable-stream@^2.2.2: version "2.2.2" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.2.tgz#a9e6fec3c7dda85f8bb1b3ba7028604556fc825e" dependencies: @@ -2707,7 +3184,7 @@ readable-stream@^2.0.0, "readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2. string_decoder "~0.10.x" util-deprecate "~1.0.1" -readable-stream@~2.0.0: +readable-stream@~2.0.0, readable-stream@~2.0.5: version "2.0.6" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" dependencies: @@ -2772,6 +3249,38 @@ repeat-string@^1.5.2, repeat-string@^1.5.4: version "1.6.1" resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" +repeating@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" + dependencies: + is-finite "^1.0.0" + +request@2.75.0: + version "2.75.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.75.0.tgz#d2b8268a286da13eaa5d01adf5d18cc90f657d93" + dependencies: + aws-sign2 "~0.6.0" + aws4 "^1.2.1" + bl "~1.1.2" + caseless "~0.11.0" + combined-stream "~1.0.5" + extend "~3.0.0" + forever-agent "~0.6.1" + form-data "~2.0.0" + har-validator "~2.0.6" + hawk "~3.1.3" + http-signature "~1.1.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.7" + node-uuid "~1.4.7" + oauth-sign "~0.8.1" + qs "~6.2.0" + stringstream "~0.0.4" + tough-cookie "~2.3.0" + tunnel-agent "~0.4.1" + request@^2.79.0: version "2.79.0" resolved "https://registry.yarnpkg.com/request/-/request-2.79.0.tgz#4dfe5bf6be8b8cdc37fcf93e04b65577722710de" @@ -2797,6 +3306,14 @@ request@^2.79.0: tunnel-agent "~0.4.1" uuid "^3.0.0" +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + +require-main-filename@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" + require-uncached@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" @@ -2815,6 +3332,10 @@ resolve-from@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" +resolve-from@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-2.0.0.tgz#9480ab20e94ffa1d9e80a804c7ea147611966b57" + resolve@1.1.7: version "1.1.7" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" @@ -2840,7 +3361,7 @@ right-now@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/right-now/-/right-now-1.0.0.tgz#6e89609deebd7dcdaf8daecc9aea39cf585a0918" -rimraf@2, rimraf@^2.2.8, rimraf@~2.5.1, rimraf@~2.5.4: +rimraf@2, rimraf@^2.2.8, rimraf@^2.3.3, rimraf@^2.4.3, rimraf@^2.4.4, rimraf@^2.5.4, rimraf@~2.5.1, rimraf@~2.5.4: version "2.5.4" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.5.4.tgz#96800093cbf1a0c86bd95b4625467535c29dfa04" dependencies: @@ -2864,14 +3385,14 @@ rx-lite@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102" +"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@~5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" + semver@4.3.2: version "4.3.2" resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.2.tgz#c7a07158a80bedd052355b770d82d6640f803be7" -semver@~5.3.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" - server-router@^4.0.0: version "4.0.2" resolved "https://registry.yarnpkg.com/server-router/-/server-router-4.0.2.tgz#2a1354d3654ad1a3254d41499f41dcb232fd0507" @@ -2888,7 +3409,7 @@ server-sink@^1.0.0: http-ndjson "^3.0.0" size-stream "^1.0.1" -set-blocking@~2.0.0: +set-blocking@^2.0.0, set-blocking@~2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" @@ -2954,7 +3475,11 @@ shelljs@^0.7.5: interpret "^1.0.0" rechoir "^0.6.2" -signal-exit@^3.0.0: +signal-exit@^2.0.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-2.1.2.tgz#375879b1f92ebc3b334480d038dc546a6d558564" + +signal-exit@^3.0.0, signal-exit@^3.0.1: version "3.0.2" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" @@ -2968,13 +3493,17 @@ slice-ansi@0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" +slide@^1.1.5: + version "1.1.6" + resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" + sntp@1.x.x: version "1.0.9" resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" dependencies: hoek "2.x.x" -"source-map@>= 0.1.2", source-map@^0.5.6, source-map@~0.5.1, source-map@~0.5.3: +"source-map@>= 0.1.2", source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.1, source-map@~0.5.3: version "0.5.6" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" @@ -2984,17 +3513,42 @@ source-map@^0.1.34, source-map@~0.1.33: dependencies: amdefine ">=0.0.4" +source-map@^0.4.4, source-map@~0.4.0, source-map@~0.4.2: + version "0.4.4" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" + dependencies: + amdefine ">=0.0.4" + source-map@~0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.2.0.tgz#dab73fbcfc2ba819b4de03bd6f6eaa48164b3f9d" dependencies: amdefine ">=0.0.4" -source-map@~0.4.0, source-map@~0.4.2: - version "0.4.4" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" +spawn-wrap@1.2.4: + version "1.2.4" + resolved "https://registry.yarnpkg.com/spawn-wrap/-/spawn-wrap-1.2.4.tgz#920eb211a769c093eebfbd5b0e7a5d2e68ab2e40" dependencies: - amdefine ">=0.0.4" + foreground-child "^1.3.3" + mkdirp "^0.5.0" + os-homedir "^1.0.1" + rimraf "^2.3.3" + signal-exit "^2.0.0" + which "^1.2.4" + +spdx-correct@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40" + dependencies: + spdx-license-ids "^1.0.2" + +spdx-expression-parse@~1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz#9bdf2f20e1f40ed447fbe273266191fced51626c" + +spdx-license-ids@^1.0.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57" split2@^0.2.1: version "0.2.1" @@ -3037,6 +3591,10 @@ stack-trace@0.0.9: version "0.0.9" resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.9.tgz#a8f6eaeca90674c333e7c43953f275b451510695" +stack-utils@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-0.4.0.tgz#940cb82fccfa84e8ff2f3fdf293fe78016beccd1" + standard-engine@~5.2.0: version "5.2.0" resolved "https://registry.yarnpkg.com/standard-engine/-/standard-engine-5.2.0.tgz#400660ae5acce8afd4db60ff2214a9190ad790a3" @@ -3125,7 +3683,7 @@ stream-splicer@^2.0.0: inherits "^2.0.1" readable-stream "^2.0.2" -string-width@^1.0.1: +string-width@^1.0.1, string-width@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" dependencies: @@ -3160,6 +3718,12 @@ strip-ansi@^3.0.0, strip-ansi@^3.0.1: dependencies: ansi-regex "^2.0.0" +strip-bom@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" + dependencies: + is-utf8 "^0.2.0" + strip-bom@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" @@ -3212,6 +3776,76 @@ table@^3.7.8: slice-ansi "0.0.4" string-width "^2.0.0" +tap-mocha-reporter@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/tap-mocha-reporter/-/tap-mocha-reporter-3.0.1.tgz#59abab0103b3453ca05df8f553ffe7b8cffac868" + dependencies: + color-support "^1.1.0" + debug "^2.1.3" + diff "^1.3.2" + escape-string-regexp "^1.0.3" + glob "^7.0.5" + js-yaml "^3.3.1" + tap-parser "^4.2.3" + unicode-length "^1.0.0" + optionalDependencies: + readable-stream "^2.1.5" + +tap-out@^1.4.1: + version "1.4.2" + resolved "https://registry.yarnpkg.com/tap-out/-/tap-out-1.4.2.tgz#c907ec1bf9405111d088263e92f5608b88cbb37a" + dependencies: + re-emitter "^1.0.0" + readable-stream "^2.0.0" + split "^1.0.0" + trim "0.0.1" + +tap-parser@^4.2.2, tap-parser@^4.2.3: + version "4.2.4" + resolved "https://registry.yarnpkg.com/tap-parser/-/tap-parser-4.2.4.tgz#65a2a602e49e17db83fa1f295f53fad03025cc4d" + dependencies: + events-to-array "^1.0.1" + js-yaml "^3.2.7" + optionalDependencies: + readable-stream "^2" + +tap-spec@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/tap-spec/-/tap-spec-4.1.1.tgz#e2e9f26f5208232b1f562288c97624d58a88f05a" + dependencies: + chalk "^1.0.0" + duplexer "^0.1.1" + figures "^1.4.0" + lodash "^3.6.0" + pretty-ms "^2.1.0" + repeat-string "^1.5.2" + tap-out "^1.4.1" + through2 "^2.0.0" + +tap@^9.0.3: + version "9.0.3" + resolved "https://registry.yarnpkg.com/tap/-/tap-9.0.3.tgz#bd3deecb507f4e368486eeba8f10cd78f42f7283" + dependencies: + bluebird "^3.3.1" + clean-yaml-object "^0.1.0" + color-support "^1.1.0" + coveralls "^2.11.2" + deeper "^2.1.0" + foreground-child "^1.3.3" + glob "^7.0.0" + isexe "^1.0.0" + js-yaml "^3.3.1" + nyc "^10.0.0" + only-shallow "^1.0.2" + opener "^1.4.1" + os-homedir "1.0.1" + readable-stream "^2.0.2" + signal-exit "^3.0.0" + stack-utils "^0.4.0" + tap-mocha-reporter "^3.0.1" + tap-parser "^4.2.2" + tmatch "^3.0.0" + tar-pack@~3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.3.0.tgz#30931816418f55afc4d21775afdd6720cee45dae" @@ -3233,6 +3867,16 @@ tar@~2.2.1: fstream "^1.0.2" inherits "2" +test-exclude@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-3.3.0.tgz#7a17ca1239988c98367b0621456dbb7d4bc38977" + dependencies: + arrify "^1.0.1" + micromatch "^2.3.11" + object-assign "^4.1.0" + read-pkg-up "^1.0.1" + require-main-filename "^1.0.1" + text-table@~0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" @@ -3281,16 +3925,28 @@ timers-browserify@^1.0.1: dependencies: process "~0.11.0" +tmatch@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/tmatch/-/tmatch-3.0.0.tgz#7d2071dedbbc587f194acda3067bd0747b670991" + to-arraybuffer@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" +to-fast-properties@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.2.tgz#f3f5c0c3ba7299a7ef99427e44633257ade43320" + tough-cookie@~2.3.0: version "2.3.2" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.2.tgz#f081f76e4c85720e6c37a5faced737150d84072a" dependencies: punycode "^1.4.1" +trim@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/trim/-/trim-0.0.1.tgz#5858547f6b290757ee95cccc666fb50084c460dd" + tryit@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/tryit/-/tryit-1.0.3.tgz#393be730a9446fd1ead6da59a014308f36c289cb" @@ -3317,7 +3973,7 @@ typedarray@^0.0.6, typedarray@~0.0.5: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" -uglify-js@2.x.x: +uglify-js@2.x.x, uglify-js@^2.6: version "2.7.5" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.7.5.tgz#4612c0c7baaee2ba7c487de4904ae122079f2ca8" dependencies: @@ -3371,6 +4027,13 @@ unassertify@^2.0.3: through "^2.3.7" unassert "^1.3.1" +unicode-length@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/unicode-length/-/unicode-length-1.0.3.tgz#5ada7a7fed51841a418a328cf149478ac8358abb" + dependencies: + punycode "^1.3.2" + strip-ansi "^3.0.1" + uniq@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" @@ -3422,6 +4085,13 @@ v8flags@^2.0.2: dependencies: user-home "^1.1.1" +validate-npm-package-license@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc" + dependencies: + spdx-correct "~1.0.0" + spdx-expression-parse "~1.0.0" + verror@1.3.6: version "1.3.6" resolved "https://registry.yarnpkg.com/verror/-/verror-1.3.6.tgz#cff5df12946d297d2baaefaa2689e25be01c005c" @@ -3459,7 +4129,11 @@ wayfarer@^6.1.4, wayfarer@^6.2.1: dependencies: xtend "^4.0.1" -which@^1.2.12: +which-module@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" + +which@^1.2.12, which@^1.2.4, which@^1.2.9: version "1.2.12" resolved "https://registry.yarnpkg.com/which/-/which-1.2.12.tgz#de67b5e450269f194909ef23ece4ebe416fa1192" dependencies: @@ -3475,7 +4149,7 @@ window-size@0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" -wordwrap@0.0.2: +wordwrap@0.0.2, wordwrap@~0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" @@ -3483,10 +4157,25 @@ wordwrap@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" +wrap-ansi@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" +write-file-atomic@^1.1.4: + version "1.3.1" + resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-1.3.1.tgz#7d45ba32316328dd1ec7d90f60ebc0d845bb759a" + dependencies: + graceful-fs "^4.1.11" + imurmurhash "^0.1.4" + slide "^1.1.5" + write@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" @@ -3503,6 +4192,38 @@ xtend@~2.1.1: dependencies: object-keys "~0.4.0" +y18n@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" + +yallist@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.0.0.tgz#306c543835f09ee1a4cb23b7bce9ab341c91cdd4" + +yargs-parser@^4.0.2, yargs-parser@^4.2.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-4.2.1.tgz#29cceac0dc4f03c6c87b4a9f217dd18c9f74871c" + dependencies: + camelcase "^3.0.0" + +yargs@^6.6.0: + version "6.6.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-6.6.0.tgz#782ec21ef403345f830a808ca3d513af56065208" + dependencies: + camelcase "^3.0.0" + cliui "^3.2.0" + decamelize "^1.1.1" + get-caller-file "^1.0.1" + 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" + y18n "^3.2.1" + yargs-parser "^4.2.0" + yargs@~3.10.0: version "3.10.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1" From a9524bb1616acc6ab7b03ab2877ee78abe3d49c4 Mon Sep 17 00:00:00 2001 From: Frederic Gingras Date: Wed, 18 Jan 2017 11:03:56 -0500 Subject: [PATCH 09/27] server: helpers: csv --- Makefile | 5 +- client/app.js | 10 ++-- package.json | 3 +- server.js | 30 ++++++----- server/helpers/csv.js | 61 +++++++++++++++++++++ tests/unit/csv_helper.js | 61 +++++++++++++++++++++ yarn.lock | 112 +++++++++++++++++++++++++++++++++------ 7 files changed, 245 insertions(+), 37 deletions(-) diff --git a/Makefile b/Makefile index fa59b2fe5..e1f4269ab 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,6 @@ PATH := ./node_modules/.bin:$(PATH) # node or yarn are not on $PATH NODE := node YARN := yarn -TAP := tap TAPE := tape TAPSPEC := tap-spec STANDARD := standard @@ -25,10 +24,10 @@ lint: ## Ensures your code follows the "standard" $(STANDARD) --fix test-unit: ## Run unit tests - $(TAP) tests/unit/*.js | $(TAPSPEC) + $(TAPE) tests/unit/*.js | $(TAPSPEC) test-integration: ## Run integration tests - $(TAP) tests/integration/*.js | $(TAPSPEC) + $(TAPE) tests/integration/*.js | $(TAPSPEC) test-system: ## Run system tests $(TAPE) tests/system/*.js | $(TAPSPEC) diff --git a/client/app.js b/client/app.js index 5b2d0a23a..6da59c8ac 100644 --- a/client/app.js +++ b/client/app.js @@ -1,6 +1,6 @@ -var html = require('choo/html') -var choo = require('choo') -var app = choo() +const html = require('choo/html') +const choo = require('choo') +const app = choo() app.model({ state: {title: 'Not quite set yet'}, @@ -67,7 +67,7 @@ function mainView (state, prev, send) { app.router(['/', mainView]) -var tree = app.start() -var appEl = document.getElementById('app') +const tree = app.start() +const appEl = document.getElementById('app') appEl.innerHTML = '' appEl.appendChild(tree) diff --git a/package.json b/package.json index 54647f0b6..5f8a709c7 100644 --- a/package.json +++ b/package.json @@ -15,6 +15,7 @@ "devDependencies": { "standard": "^8.6.0", "tap": "^9.0.3", - "tap-spec": "^4.1.1" + "tap-spec": "^4.1.1", + "tape": "^4.6.3" } } diff --git a/server.js b/server.js index 40b2b218b..7ade04e4e 100644 --- a/server.js +++ b/server.js @@ -1,12 +1,14 @@ -var fs = require('fs') -var path = require('path') -var http = require('http') -var merry = require('merry') -var bankai = require('bankai') +const fs = require('fs') +const path = require('path') +const http = require('http') +const merry = require('merry') +const bankai = require('bankai') -var env = merry.env({PORT: 8000}) -var production = env.NODE_ENV === 'production' -var app = merry() +// Server setup + +const env = merry.env({PORT: 8000}) +const production = env.NODE_ENV === 'production' +const app = merry() app.router([ // Static assets @@ -15,7 +17,7 @@ app.router([ ['/tachyons.min.css', serveStaticFile('tachyons.min.css', 'text/css')], // API - ['/upload', {post: handleUpload}], + ['/import', {post: handleImport}], // Error and Not found handlers ['/404', serveStaticFile('not-found.html', 'text/html')] @@ -24,20 +26,22 @@ app.router([ http.createServer(app.start()).listen(env.PORT) app.log.info('started listening on port ' + env.PORT) -function handleUpload (req, res, ctx, done) { +// Route handlers + +function handleImport (req, res, ctx, done) { done(merry.error({statusCode: 400})) done(null, 'hello world') } function serveClientJs (req, res, ctx, done) { - var clientPath = path.join(__dirname, 'client', 'app.js') - var assets = bankai(clientPath, {optimize: production, cssDisabled: true}) + const clientPath = path.join(__dirname, 'client', 'app.js') + const assets = bankai(clientPath, {optimize: production, cssDisabled: true}) done(null, assets.js(req, res)) } function serveStaticFile (filename, contentType) { return function (req, res, ctx, done) { - var absolutePath = path.join(__dirname, 'client', filename) + const absolutePath = path.join(__dirname, 'client', filename) res.writeHead(200, {'Content-Type': contentType}) done(null, fs.createReadStream(absolutePath).pipe(res)) } diff --git a/server/helpers/csv.js b/server/helpers/csv.js index e69de29bb..55d101fb9 100644 --- a/server/helpers/csv.js +++ b/server/helpers/csv.js @@ -0,0 +1,61 @@ +const assert = require('assert') + +class CSVHelper { + // Parses a CSV string into an array of object + // + // Object attribute names are defined by given `columns` array + // + // Example: + // + // parse(['a', 'b'], 'header\n1,2\n3,4') + // => [{a: '1', b: '2'}, {a: '3', b: '4'}] + parse (columns, data, hasHeader = true) { + assert(Array.isArray(columns), 'CSVHelper: parse: columns needs to be an array') + assert(typeof data === 'string', 'CSVHelper: parse: data needs to be a string') + const result = [{}] + let columnIndex = 0 + + for (let i = 0; i < data.length; i++) { + const currentRow = result[result.length - 1] + + switch (data[i]) { + case '\r': + case '\n': + // If last row in result has items, it's save to create a new one + // else we want to skip creating a new row as there could be multiple + // '\r' or '\n' ending the line. + if (Object.keys(currentRow).length > 0) { + columnIndex = 0 + result.push({}) + } + break + case ',': + // Matching on ',' without a way to include a comma in strings + // or escape it is simplistic but ok for our current needs + columnIndex++ + break + default: + const columnName = columnIndex < columns.length + ? columns[columnIndex] + : String(columnIndex + 1) + currentRow[columnName] = (currentRow[columnName] || '') + data[i] + break + } + } + + // Skip the first result/row when we have headers + const sliceStart = hasHeader ? 1 : 0 + + // Skip the last element if it's empty + // (will have been added if some linefeed was encoundred last) + const lastItemSize = Object.keys(result[result.length - 1]).length + const sliceEnd = lastItemSize > 0 ? result.length : result.length - 1 + + return result.slice(sliceStart, sliceEnd) + } +} + +CSVHelper.dependencyName = 'helpers:csv' +CSVHelper.dependencies = [] + +module.exports = CSVHelper diff --git a/tests/unit/csv_helper.js b/tests/unit/csv_helper.js index e69de29bb..96f88bb22 100644 --- a/tests/unit/csv_helper.js +++ b/tests/unit/csv_helper.js @@ -0,0 +1,61 @@ +const test = require('tape') + +const CSVHelper = require('../../server/helpers/csv') +const csvHelper = new CSVHelper() + +test('CSVHelper: parse: simple case', function (t) { + const result = csvHelper.parse(['a'], 'header\nb') + t.deepEqual(result, [{a: 'b'}]) + t.end() +}) + +test('CSVHelper: parse: no headers', function (t) { + const result = csvHelper.parse(['a'], 'b', false) + t.deepEqual(result, [{a: 'b'}]) + t.end() +}) + +test('CSVHelper: parse: multiple lines', function (t) { + const result = csvHelper.parse(['a'], 'h\n1\n2') + t.deepEqual(result, [{a: '1'}, {a: '2'}]) + t.end() +}) + +test('CSVHelper: parse: multiple items', function (t) { + const result = csvHelper.parse(['a', 'b'], 'h\n1,2') + t.deepEqual(result, [{a: '1', b: '2'}]) + t.end() +}) + +test('CSVHelper: parse: more items than columns passed', function (t) { + const result = csvHelper.parse(['a'], 'h\n1,2') + t.deepEqual(result, [{a: '1', '2': '2'}]) + t.end() +}) + +test('CSVHelper: parse: more than 1 line feed', function (t) { + let result + + result = csvHelper.parse(['a'], 'h\r\n1') + t.deepEqual(result, [{a: '1'}]) + + result = csvHelper.parse(['a'], 'h\r\n\n\n1') + t.deepEqual(result, [{a: '1'}]) + + t.end() +}) + +test('CSVHelper: parse: trailing line feed', function (t) { + const result = csvHelper.parse(['a'], 'h\n1\n') + t.deepEqual(result, [{a: '1'}]) + t.end() +}) + +test('CSVHelper: parse: all together', function (t) { + const result = csvHelper.parse(['a', 'b'], 'h1,h2,h3\n1,2,3\r\n4,5,6\n') + t.deepEqual(result, [ + {a: '1', b: '2', '3': '3'}, + {a: '4', b: '5', '3': '6'} + ]) + t.end() +}) diff --git a/yarn.lock b/yarn.lock index fdce9f1ac..333616c42 100644 --- a/yarn.lock +++ b/yarn.lock @@ -983,7 +983,7 @@ decamelize@^1.0.0, decamelize@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" -deep-equal@^1.0.0: +deep-equal@^1.0.0, deep-equal@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" @@ -1005,7 +1005,14 @@ default-require-extensions@^1.0.0: dependencies: strip-bom "^2.0.0" -defined@^1.0.0: +define-properties@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.2.tgz#83a73f2fea569898fb737193c8f873caf6d45c94" + dependencies: + foreach "^2.0.5" + object-keys "^1.0.8" + +defined@^1.0.0, defined@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" @@ -1165,6 +1172,23 @@ error-ex@^1.2.0: dependencies: is-arrayish "^0.2.1" +es-abstract@^1.5.0: + version "1.6.1" + resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.6.1.tgz#bb8a2064120abcf928a086ea3d9043114285ec99" + dependencies: + es-to-primitive "^1.1.1" + function-bind "^1.1.0" + is-callable "^1.1.3" + is-regex "^1.0.3" + +es-to-primitive@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.1.1.tgz#45355248a88979034b6792e19bb81f2b7975dd0d" + dependencies: + is-callable "^1.1.1" + is-date-object "^1.0.1" + is-symbol "^1.0.1" + es5-ext@^0.10.7, es5-ext@^0.10.8, es5-ext@~0.10.11, es5-ext@~0.10.2, es5-ext@~0.10.7: version "0.10.12" resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.12.tgz#aa84641d4db76b62abba5e45fd805ecbab140047" @@ -1549,6 +1573,12 @@ flatten@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782" +for-each@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.2.tgz#2c40450b9348e97f281322593ba96704b9abd4d4" + dependencies: + is-function "~1.0.0" + for-in@^0.1.5: version "0.1.6" resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.6.tgz#c9f96e89bfad18a545af5ec3ed352a1d9e5b4dc8" @@ -1635,7 +1665,7 @@ fstream@^1.0.0, fstream@^1.0.2, fstream@~1.0.10: mkdirp ">=0.5 0" rimraf "2" -function-bind@^1.0.2: +function-bind@^1.0.2, function-bind@^1.1.0, function-bind@~1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.0.tgz#16176714c801798e4e8f2cf7f7529467bb4a5771" @@ -1713,7 +1743,7 @@ glob-parent@^2.0.0: dependencies: is-glob "^2.0.0" -glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.0.6, glob@^7.1.0: +glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.0.6, glob@^7.1.0, glob@~7.1.1: version "7.1.1" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" dependencies: @@ -1809,7 +1839,7 @@ has-unicode@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" -has@^1.0.0: +has@^1.0.0, has@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/has/-/has-1.0.1.tgz#8461733f538b0837c9361e39a9ab9e9704dc2f28" dependencies: @@ -1930,7 +1960,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1: +inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" @@ -2027,6 +2057,14 @@ is-builtin-module@^1.0.0: dependencies: builtin-modules "^1.0.0" +is-callable@^1.1.1, is-callable@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.3.tgz#86eb75392805ddc33af71c92a0eedf74ee7604b2" + +is-date-object@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" + is-dotfile@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.2.tgz#2c132383f39199f8edc268ca01b9b007d205cc4d" @@ -2061,6 +2099,10 @@ is-fullwidth-code-point@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" +is-function@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.1.tgz#12cfb98b65b57dd3d193a3121f5f6e2f437602b5" + is-glob@^2.0.0, is-glob@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" @@ -2110,6 +2152,10 @@ is-property@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" +is-regex@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.3.tgz#0d55182bddf9f2fde278220aec3a75642c908637" + is-resolvable@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.0.0.tgz#8df57c61ea2e3c501408d100fb013cf8d6e0cc62" @@ -2120,6 +2166,10 @@ is-stream@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" +is-symbol@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.1.tgz#3cc59f00025194b6ab2e38dbae6689256b660572" + is-typedarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" @@ -2519,7 +2569,7 @@ minimist@0.0.8, minimist@~0.0.1: version "0.0.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" -minimist@1.2.0, minimist@^1.1.0, minimist@^1.2.0: +minimist@1.2.0, minimist@^1.1.0, minimist@^1.2.0, minimist@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" @@ -2691,7 +2741,11 @@ object-inspect@~0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-0.4.0.tgz#f5157c116c1455b243b06ee97703392c5ad89fec" -object-keys@^1.0.6: +object-inspect@~1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.2.1.tgz#3b62226eb8f6d441751c7d8f22a20ff80ac9dc3f" + +object-keys@^1.0.6, object-keys@^1.0.8: version "1.0.11" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.11.tgz#c54601778ad560f1142ce0e01bcca8b56d13426d" @@ -2759,14 +2813,10 @@ os-browserify@~0.1.1: version "0.1.2" resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.1.2.tgz#49ca0293e0b19590a5f5de10c7f265a617d8fe54" -os-homedir@1.0.1: +os-homedir@1.0.1, os-homedir@^1.0.0, os-homedir@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.1.tgz#0d62bdf44b916fd3bbdcf2cab191948fb094f007" -os-homedir@^1.0.0, os-homedir@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" - os-locale@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" @@ -3336,7 +3386,7 @@ resolve-from@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-2.0.0.tgz#9480ab20e94ffa1d9e80a804c7ea147611966b57" -resolve@1.1.7: +resolve@1.1.7, resolve@~1.1.7: version "1.1.7" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" @@ -3351,6 +3401,12 @@ restore-cursor@^1.0.1: exit-hook "^1.0.0" onetime "^1.0.0" +resumer@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/resumer/-/resumer-0.0.0.tgz#f1e8f461e4064ba39e82af3cdc2a8c893d076759" + dependencies: + through "~2.3.4" + right-align@^0.1.1: version "0.1.3" resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" @@ -3698,6 +3754,14 @@ string-width@^2.0.0: is-fullwidth-code-point "^2.0.0" strip-ansi "^3.0.0" +string.prototype.trim@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/string.prototype.trim/-/string.prototype.trim-1.1.2.tgz#d04de2c89e137f4d7d206f086b5ed2fae6be8cea" + dependencies: + define-properties "^1.1.2" + es-abstract "^1.5.0" + function-bind "^1.0.2" + string_decoder@~0.10.0, string_decoder@~0.10.x: version "0.10.31" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" @@ -3846,6 +3910,24 @@ tap@^9.0.3: tap-parser "^4.2.2" tmatch "^3.0.0" +tape@^4.6.3: + version "4.6.3" + resolved "https://registry.yarnpkg.com/tape/-/tape-4.6.3.tgz#637e77581e9ab2ce17577e9bd4ce4f575806d8b6" + dependencies: + deep-equal "~1.0.1" + defined "~1.0.0" + for-each "~0.3.2" + function-bind "~1.1.0" + glob "~7.1.1" + has "~1.0.1" + inherits "~2.0.3" + minimist "~1.2.0" + object-inspect "~1.2.1" + resolve "~1.1.7" + resumer "~0.0.0" + string.prototype.trim "~1.1.2" + through "~2.3.8" + tar-pack@~3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.3.0.tgz#30931816418f55afc4d21775afdd6720cee45dae" @@ -3909,7 +3991,7 @@ through2@~0.6.1: readable-stream ">=1.0.33-1 <1.1.0-0" xtend ">=4.0.0 <4.1.0-0" -through@2, "through@>=2.2.7 <3", through@^2.3.6, through@^2.3.7, through@~2.3.4: +through@2, "through@>=2.2.7 <3", through@^2.3.6, through@^2.3.7, through@~2.3.4, through@~2.3.8: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" From 023c56ad42d63dec1166d5d881e5679de7a29b9d Mon Sep 17 00:00:00 2001 From: Frederic Gingras Date: Wed, 18 Jan 2017 11:36:28 -0500 Subject: [PATCH 10/27] server: library: container --- package.json | 3 +- server/library/container.js | 55 ++++++++++++++++++ tests/unit/container_library.js | 98 +++++++++++++++++++++++++++++++++ yarn.lock | 8 ++- 4 files changed, 161 insertions(+), 3 deletions(-) create mode 100644 tests/unit/container_library.js diff --git a/package.json b/package.json index 5f8a709c7..d9b79170e 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,8 @@ "choo": "^4.0.3", "knex": "^0.12.6", "merry": "^4.1.0", - "pg": "^6.1.2" + "pg": "^6.1.2", + "ramda": "^0.23.0" }, "devDependencies": { "standard": "^8.6.0", diff --git a/server/library/container.js b/server/library/container.js index e69de29bb..4ccdad79c 100644 --- a/server/library/container.js +++ b/server/library/container.js @@ -0,0 +1,55 @@ +const assert = require('assert') +const R = require('ramda') + +// Creates an instance of a class, passing args to the constructor +// ES6 constructors need the `new` keyword to be used, so, no .apply +// magic can be done here until WebReflection lands in Node.js stable. +function applyToConstructor (constructor, args) { + return R.apply(R.construct(constructor), args) +} + +class Container { + constructor (log) { + this.log = log || (() => {}) + this.contents = {} + + // Help avoid unbound this error for cases where `container.{get,set}` + // is being passed around as a value + this.get.bind(this) + this.set.bind(this) + } + + // Get an object's instance by name + get (name) { + assert(name in this.contents, 'container: get: nothing registered for "' + name + '"') + return this.contents[name] + } + + // Set an object's instance by name + set (name, instance) { + assert(typeof name === 'string', 'container: set: name must be a string') + this.log('container: set: ' + name) + this.contents[name] = instance + return instance + } + + create (klass) { + assert(Array.isArray(klass.dependencies), 'container: create: class given doesn\'t have `dependencies` defined (or not an array)') + + const dependencies = [] + R.forEach(function (dependencyName) { + dependencies.push(this.get(dependencyName)) + }.bind(this), klass.dependencies) + + return applyToConstructor(klass, dependencies) + } + + load (klass) { + assert(typeof klass.dependencyName === 'string', 'container: load: class given doesn\'t have a `dependencyName` defined') + + const instance = this.create(klass) + return this.set(klass.dependencyName, instance) + } +} + +module.exports = Container diff --git a/tests/unit/container_library.js b/tests/unit/container_library.js new file mode 100644 index 000000000..9b61bf7be --- /dev/null +++ b/tests/unit/container_library.js @@ -0,0 +1,98 @@ +const test = require('tape') + +const Container = require('../../server/library/container') + +test('Container: set: checks name is a string', function (t) { + const c = new Container() + t.throws(() => c.set(1, 'value')) + t.end() +}) + +test('Container: set: saves instance value', function (t) { + const c = new Container() + c.set('x', 'value') + t.equal(c.contents['x'], 'value') + t.end() +}) + +test('Container: set: logs debug info', function (t) { + let logged = null + const c = new Container((message) => { + logged = message + }) + c.set('x', 'value') + t.equal(logged, 'container: set: x') + t.end() +}) + +test('Container: set: works when not given log', function (t) { + const c = new Container() + c.set('x', 'value') // This shouldn't throw + t.end() +}) + +test('Container: get: fetches the right value', function (t) { + const c = new Container() + const obj = {} + c.set('x', obj) + t.equal(c.get('x'), obj) + t.end() +}) + +test('Container: get: throws when missing value', function (t) { + const c = new Container() + t.throws(() => c.get('x')) + t.end() +}) + +test('Container: create: passes the right values to constructor', function (t) { + class X { + constructor (y, z) { + this.y = y + this.z = z + } + } + X.dependencies = ['y', 'z'] + + class Y {} + const y = new Y() + + class Z {} + const z = new Z() + + const c = new Container() + c.set('y', y) + c.set('z', z) + const instance = c.create(X) + + t.equal(instance.y, y) + t.equal(instance.z, z) + t.end() +}) + +test('Container: create: throws when missing dependencies', function (t) { + class X {} + const c = new Container() + t.throws(() => c.create(X)) + t.end() +}) + +test('Container: load: sets create\'s result', function (t) { + class X {} + X.dependencyName = 'the x' + + const c = new Container() + c.create = () => 'value' + + c.load(X) + + t.equal(c.get('the x'), 'value') + t.end() +}) + +test('Container: load: throws when missing dependencyName', function (t) { + class X {} + const c = new Container() + t.throws(() => c.load(X)) + t.end() +}) diff --git a/yarn.lock b/yarn.lock index 333616c42..d61d658e7 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2569,11 +2569,11 @@ minimist@0.0.8, minimist@~0.0.1: version "0.0.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" -minimist@1.2.0, minimist@^1.1.0, minimist@^1.2.0, minimist@~1.2.0: +minimist@1.2.0, minimist@^1.1.0, minimist@^1.1.1, minimist@^1.2.0, minimist@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" -minimist@^1.1.1, minimist@~1.1.0: +minimist@~1.1.0: version "1.1.3" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.1.3.tgz#3bedfd91a92d39016fcfaa1c681e8faa1a1efda8" @@ -3159,6 +3159,10 @@ quote-stream@~0.0.0: minimist "0.0.8" through2 "~0.4.1" +ramda@^0.23.0: + version "0.23.0" + resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.23.0.tgz#ccd13fff73497a93974e3e86327bfd87bd6e8e2b" + randomatic@^1.1.3: version "1.1.6" resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.6.tgz#110dcabff397e9dcff7c0789ccc0a49adf1ec5bb" From d7ff21b25ef9977cf3b6a32762c1a5f271dc6020 Mon Sep 17 00:00:00 2001 From: Frederic Gingras Date: Wed, 18 Jan 2017 12:08:18 -0500 Subject: [PATCH 11/27] server: models --- server/models/employee.js | 15 +++++++++++++++ server/models/expense.js | 18 ++++++++++++++++++ server/models/expense_category.js | 15 +++++++++++++++ server/models/tax.js | 15 +++++++++++++++ 4 files changed, 63 insertions(+) diff --git a/server/models/employee.js b/server/models/employee.js index e69de29bb..ea69a2367 100644 --- a/server/models/employee.js +++ b/server/models/employee.js @@ -0,0 +1,15 @@ +const R = require('ramda') + +const FIELDS = ['id', 'name', 'address'] + +class Employee { + constructor (values = {}) { + Object.assign(this, values) + } + + toJSON () { + return R.pick(this, FIELDS) + } +} + +module.exports = Employee diff --git a/server/models/expense.js b/server/models/expense.js index e69de29bb..f817324ca 100644 --- a/server/models/expense.js +++ b/server/models/expense.js @@ -0,0 +1,18 @@ +const R = require('ramda') + +const FIELDS = [ + 'id', 'date', 'category_id', 'employee_id', 'tax_id', + 'description', 'amount' +] + +class Expense { + constructor (values = {}) { + Object.assign(this, values) + } + + toJSON () { + return R.pick(this, FIELDS) + } +} + +module.exports = Expense diff --git a/server/models/expense_category.js b/server/models/expense_category.js index e69de29bb..01eb84de7 100644 --- a/server/models/expense_category.js +++ b/server/models/expense_category.js @@ -0,0 +1,15 @@ +const R = require('ramda') + +const FIELDS = ['id', 'name'] + +class ExpenseCategory { + constructor (values = {}) { + Object.assign(this, values) + } + + toJSON () { + return R.pick(this, FIELDS) + } +} + +module.exports = ExpenseCategory diff --git a/server/models/tax.js b/server/models/tax.js index e69de29bb..64648a088 100644 --- a/server/models/tax.js +++ b/server/models/tax.js @@ -0,0 +1,15 @@ +const R = require('ramda') + +const FIELDS = ['id', 'name', 'year', 'percentage'] + +class Tax { + constructor (values = {}) { + Object.assign(this, values) + } + + toJSON () { + return R.pick(this, FIELDS) + } +} + +module.exports = Tax From 3e88316126cea640ccc7792f71b112151402918f Mon Sep 17 00:00:00 2001 From: Frederic Gingras Date: Wed, 18 Jan 2017 12:36:37 -0500 Subject: [PATCH 12/27] server: repositories (& database utility) --- README.md | 5 ++++ package.json | 4 ++- server.js | 16 +++++++++++ server/library/database.js | 34 +++++++++++++++++++++++ server/models/employee.js | 2 +- server/models/expense.js | 4 +-- server/models/expense_category.js | 2 +- server/models/tax.js | 2 +- server/repositories/employees.js | 22 +++++++++++++++ server/repositories/expense_categories.js | 22 +++++++++++++++ server/repositories/expenses.js | 22 +++++++++++++++ server/repositories/taxes.js | 22 +++++++++++++++ yarn.lock | 8 ++++++ 13 files changed, 159 insertions(+), 6 deletions(-) create mode 100644 server/library/database.js diff --git a/README.md b/README.md index 3e3b9c93c..4d1d57903 100644 --- a/README.md +++ b/README.md @@ -93,6 +93,11 @@ case but can be automated with Ansible/Tower | Chef/Server | Puppet/Server. ### What I am proud of +### Other considerations + +- Employees addresses could have been further normalized +- Front-end production build is far from being optimal. Should really be static assets served from disk by Nginx, not by Node.js. + ### Questions - Is the only line in the example data, taxed in NY, using 7.5% not 8.875% an error? diff --git a/package.json b/package.json index d9b79170e..0fff50341 100644 --- a/package.json +++ b/package.json @@ -8,10 +8,12 @@ "dependencies": { "bankai": "^5.2.1", "choo": "^4.0.3", + "humps": "^2.0.0", "knex": "^0.12.6", "merry": "^4.1.0", "pg": "^6.1.2", - "ramda": "^0.23.0" + "ramda": "^0.23.0", + "ulid": "^0.1.0" }, "devDependencies": { "standard": "^8.6.0", diff --git a/server.js b/server.js index 7ade04e4e..013c28fae 100644 --- a/server.js +++ b/server.js @@ -1,18 +1,34 @@ const fs = require('fs') const path = require('path') const http = require('http') +const knex = require('knex') const merry = require('merry') const bankai = require('bankai') +const Database = require('./server/library/database') +const Container = require('./server/library/container') + // Server setup const env = merry.env({PORT: 8000}) const production = env.NODE_ENV === 'production' const app = merry() +const container = new Container(app.log.debug.bind(app.log)) +container.set('config', env) +container.set('db', new Database(knex(require('./knexfile')))) +container.load(require('./server/helpers/csv')) +container.load(require('./server/repositories/tax')) +container.load(require('./server/repositories/employee')) +container.load(require('./server/repositories/expense_category')) +container.load(require('./server/repositories/expense')) +container.load(require('./server/services/import')) +container.load(require('./server/services/report')) + app.router([ // Static assets ['/', serveStaticFile('index.html', 'text/html')], + ['/import', serveStaticFile('index.html', 'text/html')], ['/app.js', serveClientJs], ['/tachyons.min.css', serveStaticFile('tachyons.min.css', 'text/css')], diff --git a/server/library/database.js b/server/library/database.js new file mode 100644 index 000000000..d115bfe97 --- /dev/null +++ b/server/library/database.js @@ -0,0 +1,34 @@ +const ulid = require('ulid') +const humps = require('humps') + +class Database { + constructor(knex) { + this.knex = knex + } + + async findById(TABLE, Entity, id) { + const data = await this.db + .select() + .from(TABLE) + .where('id', id) + .limit(1) + + if (!data || data.length === 0) { + return null + } + return new Entity(humps.camelizeKeys(data[0])) + } + + async create(TABLE, Entity, entity) { + entity.id = ulid(); // Assign a new id + + const data = await this.db + .into(TABLE) + .insert(humps.decamelizeKeys(entity.toObject())) + .returning('*') + + return new Entity(humps.camelizeKeys(data[0])); + } +} + +module.exports = Database; diff --git a/server/models/employee.js b/server/models/employee.js index ea69a2367..99f7b2741 100644 --- a/server/models/employee.js +++ b/server/models/employee.js @@ -7,7 +7,7 @@ class Employee { Object.assign(this, values) } - toJSON () { + toObject () { return R.pick(this, FIELDS) } } diff --git a/server/models/expense.js b/server/models/expense.js index f817324ca..eb6ddca41 100644 --- a/server/models/expense.js +++ b/server/models/expense.js @@ -1,7 +1,7 @@ const R = require('ramda') const FIELDS = [ - 'id', 'date', 'category_id', 'employee_id', 'tax_id', + 'id', 'date', 'categoryId', 'employeeId', 'taxId', 'description', 'amount' ] @@ -10,7 +10,7 @@ class Expense { Object.assign(this, values) } - toJSON () { + toObject () { return R.pick(this, FIELDS) } } diff --git a/server/models/expense_category.js b/server/models/expense_category.js index 01eb84de7..0b996d25c 100644 --- a/server/models/expense_category.js +++ b/server/models/expense_category.js @@ -7,7 +7,7 @@ class ExpenseCategory { Object.assign(this, values) } - toJSON () { + toObject () { return R.pick(this, FIELDS) } } diff --git a/server/models/tax.js b/server/models/tax.js index 64648a088..797b6b776 100644 --- a/server/models/tax.js +++ b/server/models/tax.js @@ -7,7 +7,7 @@ class Tax { Object.assign(this, values) } - toJSON () { + toObject () { return R.pick(this, FIELDS) } } diff --git a/server/repositories/employees.js b/server/repositories/employees.js index e69de29bb..3c558b879 100644 --- a/server/repositories/employees.js +++ b/server/repositories/employees.js @@ -0,0 +1,22 @@ +const Employee = require('../models/employee'); + +const TABLE = 'employees'; + +class EmployeesRepository { + constructor(db) { + this.db = db; + } + + find(id) { + return this.db.findById(TABLE, Employee, id) + } + + create(employee) { + return this.db.create(TABLE, Employee, employee) + } +} + +EmployeesRepository.dependencyName = 'repo:employees' +EmployeesRepository.dependencies = ['db'] + +module.exports = EmployeesRepository diff --git a/server/repositories/expense_categories.js b/server/repositories/expense_categories.js index e69de29bb..33c341fbe 100644 --- a/server/repositories/expense_categories.js +++ b/server/repositories/expense_categories.js @@ -0,0 +1,22 @@ +const ExpenseCategory = require('../models/expense_category'); + +const TABLE = 'expense_categories'; + +class ExpenseCategoriesRepository { + constructor(db) { + this.db = db; + } + + find(id) { + return this.db.findById(TABLE, ExpenseCategory, id) + } + + create(expenseCategory) { + return this.db.create(TABLE, ExpenseCategory, expenseCategory) + } +} + +ExpenseCategoriesRepository.dependencyName = 'repo:expenseCategories' +ExpenseCategoriesRepository.dependencies = ['db'] + +module.exports = ExpenseCategoriesRepository diff --git a/server/repositories/expenses.js b/server/repositories/expenses.js index e69de29bb..f6d441407 100644 --- a/server/repositories/expenses.js +++ b/server/repositories/expenses.js @@ -0,0 +1,22 @@ +const Expense = require('../models/expense'); + +const TABLE = 'expenses'; + +class ExpensesRepository { + constructor(db) { + this.db = db; + } + + find(id) { + return this.db.findById(TABLE, Expense, id) + } + + create(expense) { + return this.db.create(TABLE, Expense, expense) + } +} + +ExpenseCategoriesRepository.dependencyName = 'repo:expenses' +ExpenseCategoriesRepository.dependencies = ['db'] + +module.exports = ExpensesRepository diff --git a/server/repositories/taxes.js b/server/repositories/taxes.js index e69de29bb..73b0da2b9 100644 --- a/server/repositories/taxes.js +++ b/server/repositories/taxes.js @@ -0,0 +1,22 @@ +const Tax = require('../models/tax'); + +const TABLE = 'taxes'; + +class TaxesRepository { + constructor(db) { + this.db = db; + } + + find(id) { + return this.db.findById(TABLE, Tax, id) + } + + create(tax) { + return this.db.create(TABLE, Tax, tax) + } +} + +TaxesRepository.dependencyName = 'repo:taxes' +TaxesRepository.dependencies = ['db'] + +module.exports = TaxesRepository diff --git a/yarn.lock b/yarn.lock index d61d658e7..827699841 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1915,6 +1915,10 @@ https-browserify@~0.0.0: version "0.0.1" resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-0.0.1.tgz#3f91365cabe60b77ed0ebba24b454e3e09d95a82" +humps@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/humps/-/humps-2.0.0.tgz#dd4a423e9784626fe7b9f19fde0baff659b40173" + hyperscript-attribute-to-property@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/hyperscript-attribute-to-property/-/hyperscript-attribute-to-property-1.0.0.tgz#825308d49bb8e2957923f731981bcc811cad7aff" @@ -4086,6 +4090,10 @@ uid-number@~0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" +ulid@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/ulid/-/ulid-0.1.0.tgz#9044142d2b4b7bb2551ed7d6e2d301c46e1d3725" + umd@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/umd/-/umd-3.0.1.tgz#8ae556e11011f63c2596708a8837259f01b3d60e" From 98a5c2e6748c7265e8378367709a471b1577a696 Mon Sep 17 00:00:00 2001 From: Frederic Gingras Date: Wed, 18 Jan 2017 13:18:21 -0500 Subject: [PATCH 13/27] server: library: database tests --- Makefile | 2 +- server/library/database.js | 9 +- INSTRUCTIONS.md => support/INSTRUCTIONS.md | 0 data_example.csv => support/data_example.csv | 0 tests/unit/database_library.js | 92 ++++++++++++++++++++ 5 files changed, 98 insertions(+), 5 deletions(-) rename INSTRUCTIONS.md => support/INSTRUCTIONS.md (100%) rename data_example.csv => support/data_example.csv (100%) create mode 100644 tests/unit/database_library.js diff --git a/Makefile b/Makefile index e1f4269ab..e94b8c22b 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ PATH := ./node_modules/.bin:$(PATH) # node or yarn are not on $PATH NODE := node YARN := yarn -TAPE := tape +TAPE := $(NODE) --harmony ./node_modules/.bin/tape TAPSPEC := tap-spec STANDARD := standard diff --git a/server/library/database.js b/server/library/database.js index d115bfe97..e5002f312 100644 --- a/server/library/database.js +++ b/server/library/database.js @@ -2,12 +2,13 @@ const ulid = require('ulid') const humps = require('humps') class Database { - constructor(knex) { + constructor(knex, idGenerator = ulid) { this.knex = knex + this.idGenerator = idGenerator } async findById(TABLE, Entity, id) { - const data = await this.db + const data = await this.knex .select() .from(TABLE) .where('id', id) @@ -20,9 +21,9 @@ class Database { } async create(TABLE, Entity, entity) { - entity.id = ulid(); // Assign a new id + entity.id = this.idGenerator(); // Assign a new id - const data = await this.db + const data = await this.knex .into(TABLE) .insert(humps.decamelizeKeys(entity.toObject())) .returning('*') diff --git a/INSTRUCTIONS.md b/support/INSTRUCTIONS.md similarity index 100% rename from INSTRUCTIONS.md rename to support/INSTRUCTIONS.md diff --git a/data_example.csv b/support/data_example.csv similarity index 100% rename from data_example.csv rename to support/data_example.csv diff --git a/tests/unit/database_library.js b/tests/unit/database_library.js new file mode 100644 index 000000000..0b67167b1 --- /dev/null +++ b/tests/unit/database_library.js @@ -0,0 +1,92 @@ +const test = require('tape') + +const Database = require('../../server/library/database') + +test('Database: findById: calls knex and creates entity right', (t) => { + const dbResult = [{id: 1, tax_id: 'abc123'}] + const fakeKnex = new FakeKnex(dbResult) + const db = new Database(fakeKnex) + + t.plan(2) + db.findById('table', Entity, 1).then((result) => { + t.deepEqual(fakeKnex.callLog, [ + ['select'], + ['from', 'table'], + ['where', 'id', 1], + ['limit', 1] + ]) + t.deepEqual(result, {id: 1, taxId: 'abc123'}) + }).catch(err => t.fail(err)) +}) + +test('Database: findById: return null when no result', (t) => { + const dbResult = [] + const fakeKnex = new FakeKnex(dbResult) + const db = new Database(fakeKnex) + + t.plan(1) + db.findById('table', Entity, 1).then((result) => { + t.equal(result, null) + }).catch(err => t.fail(err)) +}) + +test('Database: create: calls knex right', (t) => { + const dbResult = [{id: 1, tax_id: 'abc123', created_at: '2017'}] + const fakeKnex = new FakeKnex(dbResult) + const staticIdGenerator = () => 123 + const db = new Database(fakeKnex, staticIdGenerator) + const entity = new Entity({taxId: 'abc123'}) + + t.plan(2) + db.create('table', Entity, entity).then((result) => { + t.deepEqual(fakeKnex.callLog, [ + ['into', 'table'], + ['insert', {id: 123, tax_id: 'abc123'}], // Notice camelCase -> snake_case + ['returning', '*'] + ]) + + // Notice snake_case -> camelCase (this is based on `result`) + t.deepEqual(result, {id: 1, taxId: 'abc123', createdAt: '2017'}) + }).catch(err => t.fail(err)) +}) + +class Entity { + constructor(params) { + Object.assign(this, params) + } + + toObject() { + return this + } +} + +class FakeKnex { + constructor(result) { + this.callLog = [] + this.result = result + this.then = this.then.bind(this) + + const methods = [ + 'select', 'from', 'where', 'limit', 'insert', 'into', + 'returning' + ] + for (let method of methods) { + this[method] = this.buildStub(method) + } + } + + then(successHandler, errorHandler) { + if (this.result instanceof Error) { + errorHandler(this.result) + } else { + successHandler(this.result) + } + } + + buildStub(name) { + return (...args) => { + this.callLog.push([name].concat(args)) + return this // Make method chaining work + } + } +} From 62d127f0a63ef9b31536af70dd30ce3c3237691f Mon Sep 17 00:00:00 2001 From: Frederic Gingras Date: Wed, 18 Jan 2017 16:19:23 -0500 Subject: [PATCH 14/27] server: services: import start --- Makefile | 4 +- README.md | 2 + migrations/20170116181958_add_taxes_table.js | 15 --- .../20170116182042_add_expenses_table.js | 2 +- server/controllers/import.js | 0 server/controllers/report.js | 0 server/library/database.js | 14 +-- server/models/tax.js | 2 +- server/repositories/employees.js | 30 +++-- server/repositories/expense_categories.js | 33 ++++-- server/repositories/expenses.js | 26 +++-- server/repositories/taxes.js | 37 ++++-- server/services/import.js | 105 ++++++++++++++++++ tests/unit/database_library.js | 20 ++-- 14 files changed, 216 insertions(+), 74 deletions(-) delete mode 100644 migrations/20170116181958_add_taxes_table.js create mode 100644 server/controllers/import.js create mode 100644 server/controllers/report.js diff --git a/Makefile b/Makefile index e94b8c22b..99b2992a2 100644 --- a/Makefile +++ b/Makefile @@ -36,8 +36,8 @@ test: ## Run all tests including style checks test: lint test-unit test-integration test-system db-create: ## Creates a new database for the application to use (run once) - psql -c "CREATE ROLE wave_challenge WITH SUPERUSER LOGIN PASSWORD 'wave_challenge'" - psql -c "CREATE DATABASE wave_challenge WITH OWNER wave_challenge" + psql -c "CREATE IF NOT EXIST ROLE wave_challenge WITH SUPERUSER LOGIN PASSWORD 'wave_challenge'" + psql -c "CREATE IF NOT EXIST DATABASE wave_challenge WITH OWNER wave_challenge" db-migrate: ## Runs all pending migrations againt the database ./node_modules/.bin/knex migrate:latest diff --git a/README.md b/README.md index 4d1d57903..bf9b71220 100644 --- a/README.md +++ b/README.md @@ -96,6 +96,8 @@ case but can be automated with Ansible/Tower | Chef/Server | Puppet/Server. ### Other considerations - Employees addresses could have been further normalized +- Taxes matching is a bit brittle, having only the state 2 letter code means we can match US tax names but would have trouble with other countries / different formats +- On the subject of taxes, assuming they change only yearly and that it's effective on Jan 1 is quite brittle, we migth come to mid-year tax changes, or simply later than exactly Jan 1. - Front-end production build is far from being optimal. Should really be static assets served from disk by Nginx, not by Node.js. ### Questions diff --git a/migrations/20170116181958_add_taxes_table.js b/migrations/20170116181958_add_taxes_table.js deleted file mode 100644 index cbf9ca0c0..000000000 --- a/migrations/20170116181958_add_taxes_table.js +++ /dev/null @@ -1,15 +0,0 @@ -exports.up = function (knex, Promise) { - return knex.schema.createTable('taxes', function (t) { - t.string('id', 26).notNullable().primary() - t.text('name').notNullable() - t.integer('year').notNullable() - t.decimal('percentage', 7, 5).notNullable() // e.g. 99.99999 - - t.index(['name', 'year']) - t.unique(['name', 'year']) - }) -} - -exports.down = function (knex, Promise) { - return knex.schema.dropTable('taxes') -} diff --git a/migrations/20170116182042_add_expenses_table.js b/migrations/20170116182042_add_expenses_table.js index c18f7e006..67a33d302 100644 --- a/migrations/20170116182042_add_expenses_table.js +++ b/migrations/20170116182042_add_expenses_table.js @@ -4,7 +4,7 @@ exports.up = function (knex, Promise) { t.timestamp('date').notNullable().index() t.string('category_id', 26).notNullable().references('id').inTable('expense_categories') t.string('employee_id', 26).notNullable().references('id').inTable('employees') - t.string('tax_id', 26).notNullable().references('id').inTable('taxes') + t.text('tax_id').notNullable() t.text('description').notNullable() t.integer('amount').notNullable() }) diff --git a/server/controllers/import.js b/server/controllers/import.js new file mode 100644 index 000000000..e69de29bb diff --git a/server/controllers/report.js b/server/controllers/report.js new file mode 100644 index 000000000..e69de29bb diff --git a/server/library/database.js b/server/library/database.js index e5002f312..85bab1b59 100644 --- a/server/library/database.js +++ b/server/library/database.js @@ -2,16 +2,16 @@ const ulid = require('ulid') const humps = require('humps') class Database { - constructor(knex, idGenerator = ulid) { + constructor (knex, idGenerator = ulid) { this.knex = knex this.idGenerator = idGenerator } - async findById(TABLE, Entity, id) { + async findWhere (TABLE, Entity, where) { const data = await this.knex .select() .from(TABLE) - .where('id', id) + .where(humps.decamelizeKeys(where)) .limit(1) if (!data || data.length === 0) { @@ -20,16 +20,16 @@ class Database { return new Entity(humps.camelizeKeys(data[0])) } - async create(TABLE, Entity, entity) { - entity.id = this.idGenerator(); // Assign a new id + async create (TABLE, Entity, entity) { + entity.id = this.idGenerator() // Assign a new id const data = await this.knex .into(TABLE) .insert(humps.decamelizeKeys(entity.toObject())) .returning('*') - return new Entity(humps.camelizeKeys(data[0])); + return new Entity(humps.camelizeKeys(data[0])) } } -module.exports = Database; +module.exports = Database diff --git a/server/models/tax.js b/server/models/tax.js index 797b6b776..5341d7216 100644 --- a/server/models/tax.js +++ b/server/models/tax.js @@ -1,6 +1,6 @@ const R = require('ramda') -const FIELDS = ['id', 'name', 'year', 'percentage'] +const FIELDS = ['id', 'country', 'state', 'type', 'effectiveSince', 'percent'] class Tax { constructor (values = {}) { diff --git a/server/repositories/employees.js b/server/repositories/employees.js index 3c558b879..3d9f8fd03 100644 --- a/server/repositories/employees.js +++ b/server/repositories/employees.js @@ -1,22 +1,34 @@ -const Employee = require('../models/employee'); +const Employee = require('../models/employee') -const TABLE = 'employees'; +const TABLE = 'employees' class EmployeesRepository { - constructor(db) { - this.db = db; + constructor (db, cache) { + this.db = db + this.cache = cache } - find(id) { - return this.db.findById(TABLE, Employee, id) + findById (id) { + return this.db.findWhere(TABLE, Employee, {id}) } - create(employee) { - return this.db.create(TABLE, Employee, employee) + findByName (name) { + return this.db.findWhere(TABLE, Employee, {name}) + } + + async findOrCreate (employee) { + const dbEmployee = await this.findByName(employee.name) + if (dbEmployee) { + return dbEmployee + } + + const e = await this.db.create(TABLE, Employee, employee) + this.cache.set(`db:entities:${TABLE}:${e.id}`, e) + return e } } EmployeesRepository.dependencyName = 'repo:employees' -EmployeesRepository.dependencies = ['db'] +EmployeesRepository.dependencies = ['db', 'cache'] module.exports = EmployeesRepository diff --git a/server/repositories/expense_categories.js b/server/repositories/expense_categories.js index 33c341fbe..b41a925d1 100644 --- a/server/repositories/expense_categories.js +++ b/server/repositories/expense_categories.js @@ -1,22 +1,37 @@ -const ExpenseCategory = require('../models/expense_category'); +const ExpenseCategory = require('../models/expense_category') -const TABLE = 'expense_categories'; +const TABLE = 'expense_categories' class ExpenseCategoriesRepository { - constructor(db) { - this.db = db; + constructor (db, cache) { + this.db = db + this.cache = cache } - find(id) { - return this.db.findById(TABLE, ExpenseCategory, id) + findById (id) { + return this.cache.try( + `db:entities:${TABLE}:${id}`, + () => this.db.findWhere(TABLE, ExpenseCategory, {id}) + ) } - create(expenseCategory) { - return this.db.create(TABLE, ExpenseCategory, expenseCategory) + findByName (name) { + return this.db.findWhere(TABLE, ExpenseCategory, {name}) + } + + async findOrCreate (category) { + const dbCategory = await this.findByName(category.name) + if (dbCategory) { + return dbCategory + } + + const c = await this.db.create(TABLE, ExpenseCategory, category) + this.cache.set(`db:entities:${TABLE}:${c.id}`, c) + return c } } ExpenseCategoriesRepository.dependencyName = 'repo:expenseCategories' -ExpenseCategoriesRepository.dependencies = ['db'] +ExpenseCategoriesRepository.dependencies = ['db', 'cache'] module.exports = ExpenseCategoriesRepository diff --git a/server/repositories/expenses.js b/server/repositories/expenses.js index f6d441407..77998a1f2 100644 --- a/server/repositories/expenses.js +++ b/server/repositories/expenses.js @@ -1,22 +1,28 @@ -const Expense = require('../models/expense'); +const Expense = require('../models/expense') -const TABLE = 'expenses'; +const TABLE = 'expenses' class ExpensesRepository { - constructor(db) { - this.db = db; + constructor (db, cache) { + this.db = db + this.cache = cache } - find(id) { - return this.db.findById(TABLE, Expense, id) + async findById (id) { + return this.cache.try( + `db:entities:${TABLE}:${id}`, + () => this.db.findWhere(TABLE, Expense, {id}) + ) } - create(expense) { - return this.db.create(TABLE, Expense, expense) + async create (expense) { + const e = await this.db.create(TABLE, Expense, expense) + this.cache.set(`db:entities:${TABLE}:${e.id}`, e) + return e } } -ExpenseCategoriesRepository.dependencyName = 'repo:expenses' -ExpenseCategoriesRepository.dependencies = ['db'] +ExpensesRepository.dependencyName = 'repo:expenses' +ExpensesRepository.dependencies = ['db', 'cache'] module.exports = ExpensesRepository diff --git a/server/repositories/taxes.js b/server/repositories/taxes.js index 73b0da2b9..fa62cda61 100644 --- a/server/repositories/taxes.js +++ b/server/repositories/taxes.js @@ -1,22 +1,39 @@ -const Tax = require('../models/tax'); +const TAXES = {} -const TABLE = 'taxes'; +function registerTax (country, state, type, effectiveSince, percent) { + const id = `${country}-${state}-${type}-${effectiveSince.getFullYear()}` + TAXES[id] = {id, country, state, type, effectiveSince, percent} +} + +// Register all known taxes in a static object +// +// This makes for fast and easy retrival, those values are not dynamic and +// frozen in time once declared. (Although saving a copy of the percent on +// and expense or invoice is not a bad idea in case we come to violate that +registerTax('US', 'CA', 'sales', new Date(2017, 0, 1), 7.5) +registerTax('US', 'NY', 'sales', new Date(2017, 0, 1), 8.875) class TaxesRepository { - constructor(db) { - this.db = db; - } + findByNameSync (name) { + const match = name.match(/([A-Z]{2})\sSales tax/) + if (match) { + const stateCode = match[1] + return TAXES[`US-${stateCode}-sales-2017`] + } - find(id) { - return this.db.findById(TABLE, Tax, id) + throw new Error('TaxesRepository: findByName: could not guess tax for name: ' + name) } - create(tax) { - return this.db.create(TABLE, Tax, tax) + // Finds a tax "spoken" name, used when importing from external sources + // + // (Returns a promise to be homogenous with how other repo work and + // for future proofing) + findByName (name) { + return new Promise((resolve) => resolve(this.findByNameSync(name))) } } TaxesRepository.dependencyName = 'repo:taxes' -TaxesRepository.dependencies = ['db'] +TaxesRepository.dependencies = [] module.exports = TaxesRepository diff --git a/server/services/import.js b/server/services/import.js index e69de29bb..287dadb9b 100644 --- a/server/services/import.js +++ b/server/services/import.js @@ -0,0 +1,105 @@ +const Employee = require('../models/Employee') +const ExpenseCategory = require('../models/ExpenseCategory') + +class ImportService { + constructor ( + csvHelper, taxesRepo, employeesRepo, + expensesRepo, expenseCategoriesRepo + ) { + this.csvHelper = csvHelper + this.taxesRepo = taxesRepo + this.employeesRepo = employeesRepo + this.expensesRepo = expensesRepo + this.expenseCategoriesRepo = expenseCategoriesRepo + } + + importParseCSV (csvData) { + const columns = [ + 'date', 'category', 'employeeName', 'employeeAddress', + 'description', 'amount', 'taxName' + ] + const rawExpenses = this.csvHelper(columns, csvData) + + // Now, all data is still strings, let cast those to the right type + return rawExpenses.map((e) => { + // Parse date from "12/20/2000" + const [dateM, dateD, dateY] = e.date.split('/') + e.date = new Date(dateY, dateM, dateD) + + // Parse amount as float + e.amount = parseFloat(e.amount) + + return e + }) + } + + async importEmployees (expenses) { + for (let expense of expenses) { + // Create employee + const employee = await this.employeesRepo.findOrCreate(new Employee({ + name: expense.employeeName, + address: expense.employeeAddress + })) + + // Save newly assigned employee id on expense + expense.employeeId = employee.id + } + + return expenses + } + + async importExpenseCategory (expenses) { + const findOrCreate = this.expenseCategoriesRepo.findOrCreate + + for (let expense of expenses) { + // Create employee + const category = await findOrCreate(new ExpenseCategory({ + name: expense.category + })) + + // Save newly assigned category id on expense + expense.categoryId = category.id + } + } + + async importFindTaxIds (expenses) { + for (let expense of expenses) { + // Create employee + const tax = await this.taxesRepo.findByName(new Employee()) + + expense.taxId = tax.id + } + } + + importCreateExpenses (expenses) { + const create = this.expensesRepo.create.bind(this.expensesRepo) + return Promise.all(expenses.map(create)) + } + + // Parses expense CSV and saves it's content to the database + async import (csvData) { + // Step 1: Parse CSV Data + const expenses = this.importCSV(csvData) + + // Step 2: Extract employees and save those missing from the database + await this.importEmployees(expenses) + + // Step 3: Extract expense categories and save the missing ones + await this.importExpenseCategories(expenses) + + // Step 4: Match taxName with taxIds + await this.importFindTaxIds(expenses) + + // Step 5: Create all expenses (now we ensured related models exist) + return await this.importCreateExpenses(expenses) + } +} + +ImportService.dependencyName = 'services:import' +ImportService.dependencies = [ + 'helpers:csv', + 'repo:taxes', 'repo:employees', + 'repo:expenses', 'repo:expense_categories' +] + +module.exports = ImportService diff --git a/tests/unit/database_library.js b/tests/unit/database_library.js index 0b67167b1..d0f9fd5c8 100644 --- a/tests/unit/database_library.js +++ b/tests/unit/database_library.js @@ -2,30 +2,30 @@ const test = require('tape') const Database = require('../../server/library/database') -test('Database: findById: calls knex and creates entity right', (t) => { +test('Database: findWhere: calls knex and creates entity right', (t) => { const dbResult = [{id: 1, tax_id: 'abc123'}] const fakeKnex = new FakeKnex(dbResult) const db = new Database(fakeKnex) t.plan(2) - db.findById('table', Entity, 1).then((result) => { + db.findWhere('table', Entity, {someId: 1}).then((result) => { t.deepEqual(fakeKnex.callLog, [ ['select'], ['from', 'table'], - ['where', 'id', 1], + ['where', {some_id: 1}], ['limit', 1] ]) t.deepEqual(result, {id: 1, taxId: 'abc123'}) }).catch(err => t.fail(err)) }) -test('Database: findById: return null when no result', (t) => { +test('Database: findWhere: return null when no result', (t) => { const dbResult = [] const fakeKnex = new FakeKnex(dbResult) const db = new Database(fakeKnex) t.plan(1) - db.findById('table', Entity, 1).then((result) => { + db.findWhere('table', Entity, {id: 1}).then((result) => { t.equal(result, null) }).catch(err => t.fail(err)) }) @@ -51,17 +51,17 @@ test('Database: create: calls knex right', (t) => { }) class Entity { - constructor(params) { + constructor (params) { Object.assign(this, params) } - toObject() { + toObject () { return this } } class FakeKnex { - constructor(result) { + constructor (result) { this.callLog = [] this.result = result this.then = this.then.bind(this) @@ -75,7 +75,7 @@ class FakeKnex { } } - then(successHandler, errorHandler) { + then (successHandler, errorHandler) { if (this.result instanceof Error) { errorHandler(this.result) } else { @@ -83,7 +83,7 @@ class FakeKnex { } } - buildStub(name) { + buildStub (name) { return (...args) => { this.callLog.push([name].concat(args)) return this // Make method chaining work From b2ced896a1117593ae6c0d89350b11007d52d7b1 Mon Sep 17 00:00:00 2001 From: Frederic Gingras Date: Wed, 18 Jan 2017 16:29:34 -0500 Subject: [PATCH 15/27] server: library: cache & memory-cache --- server.js | 5 ++++- server/library/cache.js | 23 +++++++++++++++++++++++ server/library/memory-cache.js | 22 ++++++++++++++++++++++ server/repositories/employees.js | 7 +++++-- server/repositories/expense_categories.js | 2 +- server/repositories/expenses.js | 2 +- 6 files changed, 56 insertions(+), 5 deletions(-) create mode 100644 server/library/cache.js create mode 100644 server/library/memory-cache.js diff --git a/server.js b/server.js index 013c28fae..e2b32009c 100644 --- a/server.js +++ b/server.js @@ -5,8 +5,10 @@ const knex = require('knex') const merry = require('merry') const bankai = require('bankai') -const Database = require('./server/library/database') const Container = require('./server/library/container') +const Database = require('./server/library/database') +const Cache = require('./server/library/cache') +const MemoryCache = require('./server/library/memory-cache') // Server setup @@ -17,6 +19,7 @@ const app = merry() const container = new Container(app.log.debug.bind(app.log)) container.set('config', env) container.set('db', new Database(knex(require('./knexfile')))) +container.set('cache', new Cache(new MemoryCache())) container.load(require('./server/helpers/csv')) container.load(require('./server/repositories/tax')) container.load(require('./server/repositories/employee')) diff --git a/server/library/cache.js b/server/library/cache.js new file mode 100644 index 000000000..2b7f7fec3 --- /dev/null +++ b/server/library/cache.js @@ -0,0 +1,23 @@ +// Cache implementation wrapper providing utility functions +class Cache { + constructor (cache) { + this.cache = cache + + this.get = cache.get.bind(cache) + this.set = cache.set.bind(cache) + this.del = cache.del.bind(cache) + } + + async try (key, fetchFn) { + const obj = await this.cache.get(key) + if (obj) { + return obj + } + + const freshObj = await fetchFn() + await this.cache.set(key, freshObj) + return freshObj + } +} + +module.exports = Cache diff --git a/server/library/memory-cache.js b/server/library/memory-cache.js new file mode 100644 index 000000000..fc8f14a4a --- /dev/null +++ b/server/library/memory-cache.js @@ -0,0 +1,22 @@ +// Cache implementation saving data in memory +class MemoryCache { + constructor () { + this.values = {} + } + + get (key) { + return Promise.resolve(this.values[key]) + } + + set (key, value) { + this.values[key] = value + return Promise.resolve() + } + + del (key) { + delete this.values[key] + return Promise.resolve() + } +} + +module.exports = MemoryCache diff --git a/server/repositories/employees.js b/server/repositories/employees.js index 3d9f8fd03..3005b1f00 100644 --- a/server/repositories/employees.js +++ b/server/repositories/employees.js @@ -9,7 +9,10 @@ class EmployeesRepository { } findById (id) { - return this.db.findWhere(TABLE, Employee, {id}) + return this.cache.try( + `db:entities:${TABLE}:${id}`, + () => this.db.findWhere(TABLE, Employee, {id}) + ) } findByName (name) { @@ -23,7 +26,7 @@ class EmployeesRepository { } const e = await this.db.create(TABLE, Employee, employee) - this.cache.set(`db:entities:${TABLE}:${e.id}`, e) + await this.cache.set(`db:entities:${TABLE}:${e.id}`, e) return e } } diff --git a/server/repositories/expense_categories.js b/server/repositories/expense_categories.js index b41a925d1..c93f176b5 100644 --- a/server/repositories/expense_categories.js +++ b/server/repositories/expense_categories.js @@ -26,7 +26,7 @@ class ExpenseCategoriesRepository { } const c = await this.db.create(TABLE, ExpenseCategory, category) - this.cache.set(`db:entities:${TABLE}:${c.id}`, c) + await this.cache.set(`db:entities:${TABLE}:${c.id}`, c) return c } } diff --git a/server/repositories/expenses.js b/server/repositories/expenses.js index 77998a1f2..961108e4d 100644 --- a/server/repositories/expenses.js +++ b/server/repositories/expenses.js @@ -17,7 +17,7 @@ class ExpensesRepository { async create (expense) { const e = await this.db.create(TABLE, Expense, expense) - this.cache.set(`db:entities:${TABLE}:${e.id}`, e) + await this.cache.set(`db:entities:${TABLE}:${e.id}`, e) return e } } From 444112c4e80f3c674561229cd9528d7053db402c Mon Sep 17 00:00:00 2001 From: Frederic Gingras Date: Wed, 18 Jan 2017 16:52:17 -0500 Subject: [PATCH 16/27] server: services: report --- README.md | 1 + server/repositories/expenses.js | 5 +++ server/services/report.js | 58 +++++++++++++++++++++++++++++++++ 3 files changed, 64 insertions(+) diff --git a/README.md b/README.md index bf9b71220..a444fb278 100644 --- a/README.md +++ b/README.md @@ -98,6 +98,7 @@ case but can be automated with Ansible/Tower | Chef/Server | Puppet/Server. - Employees addresses could have been further normalized - Taxes matching is a bit brittle, having only the state 2 letter code means we can match US tax names but would have trouble with other countries / different formats - On the subject of taxes, assuming they change only yearly and that it's effective on Jan 1 is quite brittle, we migth come to mid-year tax changes, or simply later than exactly Jan 1. +- We are using a memory based cache implementation even in prod, it would be easy to set a Redis backed implementation in the container for the production use case but was overlooked for the sake of time - Front-end production build is far from being optimal. Should really be static assets served from disk by Nginx, not by Node.js. ### Questions diff --git a/server/repositories/expenses.js b/server/repositories/expenses.js index 961108e4d..f32670c9b 100644 --- a/server/repositories/expenses.js +++ b/server/repositories/expenses.js @@ -15,6 +15,11 @@ class ExpensesRepository { ) } + findAll () { + // Side note: fetching all entities in a database feels wrong ^^, + return this.db.find(TABLE, Expense, {}) + } + async create (expense) { const e = await this.db.create(TABLE, Expense, expense) await this.cache.set(`db:entities:${TABLE}:${e.id}`, e) diff --git a/server/services/report.js b/server/services/report.js index e69de29bb..b3187bd5b 100644 --- a/server/services/report.js +++ b/server/services/report.js @@ -0,0 +1,58 @@ +const {reduce, assoc} = require('ramda') + +class ReportService { + constructor ( + taxesRepo, employeesRepo, expensesRepo, + expenseCategoriesRepo + ) { + this.taxesRepo = taxesRepo + this.employeesRepo = employeesRepo + this.expensesRepo = expensesRepo + this.expenseCategoriesRepo = expenseCategoriesRepo + } + + // Fetches all entities needed for an expense report + // + // The fetching here is a bit naive and could be improved if speed is needed, + // we could write this as 3 sql queries + async report () { + const result = { + expenses: {}, + expenseCategories: {}, + employees: {}, + taxes: {} + } + + // Fetch all concerned expenses + const expenses = await this.expensesRepo.findAll() + result.expenses = reduce((acc, v) => assoc(v.id, v, acc), {}, expenses) + + // Fetch related entities & save them on result + const relationsPromises = [] + relationsPromises.concat(expenses.map(async (e) => { + const employee = await this.employeesRepo.findById(e.employeeId) + result.employees[employee.id] = employee + })) + relationsPromises.concat(expenses.map(async (e) => { + const ecr = this.expenseCategoriesRepo + const category = await ecr.findById(e.categoryId) + result.expenseCategories[category.id] = category + })) + relationsPromises.concat(expenses.map(async (e) => { + const tax = await this.taxesRepo.findById(e.taxId) + result.taxes[tax.id] = tax + })) + + // Wait for all fetches to resolve (happens in parrallel) + await Promise.all(relationsPromises) + return result + } +} + +ReportService.dependencyName = 'services:report' +ReportService.dependencies = [ + 'repo:taxes', 'repo:employees', + 'repo:expenses', 'repo:expense_categories' +] + +module.exports = ReportService From d570a250bf21f10fa9acd5b5aaba936104daca3f Mon Sep 17 00:00:00 2001 From: Frederic Gingras Date: Wed, 18 Jan 2017 19:14:52 -0500 Subject: [PATCH 17/27] server: merry -> koa --- Makefile | 2 +- README.md | 4 +- client/app.js | 73 - client/index.html | 19 - client/models/app.js | 0 client/pages/import.js | 0 client/pages/report.js | 0 package.json | 31 +- server.js | 96 +- server/controllers/import.js | 13 + server/controllers/report.js | 13 + server/middlewares/force-https.js | 6 + server/middlewares/request-logger.js | 6 + server/services/import.js | 6 +- server/services/report.js | 2 +- {client => static}/tachyons.min.css | 0 views/import.hbs | 20 + .../not-found.html => views/layout-error.hbs | 7 +- views/layout.hbs | 39 + views/not-found.hbs | 6 + .../layout.js => views/partials/.gitkeep | 0 yarn.lock | 2082 +++-------------- 22 files changed, 512 insertions(+), 1913 deletions(-) delete mode 100644 client/app.js delete mode 100644 client/index.html delete mode 100644 client/models/app.js delete mode 100644 client/pages/import.js delete mode 100644 client/pages/report.js create mode 100644 server/middlewares/force-https.js create mode 100644 server/middlewares/request-logger.js rename {client => static}/tachyons.min.css (100%) create mode 100644 views/import.hbs rename client/not-found.html => views/layout-error.hbs (78%) create mode 100644 views/layout.hbs create mode 100644 views/not-found.hbs rename client/elements/layout.js => views/partials/.gitkeep (100%) diff --git a/Makefile b/Makefile index 99b2992a2..b8ba96a83 100644 --- a/Makefile +++ b/Makefile @@ -9,7 +9,7 @@ TAPSPEC := tap-spec STANDARD := standard run: ## Start the application server - node --harmony server.js | ./node_modules/.bin/merry + node --harmony server.js | ./node_modules/.bin/pino help: ## Show available targets @printf "$(shell tput -Txterm setaf 2)" diff --git a/README.md b/README.md index a444fb278..7671bc9fd 100644 --- a/README.md +++ b/README.md @@ -36,10 +36,10 @@ interesting and easy to change/update/modify. - [PostgreSQL](https://www.postgresql.org/) - _Stable for a long time, fast when used correctly, wide userbase, versatile_ - Backend - [Node.js](https://nodejs.org/en/) - _Fast to develop in, fast at runtime for our use case, now adopted by many big company, in active development, wide community, packages for many things web related_ - - [Merry](https://github.com/yoshuawuyts/merry/) **New** - _Fast, fun, opiniated but most importantly: simple_ + - [Koa](http://koajs.com/) - _Futuristic, widely known, thoughfully designed, modular_ - [Knex](http://knexjs.org/) - _Versatile, simple, promise based, and fun SQL query builder_ - Frontend - - [Choo](https://github.com/yoshuawuyts/choo/) **New** - _Minimal size, small API, light on tooling, thoughfully designed, fun_ + - [Mustache](http://mustache.github.io/) - _Dead simple, logic less template engine. Avoid scope creep in views_ - [Tachyons](http://tachyons.io/) - _Allows for "designing" in the brower, easier changes to code, and very simple to learn and use_ - Operations - [Ubuntu](https://www.ubuntu.com/server) - _Easy to work with, wide adoption, package availability, most engineers have experience with it_ diff --git a/client/app.js b/client/app.js deleted file mode 100644 index 6da59c8ac..000000000 --- a/client/app.js +++ /dev/null @@ -1,73 +0,0 @@ -const html = require('choo/html') -const choo = require('choo') -const app = choo() - -app.model({ - state: {title: 'Not quite set yet'}, - reducers: { - update: function (state, data) { - return {title: data} - } - } -}) - -function mainView (state, prev, send) { - return html` - - ` - - function update (e) { - send('update', e.target.value) - } -} - -app.router(['/', mainView]) - -const tree = app.start() -const appEl = document.getElementById('app') -appEl.innerHTML = '' -appEl.appendChild(tree) diff --git a/client/index.html b/client/index.html deleted file mode 100644 index e37fe123d..000000000 --- a/client/index.html +++ /dev/null @@ -1,19 +0,0 @@ - - - - - - - - Data Import | Wave - - - - - -
-
Loading...
-
- - - diff --git a/client/models/app.js b/client/models/app.js deleted file mode 100644 index e69de29bb..000000000 diff --git a/client/pages/import.js b/client/pages/import.js deleted file mode 100644 index e69de29bb..000000000 diff --git a/client/pages/report.js b/client/pages/report.js deleted file mode 100644 index e69de29bb..000000000 diff --git a/package.json b/package.json index 0fff50341..577a1980d 100644 --- a/package.json +++ b/package.json @@ -2,23 +2,28 @@ "name": "se-challenge-expenses", "version": "1.0.0", "main": "server.js", - "repository": "git@github.com:kiasaki/wave-challenge.git", + "repository": "git@github.com:kiasaki/se-challenge-expenses.git", "author": "Frederic Gingras ", "license": "MIT", "dependencies": { - "bankai": "^5.2.1", - "choo": "^4.0.3", - "humps": "^2.0.0", - "knex": "^0.12.6", - "merry": "^4.1.0", - "pg": "^6.1.2", - "ramda": "^0.23.0", - "ulid": "^0.1.0" + "humps": "2", + "knex": "0.12", + "koa": "2", + "koa-body": "2", + "koa-convert": "1.2", + "koa-hbs": "0.9", + "koa-router": "7", + "koa-static": "https://github.com/kiasaki/koa-static.git", + "koa2-handlebars": "https://github.com/kiasaki/koa-handlebars.git", + "pg": "6", + "pino": "3", + "ramda": "0.23", + "ulid": "0.1" }, "devDependencies": { - "standard": "^8.6.0", - "tap": "^9.0.3", - "tap-spec": "^4.1.1", - "tape": "^4.6.3" + "standard": "8", + "tap": "9", + "tap-spec": "4", + "tape": "4.6" } } diff --git a/server.js b/server.js index e2b32009c..376b22577 100644 --- a/server.js +++ b/server.js @@ -1,67 +1,59 @@ -const fs = require('fs') const path = require('path') -const http = require('http') const knex = require('knex') -const merry = require('merry') -const bankai = require('bankai') +const log = require('pino')() +const convert = require('koa-convert') +const Koa = require('koa') +const koaBody = require('koa-body')() const Container = require('./server/library/container') const Database = require('./server/library/database') const Cache = require('./server/library/cache') const MemoryCache = require('./server/library/memory-cache') -// Server setup - -const env = merry.env({PORT: 8000}) -const production = env.NODE_ENV === 'production' -const app = merry() - -const container = new Container(app.log.debug.bind(app.log)) -container.set('config', env) +// Setup Container +const container = new Container(log.debug.bind(log)) +container.set('container', container) +container.set('log', log) container.set('db', new Database(knex(require('./knexfile')))) container.set('cache', new Cache(new MemoryCache())) container.load(require('./server/helpers/csv')) -container.load(require('./server/repositories/tax')) -container.load(require('./server/repositories/employee')) -container.load(require('./server/repositories/expense_category')) -container.load(require('./server/repositories/expense')) +container.load(require('./server/repositories/taxes')) +container.load(require('./server/repositories/employees')) +container.load(require('./server/repositories/expense_categories')) +container.load(require('./server/repositories/expenses')) container.load(require('./server/services/import')) container.load(require('./server/services/report')) -app.router([ - // Static assets - ['/', serveStaticFile('index.html', 'text/html')], - ['/import', serveStaticFile('index.html', 'text/html')], - ['/app.js', serveClientJs], - ['/tachyons.min.css', serveStaticFile('tachyons.min.css', 'text/css')], - - // API - ['/import', {post: handleImport}], - - // Error and Not found handlers - ['/404', serveStaticFile('not-found.html', 'text/html')] -]) - -http.createServer(app.start()).listen(env.PORT) -app.log.info('started listening on port ' + env.PORT) - -// Route handlers - -function handleImport (req, res, ctx, done) { - done(merry.error({statusCode: 400})) - done(null, 'hello world') -} - -function serveClientJs (req, res, ctx, done) { - const clientPath = path.join(__dirname, 'client', 'app.js') - const assets = bankai(clientPath, {optimize: production, cssDisabled: true}) - done(null, assets.js(req, res)) -} - -function serveStaticFile (filename, contentType) { - return function (req, res, ctx, done) { - const absolutePath = path.join(__dirname, 'client', filename) - res.writeHead(200, {'Content-Type': contentType}) - done(null, fs.createReadStream(absolutePath).pipe(res)) - } +// Setup Routes +const router = require('koa-router')() + +const reportController = container.create(require('./server/controllers/report')) +router.get('/', reportController.report) + +const importController = container.create(require('./server/controllers/import')) +router.get('/import', importController.import) +router.post('/import', koaBody, importController.import) + +// Setup Server +const staticPath = path.join(__dirname, 'static') +const app = new Koa() +app.proxy = true // Allow reverse proxing +app.use(require('koa2-handlebars')({ + extension: '.hbs', + defaultLayout: 'layout', + viewPath: path.join(__dirname, 'views'), + layoutPath: path.join(__dirname, 'views'), + partialPath: path.join(__dirname, 'views', 'partials') +})) // Setup handlebars for views +app.use(require('koa-static')('static', staticPath)) // Serve static files +app.use(require('./server/middlewares/force-https')) // Force HTTPS in prod +app.use(require('./server/middlewares/request-logger')(log)) // Log requests +app.use(router.routes()) // Router +app.use(router.allowedMethods()) // Unhandled method router middleware +app.use((ctx) => ctx.render('not-found', {layout: 'layout-error'})) // Handle 404s + +if (!module.parent) { + const port = process.env.PORT || 8000 + app.listen(port) + log.info('started listening on port ' + port) } diff --git a/server/controllers/import.js b/server/controllers/import.js index e69de29bb..4a29f9b67 100644 --- a/server/controllers/import.js +++ b/server/controllers/import.js @@ -0,0 +1,13 @@ +class ImportController { + constructor (importService) { + this.importService = importService + } + + async import (ctx) { + await ctx.render('import') + } +} + +ImportController.dependencies = ['services:import'] + +module.exports = ImportController diff --git a/server/controllers/report.js b/server/controllers/report.js index e69de29bb..03ed3aeb1 100644 --- a/server/controllers/report.js +++ b/server/controllers/report.js @@ -0,0 +1,13 @@ +class ReportController { + constructor (reportService) { + this.reportService = reportService + } + + report (ctx) { + ctx.redirect('/import') + } +} + +ReportController.dependencies = ['services:report'] + +module.exports = ReportController diff --git a/server/middlewares/force-https.js b/server/middlewares/force-https.js new file mode 100644 index 000000000..3a8017ae0 --- /dev/null +++ b/server/middlewares/force-https.js @@ -0,0 +1,6 @@ +module.exports = async function forceHTTPS (ctx, next) { + if (!ctx.secure && process.env.NODE_ENV === 'production') { + return ctx.redirect('https://' + ctx.host) + } + await next() +} diff --git a/server/middlewares/request-logger.js b/server/middlewares/request-logger.js new file mode 100644 index 000000000..23175df7c --- /dev/null +++ b/server/middlewares/request-logger.js @@ -0,0 +1,6 @@ +module.exports = function requestLogger (log) { + return (async (ctx, next) => { + log.info({method: ctx.method, url: ctx.url}, 'request') + await next() + }) +} diff --git a/server/services/import.js b/server/services/import.js index 287dadb9b..21b54fcc0 100644 --- a/server/services/import.js +++ b/server/services/import.js @@ -1,5 +1,5 @@ -const Employee = require('../models/Employee') -const ExpenseCategory = require('../models/ExpenseCategory') +const Employee = require('../models/employee') +const ExpenseCategory = require('../models/expense_category') class ImportService { constructor ( @@ -99,7 +99,7 @@ ImportService.dependencyName = 'services:import' ImportService.dependencies = [ 'helpers:csv', 'repo:taxes', 'repo:employees', - 'repo:expenses', 'repo:expense_categories' + 'repo:expenses', 'repo:expenseCategories' ] module.exports = ImportService diff --git a/server/services/report.js b/server/services/report.js index b3187bd5b..bf73698d6 100644 --- a/server/services/report.js +++ b/server/services/report.js @@ -52,7 +52,7 @@ class ReportService { ReportService.dependencyName = 'services:report' ReportService.dependencies = [ 'repo:taxes', 'repo:employees', - 'repo:expenses', 'repo:expense_categories' + 'repo:expenses', 'repo:expenseCategories' ] module.exports = ReportService diff --git a/client/tachyons.min.css b/static/tachyons.min.css similarity index 100% rename from client/tachyons.min.css rename to static/tachyons.min.css diff --git a/views/import.hbs b/views/import.hbs new file mode 100644 index 000000000..8c0f01c71 --- /dev/null +++ b/views/import.hbs @@ -0,0 +1,20 @@ +

+ Step 1: Select data file +

+ +

+ The first step in the import process is selecting a CSV file containing expense data. + Once it's uploaded and saved in the database you'll be able to visualize your per-month + expense report. +

+ +

+ The file needs to include header line and include the following fields: + date, category, employee name, employee address, expense description, pre-tax amount, tax name, tax amount +

+ + + + diff --git a/client/not-found.html b/views/layout-error.hbs similarity index 78% rename from client/not-found.html rename to views/layout-error.hbs index ebb8abee4..25b0f50a8 100644 --- a/client/not-found.html +++ b/views/layout-error.hbs @@ -27,11 +27,6 @@ -

404

-

- Sorry, we can't find the page you are looking for. -
- Please double check the URL or return home. -

+ {{body}} diff --git a/views/layout.hbs b/views/layout.hbs new file mode 100644 index 000000000..78b496899 --- /dev/null +++ b/views/layout.hbs @@ -0,0 +1,39 @@ + + + + + + + + Data Import | Wave + + + + + + +
+
+

+ Data Import +

+
+
+
+
+ + {{body}} + +
+
+ + diff --git a/views/not-found.hbs b/views/not-found.hbs new file mode 100644 index 000000000..6d33ac3d6 --- /dev/null +++ b/views/not-found.hbs @@ -0,0 +1,6 @@ +

404

+

+ Sorry, we can't find the page you are looking for. +
+ Please double check the URL or return home. +

diff --git a/client/elements/layout.js b/views/partials/.gitkeep similarity index 100% rename from client/elements/layout.js rename to views/partials/.gitkeep diff --git a/yarn.lock b/yarn.lock index 827699841..f982361eb 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,16 +2,12 @@ # yarn lockfile v1 -JSONStream@^1.0.3: - version "1.3.0" - resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.0.tgz#680ab9ac6572a8a1a207e0b38721db1c77b215e5" +accepts@^1.2.2: + version "1.3.3" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.3.tgz#c3ca7434938648c3e0d9c1e328dd68b622c284ca" dependencies: - jsonparse "^1.2.0" - through ">=2.2.7 <3" - -abbrev@1: - version "1.0.9" - resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.0.9.tgz#91b4792588a7738c25f35dd6f63752a2f8776135" + mime-types "~2.1.11" + negotiator "0.6.1" acorn-jsx@^3.0.0, acorn-jsx@^3.0.1: version "3.0.1" @@ -19,19 +15,11 @@ acorn-jsx@^3.0.0, acorn-jsx@^3.0.1: dependencies: acorn "^3.0.4" -acorn@^1.0.3: - version "1.2.2" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-1.2.2.tgz#c8ce27de0acc76d896d2b1fad3df588d9e82f014" - -acorn@^2.1.0, acorn@^2.7.0: - version "2.7.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-2.7.0.tgz#ab6e7d9d886aaca8b085bc3312b79a198433f0e7" - -acorn@^3.0.4, acorn@^3.1.0: +acorn@^3.0.4: version "3.3.0" resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" -acorn@^4.0.0, acorn@^4.0.1: +acorn@^4.0.1: version "4.0.4" resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.4.tgz#17a8d6a7a6c4ef538b814ec9abac2779293bf30a" @@ -62,32 +50,17 @@ ansi-escapes@^1.1.0: version "1.4.0" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" -ansi-regex@^0.2.0, ansi-regex@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-0.2.1.tgz#0d8e946967a3d8143f93e24e298525fc1b2235f9" - ansi-regex@^2.0.0: version "2.1.1" resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" -ansi-styles@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-1.1.0.tgz#eaecbf66cd706882760b2f4691582b8f55d7a7de" - ansi-styles@^2.2.1: version "2.2.1" resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" -anymatch@^1.3.0: +any-promise@^1.0.0, any-promise@^1.1.0: version "1.3.0" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.0.tgz#a3e52fa39168c825ff57b0248126ce5a8ff95507" - dependencies: - arrify "^1.0.0" - micromatch "^2.1.5" - -ap@~0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/ap/-/ap-0.1.0.tgz#d8a3f26615379398a1b53ca6cc1a666a0fbfe150" + resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" ap@~0.2.0: version "0.2.0" @@ -99,21 +72,10 @@ append-transform@^0.4.0: dependencies: default-require-extensions "^1.0.0" -aproba@^1.0.3: - version "1.0.4" - resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.0.4.tgz#2713680775e7614c8ba186c065d4e2e52d1072c0" - archy@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/archy/-/archy-1.0.0.tgz#f9c8c13757cc1dd7bc379ac77b2c62a5c2868c40" -are-we-there-yet@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.2.tgz#80e470e95a084794fe1899262c5667c6e88de1b3" - dependencies: - delegates "^1.0.0" - readable-stream "^2.0.0 || ^1.1.13" - argparse@^1.0.7: version "1.0.9" resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86" @@ -130,18 +92,6 @@ arr-flatten@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.0.1.tgz#e5ffe54d45e19f32f216e91eb99c8ce892bb604b" -array-filter@~0.0.0: - version "0.0.1" - resolved "https://registry.yarnpkg.com/array-filter/-/array-filter-0.0.1.tgz#7da8cf2e26628ed732803581fd21f67cacd2eeec" - -array-map@~0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/array-map/-/array-map-0.0.0.tgz#88a2bab73d1cf7bcd5c1b118a003f66f665fa662" - -array-reduce@~0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/array-reduce/-/array-reduce-0.0.0.tgz#173899d3ffd1c7d9383e4479525dbe278cab5f2b" - array-union@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" @@ -160,14 +110,6 @@ arrify@^1.0.0, arrify@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" -asn1.js@^4.0.0: - version "4.9.1" - resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.9.1.tgz#48ba240b45a9280e94748990ba597d216617fd40" - dependencies: - bn.js "^4.0.0" - inherits "^2.0.1" - minimalistic-assert "^1.0.0" - asn1@~0.2.3: version "0.2.3" resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" @@ -180,22 +122,6 @@ assert-plus@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" -assert@^1.4.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/assert/-/assert-1.4.1.tgz#99912d591836b5a6f5b345c0f07eefc08fc65d91" - dependencies: - util "0.10.3" - -astw@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/astw/-/astw-2.0.0.tgz#08121ac8288d35611c0ceec663f6cd545604897d" - dependencies: - acorn "^1.0.3" - -async-each@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" - async@^1.4.0, async@^1.4.2: version "1.5.2" resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a" @@ -290,119 +216,28 @@ balanced-match@^0.4.1: version "0.4.2" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" -bankai@^5.2.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/bankai/-/bankai-5.2.1.tgz#3f155b7268dd46b52525c1ad3135e9f2caae206b" - dependencies: - bole "^3.0.1" - browserify "^13.1.0" - bundle-collapser "^1.2.1" - concat-stream "^1.5.2" - create-html "^1.1.0" - css-extract "^1.2.0" - explain-error "^1.0.3" - from2 "^2.3.0" - garnish "^5.2.0" - map-limit "0.0.1" - mkdirp "^0.5.1" - opn "^4.0.2" - pump "^1.0.1" - resolve "^1.1.7" - sheetify "^6.0.1" - subarg "^1.0.0" - uglifyify "^3.0.4" - unassertify "^2.0.3" - watchify "^3.7.0" - watchify-request "^2.1.0" - xtend "^4.0.1" - yo-yoify "^3.5.0" - -barracks@^9.0.0: - version "9.3.0" - resolved "https://registry.yarnpkg.com/barracks/-/barracks-9.3.0.tgz#8eb222e62e814531c84a0718a83867113bd89c03" - dependencies: - nanotick "^1.1.2" - xtend "^4.0.1" - -base64-js@^1.0.2: - version "1.2.0" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.0.tgz#a39992d723584811982be5e290bb6a53d86700f1" - bcrypt-pbkdf@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.0.tgz#3ca76b85241c7170bf7d9703e7b9aa74630040d4" dependencies: tweetnacl "^0.14.3" -bel@^4.0.0: - version "4.5.1" - resolved "https://registry.yarnpkg.com/bel/-/bel-4.5.1.tgz#fd857415359780ad195670bdd02766ab2f71f182" - dependencies: - global "^4.3.0" - hyperx "^2.0.2" - on-load "^3.2.0" - -binary-extensions@^1.0.0: - version "1.8.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.8.0.tgz#48ec8d16df4377eae5fa5884682480af4d95c774" - -bl@^0.9.3: - version "0.9.5" - resolved "https://registry.yarnpkg.com/bl/-/bl-0.9.5.tgz#c06b797af085ea00bc527afc8efcf11de2232054" - dependencies: - readable-stream "~1.0.26" - -bl@^1.1.2: - version "1.2.0" - resolved "https://registry.yarnpkg.com/bl/-/bl-1.2.0.tgz#1397e7ec42c5f5dc387470c500e34a9f6be9ea98" - dependencies: - readable-stream "^2.0.5" - bl@~1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/bl/-/bl-1.1.2.tgz#fdca871a99713aa00d19e3bbba41c44787a65398" dependencies: readable-stream "~2.0.5" -block-stream@*: - version "0.0.9" - resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" - dependencies: - inherits "~2.0.0" - -bluebird@^3.3.1, bluebird@^3.4.6: +bluebird@^3.3.1, bluebird@^3.4.0, bluebird@^3.4.6: version "3.4.7" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.4.7.tgz#f72d760be09b7f76d08ed8fae98b289a8d05fab3" -bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: - version "4.11.6" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.6.tgz#53344adb14617a13f6e8dd2ce28905d1c0ba3215" - -body@~0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/body/-/body-0.1.0.tgz#e714fe28cd8848aa34cdf2c9f242bbe2e15d1cd8" - dependencies: - content-types "~0.1.0" - -bole@^3.0.1: - version "3.0.2" - resolved "https://registry.yarnpkg.com/bole/-/bole-3.0.2.tgz#bc8a483ca94049da9b837c1ad11cdfebee6e0514" - dependencies: - fast-safe-stringify "~1.1.0" - individual "~3.0.0" - boom@2.x.x: version "2.10.1" resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" dependencies: hoek "2.x.x" -boom@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/boom/-/boom-4.2.0.tgz#c1a74174b11fbba223f6162d4fd8851a1b82a536" - dependencies: - hoek "4.x.x" - brace-expansion@^1.0.0: version "1.1.6" resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.6.tgz#7197d7eaa9b87e648390ea61fc66c84427420df9" @@ -418,148 +253,6 @@ braces@^1.8.2: preserve "^0.2.0" repeat-element "^1.1.2" -brorand@^1.0.1: - version "1.0.6" - resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.0.6.tgz#4028706b915f91f7b349a2e0bf3c376039d216e5" - -browser-pack@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/browser-pack/-/browser-pack-5.0.1.tgz#4197719b20c6e0aaa09451c5111e53efb6fbc18d" - dependencies: - JSONStream "^1.0.3" - combine-source-map "~0.6.1" - defined "^1.0.0" - through2 "^1.0.0" - umd "^3.0.0" - -browser-pack@^6.0.1: - version "6.0.2" - resolved "https://registry.yarnpkg.com/browser-pack/-/browser-pack-6.0.2.tgz#f86cd6cef4f5300c8e63e07a4d512f65fbff4531" - dependencies: - JSONStream "^1.0.3" - combine-source-map "~0.7.1" - defined "^1.0.0" - through2 "^2.0.0" - umd "^3.0.0" - -browser-resolve@^1.11.0, browser-resolve@^1.7.0: - version "1.11.2" - resolved "https://registry.yarnpkg.com/browser-resolve/-/browser-resolve-1.11.2.tgz#8ff09b0a2c421718a1051c260b32e48f442938ce" - dependencies: - resolve "1.1.7" - -browser-unpack@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/browser-unpack/-/browser-unpack-1.1.1.tgz#42d1423bf719074c1ef88d82e6b94752a41882bd" - dependencies: - acorn "^2.1.0" - browser-pack "^5.0.1" - concat-stream "^1.5.0" - minimist "^1.1.1" - -browserify-aes@^1.0.0, browserify-aes@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.0.6.tgz#5e7725dbdef1fd5930d4ebab48567ce451c48a0a" - dependencies: - buffer-xor "^1.0.2" - cipher-base "^1.0.0" - create-hash "^1.1.0" - evp_bytestokey "^1.0.0" - inherits "^2.0.1" - -browserify-cipher@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.0.tgz#9988244874bf5ed4e28da95666dcd66ac8fc363a" - dependencies: - browserify-aes "^1.0.4" - browserify-des "^1.0.0" - evp_bytestokey "^1.0.0" - -browserify-des@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.0.tgz#daa277717470922ed2fe18594118a175439721dd" - dependencies: - cipher-base "^1.0.1" - des.js "^1.0.0" - inherits "^2.0.1" - -browserify-rsa@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524" - dependencies: - bn.js "^4.1.0" - randombytes "^2.0.1" - -browserify-sign@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.0.0.tgz#10773910c3c206d5420a46aad8694f820b85968f" - dependencies: - bn.js "^4.1.1" - browserify-rsa "^4.0.0" - create-hash "^1.1.0" - create-hmac "^1.1.2" - elliptic "^6.0.0" - inherits "^2.0.1" - parse-asn1 "^5.0.0" - -browserify-zlib@~0.1.2: - version "0.1.4" - resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.1.4.tgz#bb35f8a519f600e0fa6b8485241c979d0141fb2d" - dependencies: - pako "~0.2.0" - -browserify@^13.0.0, browserify@^13.1.0: - version "13.3.0" - resolved "https://registry.yarnpkg.com/browserify/-/browserify-13.3.0.tgz#b5a9c9020243f0c70e4675bec8223bc627e415ce" - dependencies: - JSONStream "^1.0.3" - assert "^1.4.0" - browser-pack "^6.0.1" - browser-resolve "^1.11.0" - browserify-zlib "~0.1.2" - buffer "^4.1.0" - cached-path-relative "^1.0.0" - concat-stream "~1.5.1" - console-browserify "^1.1.0" - constants-browserify "~1.0.0" - crypto-browserify "^3.0.0" - defined "^1.0.0" - deps-sort "^2.0.0" - domain-browser "~1.1.0" - duplexer2 "~0.1.2" - events "~1.1.0" - glob "^7.1.0" - has "^1.0.0" - htmlescape "^1.1.0" - https-browserify "~0.0.0" - inherits "~2.0.1" - insert-module-globals "^7.0.0" - labeled-stream-splicer "^2.0.0" - module-deps "^4.0.8" - os-browserify "~0.1.1" - parents "^1.0.1" - path-browserify "~0.0.0" - process "~0.11.0" - punycode "^1.3.2" - querystring-es3 "~0.2.0" - read-only-stream "^2.0.0" - readable-stream "^2.0.2" - resolve "^1.1.4" - shasum "^1.0.0" - shell-quote "^1.6.1" - stream-browserify "^2.0.0" - stream-http "^2.0.0" - string_decoder "~0.10.0" - subarg "^1.0.0" - syntax-error "^1.1.1" - through2 "^2.0.0" - timers-browserify "^1.0.1" - tty-browserify "~0.0.0" - url "~0.11.0" - util "~0.10.1" - vm-browserify "~0.0.1" - xtend "^4.0.0" - buffer-shims@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/buffer-shims/-/buffer-shims-1.0.0.tgz#9978ce317388c649ad8793028c3477ef044a8b51" @@ -568,40 +261,13 @@ buffer-writer@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/buffer-writer/-/buffer-writer-1.0.1.tgz#22a936901e3029afcd7547eb4487ceb697a3bf08" -buffer-xor@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" - -buffer@^4.1.0: - version "4.9.1" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" - dependencies: - base64-js "^1.0.2" - ieee754 "^1.1.4" - isarray "^1.0.0" - builtin-modules@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" -builtin-status-codes@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" - -bundle-collapser@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/bundle-collapser/-/bundle-collapser-1.2.1.tgz#e119afc92638e440b9085f47ae081fa756cba33d" - dependencies: - browser-pack "^5.0.1" - browser-unpack "^1.1.0" - concat-stream "^1.5.0" - falafel "^1.2.0" - minimist "^1.1.1" - through2 "^2.0.0" - -cached-path-relative@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/cached-path-relative/-/cached-path-relative-1.0.0.tgz#d1094c577fbd9a8b8bd43c96af6188aa205d05f4" +bytes@2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/bytes/-/bytes-2.4.0.tgz#7d97196f9d5baf7f6935e25985549edd2a6c2339" caching-transform@^1.0.0: version "1.0.1" @@ -611,15 +277,6 @@ caching-transform@^1.0.0: mkdirp "^0.5.1" write-file-atomic "^1.1.4" -call-matcher@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/call-matcher/-/call-matcher-1.0.1.tgz#5134d077984f712a54dad3cbf62de28dce416ca8" - dependencies: - core-js "^2.0.0" - deep-equal "^1.0.0" - espurify "^1.6.0" - estraverse "^4.0.0" - caller-path@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" @@ -649,16 +306,6 @@ center-align@^0.1.1: align-text "^0.1.3" lazy-cache "^1.0.3" -chalk@^0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-0.5.1.tgz#663b3a648b68b55d04690d49167aa837858f2174" - dependencies: - ansi-styles "^1.1.0" - escape-string-regexp "^1.0.0" - has-ansi "^0.1.0" - strip-ansi "^0.3.0" - supports-color "^0.2.0" - chalk@^1.0.0, chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" @@ -669,39 +316,6 @@ chalk@^1.0.0, chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3: strip-ansi "^3.0.0" supports-color "^2.0.0" -chokidar@^1.0.0: - version "1.6.1" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.6.1.tgz#2f4447ab5e96e50fb3d789fd90d4c72e0e4c70c2" - dependencies: - anymatch "^1.3.0" - async-each "^1.0.0" - glob-parent "^2.0.0" - inherits "^2.0.1" - is-binary-path "^1.0.0" - is-glob "^2.0.0" - path-is-absolute "^1.0.0" - readdirp "^2.0.0" - optionalDependencies: - fsevents "^1.0.0" - -choo@^4.0.3: - version "4.0.3" - resolved "https://registry.yarnpkg.com/choo/-/choo-4.0.3.tgz#e099cfec9a761560b636a97fc44fdecc7fdb8829" - dependencies: - barracks "^9.0.0" - document-ready "~1.0.2" - global "^4.3.0" - nanoraf "^2.1.1" - sheet-router "^4.0.1" - xtend "^4.0.1" - yo-yo "^1.2.2" - -cipher-base@^1.0.0, cipher-base@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.3.tgz#eeabf194419ce900da3018c207d212f2a6df0a07" - dependencies: - inherits "^2.0.1" - circular-json@^0.3.1: version "0.3.1" resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.1.tgz#be8b36aefccde8b3ca7aa2d6afc07a37242c0d2d" @@ -736,6 +350,15 @@ cliui@^3.2.0: strip-ansi "^3.0.1" wrap-ansi "^2.0.0" +co-body@*: + version "4.2.0" + resolved "https://registry.yarnpkg.com/co-body/-/co-body-4.2.0.tgz#74df20fa73262125dc45482af04e342ea8db3515" + dependencies: + inflation "~2.0.0" + qs "~4.0.0" + raw-body "~2.1.2" + type-is "~1.6.6" + co@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" @@ -748,40 +371,12 @@ color-support@^1.1.0: version "1.1.2" resolved "https://registry.yarnpkg.com/color-support/-/color-support-1.1.2.tgz#49cc99b89d1bdef1292e9d9323c66971a33eb89d" -combine-errors@3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/combine-errors/-/combine-errors-3.0.1.tgz#79a04c22db8a6c5846a951dc41e8838f92e1c1e9" - dependencies: - custom-error-instance "2.1.1" - -combine-source-map@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/combine-source-map/-/combine-source-map-0.6.1.tgz#9b4a09c316033d768e0f11e029fa2730e079ad96" - dependencies: - convert-source-map "~1.1.0" - inline-source-map "~0.5.0" - lodash.memoize "~3.0.3" - source-map "~0.4.2" - -combine-source-map@~0.7.1: - version "0.7.2" - resolved "https://registry.yarnpkg.com/combine-source-map/-/combine-source-map-0.7.2.tgz#0870312856b307a87cc4ac486f3a9a62aeccc09e" - dependencies: - convert-source-map "~1.1.0" - inline-source-map "~0.6.0" - lodash.memoize "~3.0.3" - source-map "~0.5.3" - combined-stream@^1.0.5, combined-stream@~1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009" dependencies: delayed-stream "~1.0.0" -commander@2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.5.0.tgz#d777b6a4d847d423e5d475da864294ac1ff5aa9d" - commander@^2.2.0, commander@^2.9.0: version "2.9.0" resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" @@ -792,15 +387,11 @@ commondir@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" -component-type@1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/component-type/-/component-type-1.2.1.tgz#8a47901700238e4fc32269771230226f24b415a9" - concat-map@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" -concat-stream@^1.4.6, concat-stream@^1.5.0, concat-stream@^1.5.2, concat-stream@^1.6.0: +concat-stream@^1.4.6: version "1.6.0" resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7" dependencies: @@ -808,51 +399,26 @@ concat-stream@^1.4.6, concat-stream@^1.5.0, concat-stream@^1.5.2, concat-stream@ readable-stream "^2.2.2" typedarray "^0.0.6" -concat-stream@~1.4.5: - version "1.4.10" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.4.10.tgz#acc3bbf5602cb8cc980c6ac840fa7d8603e3ef36" - dependencies: - inherits "~2.0.1" - readable-stream "~1.1.9" - typedarray "~0.0.5" - -concat-stream@~1.5.0, concat-stream@~1.5.1: - version "1.5.2" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.5.2.tgz#708978624d856af41a5a741defdd261da752c266" - dependencies: - inherits "~2.0.1" - readable-stream "~2.0.0" - typedarray "~0.0.5" - -console-browserify@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10" - dependencies: - date-now "^0.1.4" - -console-control-strings@^1.0.0, console-control-strings@~1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" - -constants-browserify@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" - -content-types@~0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/content-types/-/content-types-0.1.0.tgz#0e790b3abfef90f6ecb77ae8585db9099caf7578" - dependencies: - iterators "~0.1.0" +content-disposition@~0.5.0: + version "0.5.2" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" -convert-source-map@^1.1.1, convert-source-map@~1.1.0: - version "1.1.3" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.1.3.tgz#4829c877e9fe49b3161f3bf3673888e204699860" +content-type@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.2.tgz#b7d113aee7a8dd27bd21133c4dc2529df1721eed" convert-source-map@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.3.0.tgz#e9f3e9c6e2728efc2676696a70eb382f73106a67" -core-js@^2.0.0, core-js@^2.4.0: +cookies@~0.6.1: + version "0.6.2" + resolved "https://registry.yarnpkg.com/cookies/-/cookies-0.6.2.tgz#6ac1b052895208e8fc4c4f5f86a9ed31b9cb5ccf" + dependencies: + depd "~1.1.0" + keygrip "~1.0.1" + +core-js@^2.4.0: version "2.4.1" resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.4.1.tgz#4de911e667b0eae9124e34254b53aea6fc618d3e" @@ -860,12 +426,6 @@ core-util-is@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" -corsify@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/corsify/-/corsify-2.1.0.tgz#11a45bc47ab30c54d00bb869ea1802fbcd9a09d0" - dependencies: - http-methods "~0.1.0" - coveralls@^2.11.2: version "2.11.15" resolved "https://registry.yarnpkg.com/coveralls/-/coveralls-2.11.15.tgz#37d3474369d66c14f33fa73a9d25cee6e099fca0" @@ -876,36 +436,6 @@ coveralls@^2.11.2: minimist "1.2.0" request "2.75.0" -create-ecdh@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.0.tgz#888c723596cdf7612f6498233eebd7a35301737d" - dependencies: - bn.js "^4.1.0" - elliptic "^6.0.0" - -create-hash@^1.1.0, create-hash@^1.1.1: - version "1.1.2" - resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.1.2.tgz#51210062d7bb7479f6c65bb41a92208b1d61abad" - dependencies: - cipher-base "^1.0.1" - inherits "^2.0.1" - ripemd160 "^1.0.0" - sha.js "^2.3.6" - -create-hmac@^1.1.0, create-hmac@^1.1.2: - version "1.1.4" - resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.4.tgz#d3fb4ba253eb8b3f56e39ea2fbcb8af747bd3170" - dependencies: - create-hash "^1.1.0" - inherits "^2.0.1" - -create-html@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/create-html/-/create-html-1.1.0.tgz#238b59104f99b9a460e7dae73829c96e17c00454" - dependencies: - exit "^0.1.2" - minimist "^1.2.0" - cross-spawn@^4: version "4.0.2" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-4.0.2.tgz#7b9247621c23adfdd3856004a823cbe397424d41" @@ -919,34 +449,6 @@ cryptiles@2.x.x: dependencies: boom "2.x.x" -crypto-browserify@^3.0.0: - version "3.11.0" - resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.11.0.tgz#3652a0906ab9b2a7e0c3ce66a408e957a2485522" - dependencies: - browserify-cipher "^1.0.0" - browserify-sign "^4.0.0" - create-ecdh "^4.0.0" - create-hash "^1.1.0" - create-hmac "^1.1.0" - diffie-hellman "^5.0.0" - inherits "^2.0.1" - pbkdf2 "^3.0.3" - public-encrypt "^4.0.0" - randombytes "^2.0.0" - -css-extract@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/css-extract/-/css-extract-1.2.0.tgz#c4a67509b8a55f10ca0b7a95d0496a09bec8ce2b" - dependencies: - bl "^1.1.2" - from2-string "^1.1.0" - static-module "^1.3.0" - through2 "^2.0.1" - -custom-error-instance@2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/custom-error-instance/-/custom-error-instance-2.1.1.tgz#3cf6391487a6629a6247eb0ca0ce00081b7e361a" - d@^0.1.1, d@~0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/d/-/d-0.1.1.tgz#da184c535d18d8ee7ba2aa229b914009fae11309" @@ -959,38 +461,24 @@ dashdash@^1.12.0: dependencies: assert-plus "^1.0.0" -date-now@^0.1.4: - version "0.1.4" - resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" - debug-log@^1.0.0, debug-log@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/debug-log/-/debug-log-1.0.1.tgz#2307632d4c04382b8df8a32f70b895046d52745f" -debug@^2.1.1, debug@^2.1.3, debug@^2.2.0: +debug@*, debug@^2.1.1, debug@^2.1.3, debug@^2.2.0, debug@^2.6.0: version "2.6.0" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.0.tgz#bc596bcabe7617f11d9fa15361eded5608b8499b" dependencies: ms "0.7.2" -debug@~2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" - dependencies: - ms "0.7.1" - decamelize@^1.0.0, decamelize@^1.1.1: version "1.2.0" resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" -deep-equal@^1.0.0, deep-equal@~1.0.1: +deep-equal@~1.0.0, deep-equal@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5" -deep-extend@~0.4.0: - version "0.4.1" - resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.1.tgz#efe4113d08085f4e6f9687759810f807469e2253" - deep-is@~0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" @@ -1012,7 +500,7 @@ define-properties@^1.1.2: foreach "^2.0.5" object-keys "^1.0.8" -defined@^1.0.0, defined@~1.0.0: +defined@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" @@ -1047,21 +535,13 @@ delegates@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" -deps-sort@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/deps-sort/-/deps-sort-2.0.0.tgz#091724902e84658260eb910748cccd1af6e21fb5" - dependencies: - JSONStream "^1.0.3" - shasum "^1.0.0" - subarg "^1.0.0" - through2 "^2.0.0" +depd@^1.1.0, depd@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.0.tgz#e1bd82c6aab6ced965b97b88b17ed3e528ca18c3" -des.js@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.0.tgz#c074d2e2aa6a8a9a07dbd61f9a15c2cd83ec8ecc" - dependencies: - inherits "^2.0.1" - minimalistic-assert "^1.0.0" +destroy@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" detect-file@^0.1.0: version "0.1.0" @@ -1075,25 +555,10 @@ detect-indent@^4.0.0: dependencies: repeating "^2.0.0" -detective@^4.0.0: - version "4.3.2" - resolved "https://registry.yarnpkg.com/detective/-/detective-4.3.2.tgz#77697e2e7947ac3fe7c8e26a6d6f115235afa91c" - dependencies: - acorn "^3.1.0" - defined "^1.0.0" - diff@^1.3.2: version "1.4.0" resolved "https://registry.yarnpkg.com/diff/-/diff-1.4.0.tgz#7f28d2eb9ee7b15a97efd89ce63dcfdaa3ccbabf" -diffie-hellman@^5.0.0: - version "5.0.2" - resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.2.tgz#b5835739270cfe26acf632099fded2a07f209e5e" - dependencies: - bn.js "^4.1.0" - miller-rabin "^4.0.0" - randombytes "^2.0.0" - doctrine@^1.2.2: version "1.5.0" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" @@ -1101,32 +566,6 @@ doctrine@^1.2.2: esutils "^2.0.2" isarray "^1.0.0" -document-ready@~1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/document-ready/-/document-ready-1.0.3.tgz#eed81e09b37a687c5e6d02b3f0e5706276e82727" - dependencies: - global "~4.3.0" - -dom-walk@^0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/dom-walk/-/dom-walk-0.1.1.tgz#672226dc74c8f799ad35307df936aba11acd6018" - -domain-browser@~1.1.0: - version "1.1.7" - resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.1.7.tgz#867aa4b093faa05f1de08c06f4d7b21fdf8698bc" - -duplexer2@^0.1.2, duplexer2@~0.1.0, duplexer2@~0.1.2: - version "0.1.4" - resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.1.4.tgz#8b12dab878c0d69e3e7891051662a32fc6bddcc1" - dependencies: - readable-stream "^2.0.2" - -duplexer2@~0.0.2: - version "0.0.2" - resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.0.2.tgz#c614dcf67e2fb14995a91711e5a617e8a60a31db" - dependencies: - readable-stream "~1.1.9" - duplexer@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1" @@ -1137,34 +576,9 @@ ecc-jsbn@~0.1.1: dependencies: jsbn "~0.1.0" -elliptic@^6.0.0: - version "6.3.2" - resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.3.2.tgz#e4c81e0829cf0a65ab70e998b8232723b5c1bc48" - dependencies: - bn.js "^4.4.0" - brorand "^1.0.1" - hash.js "^1.0.0" - inherits "^2.0.1" - -end-of-stream@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.1.0.tgz#e9353258baa9108965efc41cb0ef8ade2f3cfb07" - dependencies: - once "~1.3.0" - -envobj@^1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/envobj/-/envobj-1.0.3.tgz#846556a4180c5f06840d8670eb538806c43f62d4" - dependencies: - combine-errors "3.0.1" - component-type "1.2.1" - envvar "1.1.0" - localenv "0.2.2" - object-assign "4.0.1" - -envvar@1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/envvar/-/envvar-1.1.0.tgz#c25a0866edae87046d976c8db037489551639b94" +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" error-ex@^1.2.0: version "1.3.0" @@ -1172,6 +586,10 @@ error-ex@^1.2.0: dependencies: is-arrayish "^0.2.1" +error-inject@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/error-inject/-/error-inject-1.0.0.tgz#e2b3d91b54aed672f309d950d154850fa11d4f37" + es-abstract@^1.5.0: version "1.6.1" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.6.1.tgz#bb8a2064120abcf928a086ea3d9043114285ec99" @@ -1241,40 +659,14 @@ es6-weak-map@^2.0.1: es6-iterator "2" es6-symbol "3" -escape-string-regexp@^1.0.0, escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.3, escape-string-regexp@^1.0.5: +escape-html@~1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + +escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.3, escape-string-regexp@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" -escodegen@^1.6.1, escodegen@^1.8.1: - version "1.8.1" - resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.8.1.tgz#5a5b53af4693110bebb0867aa3430dd3b70a1018" - dependencies: - esprima "^2.7.1" - estraverse "^1.9.1" - esutils "^2.0.2" - optionator "^0.8.1" - optionalDependencies: - source-map "~0.2.0" - -escodegen@~0.0.24: - version "0.0.28" - resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-0.0.28.tgz#0e4ff1715f328775d6cab51ac44a406cd7abffd3" - dependencies: - esprima "~1.0.2" - estraverse "~1.3.0" - optionalDependencies: - source-map ">= 0.1.2" - -escodegen@~1.3.2: - version "1.3.3" - resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.3.3.tgz#f024016f5a88e046fd12005055e939802e6c5f23" - dependencies: - esprima "~1.1.1" - estraverse "~1.5.0" - esutils "~1.0.0" - optionalDependencies: - source-map "~0.1.33" - escope@^3.6.0: version "3.6.0" resolved "https://registry.yarnpkg.com/escope/-/escope-3.6.0.tgz#e01975e812781a163a6dadfdd80398dc64c889c3" @@ -1353,24 +745,10 @@ espree@^3.3.1: acorn "^4.0.1" acorn-jsx "^3.0.0" -esprima@^2.6.0, esprima@^2.7.1: +esprima@^2.6.0: version "2.7.3" resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" -esprima@~1.0.2: - version "1.0.4" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-1.0.4.tgz#9f557e08fc3b4d26ece9dd34f8fbf476b62585ad" - -esprima@~1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-1.1.1.tgz#5b6f1547f4d102e670e140c509be6771d6aeb549" - -espurify@^1.3.0, espurify@^1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/espurify/-/espurify-1.6.0.tgz#6cb993582d9422bd6f2d4b258aadb14833f394f0" - dependencies: - core-js "^2.0.0" - esrecurse@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.1.0.tgz#4713b6536adf7f2ac4f327d559e7756bff648220" @@ -1378,22 +756,10 @@ esrecurse@^4.1.0: estraverse "~4.1.0" object-assign "^4.0.1" -estraverse@^1.9.1: - version "1.9.3" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-1.9.3.tgz#af67f2dc922582415950926091a4005d29c9bb44" - -estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0: +estraverse@^4.1.1, estraverse@^4.2.0: version "4.2.0" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" -estraverse@~1.3.0: - version "1.3.2" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-1.3.2.tgz#37c2b893ef13d723f276d878d60d8535152a6c42" - -estraverse@~1.5.0: - version "1.5.1" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-1.5.1.tgz#867a3e8e58a9f84618afb6c2ddbcd916b7cbaf71" - estraverse@~4.1.0: version "4.1.1" resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.1.1.tgz#f6caca728933a850ef90661d0e17982ba47111a2" @@ -1402,10 +768,6 @@ esutils@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" -esutils@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-1.0.0.tgz#8151d358e20c8acc7fb745e7472c0025fe496570" - event-emitter@~0.3.4: version "0.3.4" resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.4.tgz#8d63ddfb4cfe1fae3b32ca265c4c720222080bb5" @@ -1417,24 +779,10 @@ events-to-array@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/events-to-array/-/events-to-array-1.0.2.tgz#b3484465534fe4ff66fbdd1a83b777713ba404aa" -events@^1.0.2, events@~1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" - -evp_bytestokey@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.0.tgz#497b66ad9fef65cd7c08a6180824ba1476b66e53" - dependencies: - create-hash "^1.1.1" - exit-hook@^1.0.0: version "1.1.1" resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" -exit@^0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" - expand-brackets@^0.1.4: version "0.1.5" resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" @@ -1453,14 +801,6 @@ expand-tilde@^1.2.2: dependencies: os-homedir "^1.0.1" -explain-error@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/explain-error/-/explain-error-1.0.3.tgz#f4e2b21152120d94db36d93bef03a5c42bfedce9" - -extend@^1.2.1: - version "1.3.0" - resolved "https://registry.yarnpkg.com/extend/-/extend-1.3.0.tgz#d1516fb0ff5624d2ebf9123ea1dac5a1994004f8" - extend@^3.0.0, extend@~3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.0.tgz#5a474353b9f3353ddd8176dfd37b91c83a46f1d4" @@ -1475,16 +815,7 @@ extsprintf@1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.0.2.tgz#e1080e0658e300b06294990cc70e1502235fd550" -falafel@^1.0.0, falafel@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/falafel/-/falafel-1.2.0.tgz#c18d24ef5091174a497f318cd24b026a25cddab4" - dependencies: - acorn "^1.0.3" - foreach "^2.0.5" - isarray "0.0.1" - object-keys "^1.0.6" - -fast-json-parse@^1.0.0, fast-json-parse@^1.0.2: +fast-json-parse@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/fast-json-parse/-/fast-json-parse-1.0.2.tgz#3fb1ca12db68a85933612cc3fab4d7060cfff1d7" @@ -1492,7 +823,7 @@ fast-levenshtein@~2.0.4: version "2.0.6" resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" -fast-safe-stringify@^1.0.8, fast-safe-stringify@^1.1.3, fast-safe-stringify@~1.1.0: +fast-safe-stringify@^1.0.8, fast-safe-stringify@^1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-1.1.3.tgz#f23370808fe5ab243fa1fdee2e9ab3041c8cb884" @@ -1569,10 +900,6 @@ flatstr@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/flatstr/-/flatstr-1.0.4.tgz#b4477b7cb3377f2b63b0ede78824eb5f99ffcd74" -flatten@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782" - for-each@~0.3.2: version "0.3.2" resolved "https://registry.yarnpkg.com/for-each/-/for-each-0.3.2.tgz#2c40450b9348e97f281322593ba96704b9abd4d4" @@ -1612,26 +939,13 @@ form-data@~2.0.0: combined-stream "^1.0.5" mime-types "^2.1.11" -form-data@~2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.2.tgz#89c3534008b97eada4cbb157d58f6f5df025eae4" - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.5" - mime-types "^2.1.12" - -from2-string@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/from2-string/-/from2-string-1.1.0.tgz#18282b27d08a267cb3030cd2b8b4b0f212af752a" - dependencies: - from2 "^2.0.3" +formidable@1.0.17: + version "1.0.17" + resolved "https://registry.yarnpkg.com/formidable/-/formidable-1.0.17.tgz#ef5491490f9433b705faa77249c99029ae348559" -from2@^2.0.3, from2@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" - dependencies: - inherits "^2.0.1" - readable-stream "^2.0.0" +fresh@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.3.0.tgz#651f838e22424e7566de161d8358caa199f83d4f" fs-exists-sync@^0.1.0: version "0.1.0" @@ -1641,63 +955,10 @@ fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" -fsevents@^1.0.0: - version "1.0.17" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.0.17.tgz#8537f3f12272678765b4fd6528c0f1f66f8f4558" - dependencies: - nan "^2.3.0" - node-pre-gyp "^0.6.29" - -fstream-ignore@~1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105" - dependencies: - fstream "^1.0.0" - inherits "2" - minimatch "^3.0.0" - -fstream@^1.0.0, fstream@^1.0.2, fstream@~1.0.10: - version "1.0.10" - resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.10.tgz#604e8a92fe26ffd9f6fae30399d4984e1ab22822" - dependencies: - graceful-fs "^4.1.2" - inherits "~2.0.0" - mkdirp ">=0.5 0" - rimraf "2" - function-bind@^1.0.2, function-bind@^1.1.0, function-bind@~1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.0.tgz#16176714c801798e4e8f2cf7f7529467bb4a5771" -garnish@^5.2.0: - version "5.2.0" - resolved "https://registry.yarnpkg.com/garnish/-/garnish-5.2.0.tgz#bed43659382e4b198e33c793897be7c701e65577" - dependencies: - chalk "^0.5.1" - minimist "^1.1.0" - pad-left "^2.0.0" - pad-right "^0.2.2" - prettier-bytes "^1.0.3" - pretty-ms "^2.1.0" - right-now "^1.0.0" - split2 "^0.2.1" - stdout-stream "^1.4.0" - url-trim "^1.0.0" - -gauge@~2.7.1: - version "2.7.2" - resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.2.tgz#15cecc31b02d05345a5d6b0e171cdb3ad2307774" - dependencies: - aproba "^1.0.3" - console-control-strings "^1.0.0" - has-unicode "^2.0.0" - object-assign "^4.1.0" - signal-exit "^3.0.0" - string-width "^1.0.1" - strip-ansi "^3.0.1" - supports-color "^0.2.0" - wide-align "^1.1.0" - generate-function@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.0.0.tgz#6858fe7c0969b7d4e9093337647ac79f60dfbe74" @@ -1743,7 +1004,7 @@ glob-parent@^2.0.0: dependencies: is-glob "^2.0.0" -glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.0.6, glob@^7.1.0, glob@~7.1.1: +glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@^7.0.6, glob@~7.1.1: version "7.1.1" resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.1.tgz#805211df04faaf1c63a3600306cdf5ade50b2ec8" dependencies: @@ -1770,13 +1031,6 @@ global-prefix@^0.1.4: is-windows "^0.2.0" which "^1.2.12" -global@^4.3.0, global@~4.3.0: - version "4.3.1" - resolved "https://registry.yarnpkg.com/global/-/global-4.3.1.tgz#5f757908c7cbabce54f386ae440e11e26b7916df" - dependencies: - min-document "^2.19.0" - process "~0.5.1" - globals@^9.0.0, globals@^9.2.0: version "9.14.0" resolved "https://registry.yarnpkg.com/globals/-/globals-9.14.0.tgz#8859936af0038741263053b39d0e76ca241e4034" @@ -1800,7 +1054,7 @@ graceful-fs@^4.1.11, graceful-fs@^4.1.2: version "1.0.1" resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" -handlebars@^4.0.3: +handlebars@^4.0.3, handlebars@^4.0.5: version "4.0.6" resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.0.6.tgz#2ce4484850537f9c97a8026d5399b935c4ed4ed7" dependencies: @@ -1819,12 +1073,6 @@ har-validator@~2.0.6: is-my-json-valid "^2.12.4" pinkie-promise "^2.0.0" -has-ansi@^0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-0.1.0.tgz#84f265aae8c0e6a88a12d7022894b7568894c62e" - dependencies: - ansi-regex "^0.2.0" - has-ansi@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" @@ -1835,22 +1083,12 @@ has-flag@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" -has-unicode@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" - -has@^1.0.0, has@~1.0.1: +has@~1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/has/-/has-1.0.1.tgz#8461733f538b0837c9361e39a9ab9e9704dc2f28" dependencies: function-bind "^1.0.2" -hash.js@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.0.3.tgz#1332ff00156c0a0ffdd8236013d07b77a0451573" - dependencies: - inherits "^2.0.1" - hawk@~3.1.3: version "3.1.3" resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" @@ -1864,10 +1102,6 @@ hoek@2.x.x: version "2.16.3" resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" -hoek@4.x.x: - version "4.1.0" - resolved "https://registry.yarnpkg.com/hoek/-/hoek-4.1.0.tgz#4a4557460f69842ed463aa00628cc26d2683afa7" - home-or-tmp@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" @@ -1885,23 +1119,27 @@ hosted-git-info@^2.1.4: version "2.1.5" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.1.5.tgz#0ba81d90da2e25ab34a332e6ec77936e1598118b" -htmlescape@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/htmlescape/-/htmlescape-1.1.1.tgz#3a03edc2214bca3b66424a3e7959349509cb0351" +http-assert@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/http-assert/-/http-assert-1.2.0.tgz#d6392e6f6519def4e340266b35096db6d3feba00" + dependencies: + deep-equal "~1.0.0" + http-errors "~1.4.0" -http-methods@~0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/http-methods/-/http-methods-0.1.0.tgz#29691b6fc58f4f7e81a3605dca82682b068e4430" +http-errors@^1.2.8, http-errors@^1.3.1, http-errors@~1.5.0: + version "1.5.1" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.5.1.tgz#788c0d2c1de2c81b9e6e8c01843b6b97eb920750" dependencies: - body "~0.1.0" - content-types "~0.1.0" + inherits "2.0.3" + setprototypeof "1.0.2" + statuses ">= 1.3.1 < 2" -http-ndjson@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/http-ndjson/-/http-ndjson-3.0.0.tgz#d21654c0b770417275528b900af589283f2d07fb" +http-errors@~1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.4.0.tgz#6c0242dea6b3df7afda153c71089b31c6e82aabf" dependencies: - end-of-stream "^1.1.0" - xtend "^4.0.0" + inherits "2.0.1" + statuses ">= 1.2.1 < 2" http-signature@~1.1.0: version "1.1.1" @@ -1911,31 +1149,13 @@ http-signature@~1.1.0: jsprim "^1.2.2" sshpk "^1.7.0" -https-browserify@~0.0.0: - version "0.0.1" - resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-0.0.1.tgz#3f91365cabe60b77ed0ebba24b454e3e09d95a82" - -humps@^2.0.0: +humps@2: version "2.0.0" resolved "https://registry.yarnpkg.com/humps/-/humps-2.0.0.tgz#dd4a423e9784626fe7b9f19fde0baff659b40173" -hyperscript-attribute-to-property@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/hyperscript-attribute-to-property/-/hyperscript-attribute-to-property-1.0.0.tgz#825308d49bb8e2957923f731981bcc811cad7aff" - -hyperx@^2.0.2, hyperx@^2.0.3: - version "2.0.5" - resolved "https://registry.yarnpkg.com/hyperx/-/hyperx-2.0.5.tgz#fedef890d7203f36339b243b27d38e3a424225ab" - dependencies: - hyperscript-attribute-to-property "^1.0.0" - -iconv-lite@~0.4.11: - version "0.4.15" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.15.tgz#fe265a218ac6a57cfe854927e9d04c19825eddeb" - -ieee754@^1.1.4: - version "1.1.8" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4" +iconv-lite@0.4.13: + version "0.4.13" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.13.tgz#1f88aba4ab0b1508e8312acc39345f36e992e2f2" ignore@^3.0.9, ignore@^3.2.0: version "3.2.0" @@ -1945,17 +1165,9 @@ imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" -indexes-of@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607" - -indexof@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" - -individual@~3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/individual/-/individual-3.0.0.tgz#e7ca4f85f8957b018734f285750dc22ec2f9862d" +inflation@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/inflation/-/inflation-2.0.0.tgz#8b417e47c28f925a45133d914ca1fd389107f30f" inflight@^1.0.4: version "1.0.6" @@ -1964,7 +1176,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3: +inherits@2, inherits@2.0.3, inherits@^2.0.3, inherits@~2.0.1, inherits@~2.0.3: version "2.0.3" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" @@ -1972,22 +1184,10 @@ inherits@2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" -ini@^1.3.4, ini@~1.3.0: +ini@^1.3.4: version "1.3.4" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e" -inline-source-map@~0.5.0: - version "0.5.0" - resolved "https://registry.yarnpkg.com/inline-source-map/-/inline-source-map-0.5.0.tgz#4a4c5dd8e4fb5e9b3cda60c822dfadcaee66e0af" - dependencies: - source-map "~0.4.0" - -inline-source-map@~0.6.0: - version "0.6.2" - resolved "https://registry.yarnpkg.com/inline-source-map/-/inline-source-map-0.6.2.tgz#f9393471c18a79d1724f863fa38b586370ade2a5" - dependencies: - source-map "~0.5.3" - inquirer@^0.12.0: version "0.12.0" resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-0.12.0.tgz#1ef2bfd63504df0bc75785fff8c2c41df12f077e" @@ -2006,23 +1206,6 @@ inquirer@^0.12.0: strip-ansi "^3.0.0" through "^2.3.6" -insert-css@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/insert-css/-/insert-css-2.0.0.tgz#eb5d1097b7542f4c79ea3060d3aee07d053880f4" - -insert-module-globals@^7.0.0: - version "7.0.1" - resolved "https://registry.yarnpkg.com/insert-module-globals/-/insert-module-globals-7.0.1.tgz#c03bf4e01cb086d5b5e5ace8ad0afe7889d638c3" - dependencies: - JSONStream "^1.0.3" - combine-source-map "~0.7.1" - concat-stream "~1.5.1" - is-buffer "^1.1.0" - lexical-scope "^1.2.0" - process "~0.11.0" - through2 "^2.0.0" - xtend "^4.0.0" - interpret@^0.6.5: version "0.6.6" resolved "https://registry.yarnpkg.com/interpret/-/interpret-0.6.6.tgz#fecd7a18e7ce5ca6abfb953e1f86213a49f1625b" @@ -2045,13 +1228,7 @@ is-arrayish@^0.2.1: version "0.2.1" resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" -is-binary-path@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" - dependencies: - binary-extensions "^1.0.0" - -is-buffer@^1.0.2, is-buffer@^1.1.0: +is-buffer@^1.0.2: version "1.1.4" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.4.tgz#cfc86ccd5dc5a52fa80489111c6920c457e2d98b" @@ -2107,13 +1284,17 @@ is-function@~1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/is-function/-/is-function-1.0.1.tgz#12cfb98b65b57dd3d193a3121f5f6e2f437602b5" +is-generator-function@^1.0.3: + version "1.0.6" + resolved "https://registry.yarnpkg.com/is-generator-function/-/is-generator-function-1.0.6.tgz#9e71653cd15fff341c79c4151460a131d31e9fc4" + is-glob@^2.0.0, is-glob@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" dependencies: is-extglob "^1.0.0" -is-my-json-valid@^2.10.0, is-my-json-valid@^2.12.4, is-my-json-valid@^2.15.0: +is-my-json-valid@^2.10.0, is-my-json-valid@^2.12.4: version "2.15.0" resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.15.0.tgz#936edda3ca3c211fd98f3b2d3e08da43f7b2915b" dependencies: @@ -2166,10 +1347,6 @@ is-resolvable@^1.0.0: dependencies: tryit "^1.0.1" -is-stream@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" - is-symbol@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.1.tgz#3cc59f00025194b6ab2e38dbae6689256b660572" @@ -2186,7 +1363,7 @@ is-windows@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-0.2.0.tgz#de1aa6d63ea29dd248737b69f1ff8b8002d2108c" -isarray@0.0.1, isarray@~0.0.1: +isarray@0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" @@ -2256,22 +1433,12 @@ istanbul-reports@^1.0.0: dependencies: handlebars "^4.0.3" -iterators@~0.1.0: - version "0.1.0" - resolved "https://registry.yarnpkg.com/iterators/-/iterators-0.1.0.tgz#d03f666ca4e6130138565997cacea54164203156" - dependencies: - ap "~0.1.0" - jodid25519@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/jodid25519/-/jodid25519-1.0.2.tgz#06d4912255093419477d425633606e0e90782967" dependencies: jsbn "~0.1.0" -js-base64@^2.1.9: - version "2.1.9" - resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.1.9.tgz#f0e80ae039a4bd654b5f281fc93f04a914a7fcce" - js-tokens@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-2.0.0.tgz#79903f5563ee778cc1162e6dcf1a0027c97f9cb5" @@ -2312,12 +1479,6 @@ json-stable-stringify@^1.0.0, json-stable-stringify@^1.0.1: dependencies: jsonify "~0.0.0" -json-stable-stringify@~0.0.0: - version "0.0.1" - resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-0.0.1.tgz#611c23e814db375527df851193db59dd2af27f45" - dependencies: - jsonify "~0.0.0" - json-stringify-safe@~5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" @@ -2326,10 +1487,6 @@ jsonify@~0.0.0: version "0.0.0" resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" -jsonparse@^1.2.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.0.tgz#85fc245b1d9259acc6941960b905adf64e7de0e8" - jsonpointer@^4.0.0: version "4.0.1" resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9" @@ -2349,13 +1506,17 @@ jsx-ast-utils@^1.3.3: acorn-jsx "^3.0.1" object-assign "^4.1.0" +keygrip@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/keygrip/-/keygrip-1.0.1.tgz#b02fa4816eef21a8c4b35ca9e52921ffc89a30e9" + kind-of@^3.0.2: version "3.1.0" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.1.0.tgz#475d698a5e49ff5e53d14e3e732429dc8bf4cf47" dependencies: is-buffer "^1.0.2" -knex@^0.12.6: +knex@0.12: version "0.12.6" resolved "https://registry.yarnpkg.com/knex/-/knex-0.12.6.tgz#a255f0ea03af2c2c94687a622c08acc1a9463c0e" dependencies: @@ -2377,13 +1538,101 @@ knex@^0.12.6: tildify "~1.0.0" v8flags "^2.0.2" -labeled-stream-splicer@^2.0.0: +koa-body@2: version "2.0.0" - resolved "https://registry.yarnpkg.com/labeled-stream-splicer/-/labeled-stream-splicer-2.0.0.tgz#a52e1d138024c00b86b1c0c91f677918b8ae0a59" + resolved "https://registry.yarnpkg.com/koa-body/-/koa-body-2.0.0.tgz#c88793717825b416351dec9463824bd7184e9a2d" + dependencies: + co-body "*" + formidable "1.0.17" + koa "^2.0.0" + +koa-compose@^3.0.0: + version "3.2.1" + resolved "https://registry.yarnpkg.com/koa-compose/-/koa-compose-3.2.1.tgz#a85ccb40b7d986d8e5a345b3a1ace8eabcf54de7" + dependencies: + any-promise "^1.1.0" + +koa-convert@1.2, koa-convert@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/koa-convert/-/koa-convert-1.2.0.tgz#da40875df49de0539098d1700b50820cebcd21d0" dependencies: - inherits "^2.0.1" - isarray "~0.0.1" - stream-splicer "^2.0.0" + co "^4.6.0" + koa-compose "^3.0.0" + +koa-hbs@0.9: + version "0.9.0" + resolved "https://registry.yarnpkg.com/koa-hbs/-/koa-hbs-0.9.0.tgz#c8a2af2933a49acaa47a197e2c279f8b2ecdb76e" + dependencies: + glob "^7.0.5" + handlebars "^4.0.5" + +koa-is-json@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/koa-is-json/-/koa-is-json-1.0.0.tgz#273c07edcdcb8df6a2c1ab7d59ee76491451ec14" + +koa-router@7: + version "7.1.0" + resolved "https://registry.yarnpkg.com/koa-router/-/koa-router-7.1.0.tgz#2fe6d7e6da7e3c46d8781953835c70513a6871f5" + dependencies: + debug "^2.2.0" + http-errors "^1.3.1" + koa-compose "^3.0.0" + methods "^1.0.1" + path-to-regexp "^1.1.1" + +koa-send@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/koa-send/-/koa-send-3.3.0.tgz#5a4ae245564680c6ecf6079e9275fa5173a861dc" + dependencies: + co "^4.6.0" + debug "^2.6.0" + mz "^2.3.1" + resolve-path "^1.3.1" + +"koa-static@https://github.com/kiasaki/koa-static.git": + version "1.0.0" + resolved "https://github.com/kiasaki/koa-static.git#20f8cf9bdd09cc1d2e6a99cfafedfa747aaf7509" + dependencies: + koa-send "^3.3.0" + +"koa2-handlebars@https://github.com/kiasaki/koa-handlebars.git": + version "1.0.8" + resolved "https://github.com/kiasaki/koa-handlebars.git#b68827ea16296484a578965d783968204ed86a25" + dependencies: + bluebird "^3.4.0" + debug "^2.2.0" + handlebars "^4.0.5" + lru-cache "^4.0.1" + recursive-readdir "^2.0.0" + +koa@2, koa@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/koa/-/koa-2.0.0.tgz#da865ae8ee4afae070425290455d2cdf4885f9dc" + dependencies: + accepts "^1.2.2" + content-disposition "~0.5.0" + content-type "^1.0.0" + cookies "~0.6.1" + debug "*" + delegates "^1.0.0" + depd "^1.1.0" + destroy "^1.0.3" + error-inject "~1.0.0" + escape-html "~1.0.1" + fresh "^0.3.0" + http-assert "^1.1.0" + http-errors "^1.2.8" + is-generator-function "^1.0.3" + koa-compose "^3.0.0" + koa-convert "^1.2.0" + koa-is-json "^1.0.0" + mime-types "^2.0.7" + on-finished "^2.1.0" + only "0.0.2" + parseurl "^1.3.0" + statuses "^1.2.0" + type-is "^1.5.5" + vary "^1.0.0" lazy-cache@^1.0.3: version "1.0.4" @@ -2406,12 +1655,6 @@ levn@^0.3.0, levn@~0.3.0: prelude-ls "~1.1.2" type-check "~0.3.2" -lexical-scope@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/lexical-scope/-/lexical-scope-1.2.0.tgz#fcea5edc704a4b3a8796cdca419c3a0afaf22df4" - dependencies: - astw "^2.0.0" - liftoff@~2.2.0: version "2.2.5" resolved "https://registry.yarnpkg.com/liftoff/-/liftoff-2.2.5.tgz#998c2876cff484b103e4423b93d356da44734c91" @@ -2432,16 +1675,6 @@ load-json-file@^1.0.0: pinkie-promise "^2.0.0" strip-bom "^2.0.0" -localenv@0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/localenv/-/localenv-0.2.2.tgz#c508f29d3485bdc9341d3ead17f61c5abd1b0bab" - dependencies: - commander "2.5.0" - -lodash.memoize@~3.0.3: - version "3.0.4" - resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-3.0.4.tgz#2dcbd2c287cbc0a55cc42328bd0c736150d53e3f" - lodash@^3.6.0: version "3.10.1" resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6" @@ -2471,12 +1704,6 @@ lru-cache@^4.0.1: pseudomap "^1.0.1" yallist "^2.0.0" -map-limit@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/map-limit/-/map-limit-0.0.1.tgz#eb7961031c0f0e8d001bf2d56fab685d58822f38" - dependencies: - once "~1.3.0" - md5-hex@^1.2.0: version "1.3.0" resolved "https://registry.yarnpkg.com/md5-hex/-/md5-hex-1.3.0.tgz#d2c4afe983c4370662179b8cad145219135046c4" @@ -2487,38 +1714,21 @@ md5-o-matic@^0.1.1: version "0.1.1" resolved "https://registry.yarnpkg.com/md5-o-matic/-/md5-o-matic-0.1.1.tgz#822bccd65e117c514fab176b25945d54100a03c3" +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + merge-source-map@^1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/merge-source-map/-/merge-source-map-1.0.3.tgz#da1415f2722a5119db07b14c4f973410863a2abf" dependencies: source-map "^0.5.3" -merry@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/merry/-/merry-4.1.0.tgz#a6a6c138770c79c68f8cb75a0cd1ceb97b18bb3c" - dependencies: - boom "^4.2.0" - concat-stream "^1.6.0" - corsify "^2.1.0" - envobj "^1.0.2" - explain-error "^1.0.3" - fast-json-parse "^1.0.2" - fast-safe-stringify "^1.1.3" - from2-string "^1.1.0" - is-my-json-valid "^2.15.0" - is-stream "^1.1.0" - map-limit "0.0.1" - pino "^3.0.5" - pump "^1.0.1" - server-router "^4.0.0" - server-sink "^1.0.0" - xtend "^4.0.1" - -methods@^1.1.1: +methods@^1.0.1: version "1.1.2" resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" -micromatch@^2.1.5, micromatch@^2.3.11, micromatch@^2.3.7: +micromatch@^2.3.11, micromatch@^2.3.7: version "2.3.11" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" dependencies: @@ -2536,34 +1746,23 @@ micromatch@^2.1.5, micromatch@^2.3.11, micromatch@^2.3.7: parse-glob "^3.0.4" regex-cache "^0.4.2" -miller-rabin@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.0.tgz#4a62fb1d42933c05583982f4c716f6fb9e6c6d3d" - dependencies: - bn.js "^4.0.0" - brorand "^1.0.1" - mime-db@~1.26.0: version "1.26.0" resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.26.0.tgz#eaffcd0e4fc6935cf8134da246e2e6c35305adff" -mime-types@^2.1.11, mime-types@^2.1.12, mime-types@~2.1.7: +mime-types@^2.0.7, mime-types@^2.1.11, mime-types@~2.1.11, mime-types@~2.1.13, mime-types@~2.1.7: version "2.1.14" resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.14.tgz#f7ef7d97583fcaf3b7d282b6f8b5679dab1e94ee" dependencies: mime-db "~1.26.0" -min-document@^2.19.0: - version "2.19.0" - resolved "https://registry.yarnpkg.com/min-document/-/min-document-2.19.0.tgz#7bd282e3f5842ed295bb748cdd9f1ffa2c824685" +minimatch@3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.2.tgz#0f398a7300ea441e9c348c83d98ab8c9dbf9c40a" dependencies: - dom-walk "^0.1.0" - -minimalistic-assert@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz#702be2dda6b37f4836bcb3f5db56641b64a1d3d3" + brace-expansion "^1.0.0" -minimatch@^3.0.0, minimatch@^3.0.2: +minimatch@^3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.3.tgz#2a4e4090b96b2db06a9d7df01055a62a77c9b774" dependencies: @@ -2573,7 +1772,7 @@ minimist@0.0.8, minimist@~0.0.1: version "0.0.8" resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" -minimist@1.2.0, minimist@^1.1.0, minimist@^1.1.1, minimist@^1.2.0, minimist@~1.2.0: +minimist@1.2.0, minimist@^1.1.0, minimist@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" @@ -2581,96 +1780,40 @@ minimist@~1.1.0: version "1.1.3" resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.1.3.tgz#3bedfd91a92d39016fcfaa1c681e8faa1a1efda8" -"mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.1: +mkdirp@^0.5.0, mkdirp@^0.5.1: version "0.5.1" resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" dependencies: minimist "0.0.8" -module-deps@^4.0.8: - version "4.0.8" - resolved "https://registry.yarnpkg.com/module-deps/-/module-deps-4.0.8.tgz#55fd70623399706c3288bef7a609ff1e8c0ed2bb" - dependencies: - JSONStream "^1.0.3" - browser-resolve "^1.7.0" - cached-path-relative "^1.0.0" - concat-stream "~1.5.0" - defined "^1.0.0" - detective "^4.0.0" - duplexer2 "^0.1.2" - inherits "^2.0.1" - parents "^1.0.0" - readable-stream "^2.0.2" - resolve "^1.1.3" - stream-combiner2 "^1.1.1" - subarg "^1.0.0" - through2 "^2.0.0" - xtend "^4.0.0" - -morphdom@~2.1.0: - version "2.1.2" - resolved "https://registry.yarnpkg.com/morphdom/-/morphdom-2.1.2.tgz#e07d0a61cda5cbed43389372d78c5c84d0154b0a" - -ms@0.7.1: - version "0.7.1" - resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098" - ms@0.7.2: version "0.7.2" resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765" -multi-stage-sourcemap@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/multi-stage-sourcemap/-/multi-stage-sourcemap-0.2.1.tgz#b09fc8586eaa17f81d575c4ad02e0f7a3f6b1105" - dependencies: - source-map "^0.1.34" - mute-stream@0.0.5: version "0.0.5" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0" -nan@^2.3.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.5.0.tgz#aa8f1e34531d807e9e27755b234b4a6ec0c152a8" - -nanoraf@^2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/nanoraf/-/nanoraf-2.1.2.tgz#3c9a041582c4c6cd9fb3ececbe5c5b0a81b75565" +mz@^2.3.1: + version "2.6.0" + resolved "https://registry.yarnpkg.com/mz/-/mz-2.6.0.tgz#c8b8521d958df0a4f2768025db69c719ee4ef1ce" dependencies: - global "^4.3.0" - -nanotick@^1.1.2: - version "1.1.4" - resolved "https://registry.yarnpkg.com/nanotick/-/nanotick-1.1.4.tgz#0e8a72309488448409462ab1256ab1fe2783ea17" + any-promise "^1.0.0" + object-assign "^4.0.1" + thenify-all "^1.0.0" natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" -node-pre-gyp@^0.6.29: - version "0.6.32" - resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.32.tgz#fc452b376e7319b3d255f5f34853ef6fd8fe1fd5" - dependencies: - mkdirp "~0.5.1" - nopt "~3.0.6" - npmlog "^4.0.1" - rc "~1.1.6" - request "^2.79.0" - rimraf "~2.5.4" - semver "~5.3.0" - tar "~2.2.1" - tar-pack "~3.3.0" +negotiator@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" node-uuid@^1.4.7, node-uuid@~1.4.7: version "1.4.7" resolved "https://registry.yarnpkg.com/node-uuid/-/node-uuid-1.4.7.tgz#6da5a17668c4b3dd59623bda11cf7fa4c1f60a6f" -nopt@~3.0.6: - version "3.0.6" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" - dependencies: - abbrev "1" - normalize-package-data@^2.3.2: version "2.3.5" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.3.5.tgz#8d924f142960e1777e7ffe170543631cc7cb02df" @@ -2684,15 +1827,6 @@ normalize-path@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.0.1.tgz#47886ac1662760d4261b7d979d241709d3ce3f7a" -npmlog@^4.0.1: - version "4.0.2" - resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.0.2.tgz#d03950e0e78ce1527ba26d2a7592e9348ac3e75f" - dependencies: - are-we-there-yet "~1.1.2" - console-control-strings "~1.1.0" - gauge "~2.7.1" - set-blocking "~2.0.0" - number-is-nan@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" @@ -2733,30 +1867,18 @@ oauth-sign@~0.8.1: version "0.8.2" resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" -object-assign@4.0.1, object-assign@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.0.1.tgz#99504456c3598b5cad4fc59c26e8a9bb107fe0bd" - -object-assign@4.1.0, object-assign@^4.1.0: +object-assign@4.1.0, object-assign@^4.0.1, object-assign@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.0.tgz#7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0" -object-inspect@~0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-0.4.0.tgz#f5157c116c1455b243b06ee97703392c5ad89fec" - object-inspect@~1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.2.1.tgz#3b62226eb8f6d441751c7d8f22a20ff80ac9dc3f" -object-keys@^1.0.6, object-keys@^1.0.8: +object-keys@^1.0.8: version "1.0.11" resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.11.tgz#c54601778ad560f1142ce0e01bcca8b56d13426d" -object-keys@~0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-0.4.0.tgz#28a6aae7428dd2c3a92f3d95f21335dd204e0336" - object.omit@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" @@ -2764,15 +1886,15 @@ object.omit@^2.0.0: for-own "^0.1.4" is-extendable "^0.1.1" -on-load@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/on-load/-/on-load-3.2.0.tgz#dd3145d3a5c2faa5666920d1df674b69f0c2f66f" +on-finished@^2.1.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" dependencies: - global "^4.3.0" + ee-first "1.1.1" -once@^1.3.0, once@^1.3.1, once@^1.3.3, once@~1.3.0, once@~1.3.3: - version "1.3.3" - resolved "https://registry.yarnpkg.com/once/-/once-1.3.3.tgz#b2e261557ce4c314ec8304f3fa82663e4297ca20" +once@^1.3.0, once@^1.3.3: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" dependencies: wrappy "1" @@ -2784,17 +1906,14 @@ only-shallow@^1.0.2: version "1.2.0" resolved "https://registry.yarnpkg.com/only-shallow/-/only-shallow-1.2.0.tgz#71cecedba9324bc0518aef10ec080d3249dc2465" +only@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/only/-/only-0.0.2.tgz#2afde84d03e50b9a8edc444e30610a70295edfb4" + opener@^1.4.1: version "1.4.2" resolved "https://registry.yarnpkg.com/opener/-/opener-1.4.2.tgz#b32582080042af8680c389a499175b4c54fff523" -opn@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/opn/-/opn-4.0.2.tgz#7abc22e644dff63b0a96d5ab7f2790c0f01abc95" - dependencies: - object-assign "^4.0.1" - pinkie-promise "^2.0.0" - optimist@^0.6.1: version "0.6.1" resolved "https://registry.yarnpkg.com/optimist/-/optimist-0.6.1.tgz#da3ea74686fa21a19a111c326e90eb15a0196686" @@ -2802,7 +1921,7 @@ optimist@^0.6.1: minimist "~0.0.1" wordwrap "~0.0.2" -optionator@^0.8.1, optionator@^0.8.2: +optionator@^0.8.2: version "0.8.2" resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" dependencies: @@ -2813,10 +1932,6 @@ optionator@^0.8.1, optionator@^0.8.2: type-check "~0.3.2" wordwrap "~1.0.0" -os-browserify@~0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.1.2.tgz#49ca0293e0b19590a5f5de10c7f265a617d8fe54" - os-homedir@1.0.1, os-homedir@^1.0.0, os-homedir@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.1.tgz#0d62bdf44b916fd3bbdcf2cab191948fb094f007" @@ -2831,48 +1946,10 @@ os-tmpdir@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" -outpipe@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/outpipe/-/outpipe-1.1.1.tgz#50cf8616365e87e031e29a5ec9339a3da4725fa2" - dependencies: - shell-quote "^1.4.2" - packet-reader@0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/packet-reader/-/packet-reader-0.2.0.tgz#819df4d010b82d5ea5671f8a1a3acf039bcd7700" -pad-left@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/pad-left/-/pad-left-2.1.0.tgz#16e6a3b2d44a8e138cb0838cc7cb403a4fc9e994" - dependencies: - repeat-string "^1.5.4" - -pad-right@^0.2.2: - version "0.2.2" - resolved "https://registry.yarnpkg.com/pad-right/-/pad-right-0.2.2.tgz#6fbc924045d244f2a2a244503060d3bfc6009774" - dependencies: - repeat-string "^1.5.2" - -pako@~0.2.0: - version "0.2.9" - resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75" - -parents@^1.0.0, parents@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/parents/-/parents-1.0.1.tgz#fedd4d2bf193a77745fe71e371d73c3307d9c751" - dependencies: - path-platform "~0.11.15" - -parse-asn1@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.0.0.tgz#35060f6d5015d37628c770f4e091a0b5a278bc23" - dependencies: - asn1.js "^4.0.0" - browserify-aes "^1.0.0" - create-hash "^1.1.0" - evp_bytestokey "^1.0.0" - pbkdf2 "^3.0.3" - parse-glob@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" @@ -2896,9 +1973,9 @@ parse-passwd@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6" -path-browserify@~0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.0.tgz#a0b870729aae214005b7d5032ec2cbbb0fb4451a" +parseurl@^1.3.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.1.tgz#c8ab8c9223ba34888aa64a297b28853bec18da56" path-exists@^2.0.0: version "2.1.0" @@ -2906,7 +1983,7 @@ path-exists@^2.0.0: dependencies: pinkie-promise "^2.0.0" -path-is-absolute@^1.0.0: +path-is-absolute@1.0.1, path-is-absolute@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" @@ -2918,9 +1995,11 @@ path-parse@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" -path-platform@~0.11.15: - version "0.11.15" - resolved "https://registry.yarnpkg.com/path-platform/-/path-platform-0.11.15.tgz#e864217f74c36850f0852b78dc7bf7d4a5721bf2" +path-to-regexp@^1.1.1: + version "1.7.0" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-1.7.0.tgz#59fde0f435badacba103a84e9d3bc64e96b9937d" + dependencies: + isarray "0.0.1" path-type@^1.0.0: version "1.1.0" @@ -2930,16 +2009,6 @@ path-type@^1.0.0: pify "^2.0.0" pinkie-promise "^2.0.0" -pathname-match@^1.1.3: - version "1.2.0" - resolved "https://registry.yarnpkg.com/pathname-match/-/pathname-match-1.2.0.tgz#77cb8e3db1e41e4771c4942a9e4fecb610cc2d19" - -pbkdf2@^3.0.3: - version "3.0.9" - resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.9.tgz#f2c4b25a600058b3c3773c086c37dbbee1ffe693" - dependencies: - create-hmac "^1.1.2" - pg-connection-string@0.1.3, pg-connection-string@^0.1.3: version "0.1.3" resolved "https://registry.yarnpkg.com/pg-connection-string/-/pg-connection-string-0.1.3.tgz#da1847b20940e42ee1492beaf65d49d91b245df7" @@ -2961,7 +2030,7 @@ pg-types@1.*: postgres-date "~1.0.0" postgres-interval "~1.0.0" -pg@^6.1.2: +pg@6: version "6.1.2" resolved "https://registry.yarnpkg.com/pg/-/pg-6.1.2.tgz#2c896a7434502e2b938c100fc085b4e974a186db" dependencies: @@ -2993,9 +2062,9 @@ pinkie@^2.0.0: version "2.0.4" resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" -pino@^3.0.5: - version "3.1.1" - resolved "https://registry.yarnpkg.com/pino/-/pino-3.1.1.tgz#092ac6f427cd4a770090c44cc9edbe5feb74cd40" +pino@3: + version "3.1.2" + resolved "https://registry.yarnpkg.com/pino/-/pino-3.1.2.tgz#feb8f8baf13d6ebb58623da74ed5ac0a48024c13" dependencies: chalk "^1.1.1" fast-json-parse "^1.0.0" @@ -3019,37 +2088,13 @@ pkg-dir@^1.0.0: dependencies: find-up "^1.0.0" -plur@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/plur/-/plur-1.0.0.tgz#db85c6814f5e5e5a3b49efc28d604fec62975156" - -pluralize@^1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-1.2.1.tgz#d1a21483fd22bb41e58a12fa3421823140897c45" - -postcss-prefix@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/postcss-prefix/-/postcss-prefix-2.0.0.tgz#2139e8fba64ed71b93e3a8b1d4c5976e2a949c6f" - dependencies: - postcss "^5.0.8" - postcss-selector-parser "^1.3.0" - -postcss-selector-parser@^1.3.0: - version "1.3.3" - resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-1.3.3.tgz#d2ee19df7a64f8ef21c1a71c86f7d4835c88c281" - dependencies: - flatten "^1.0.2" - indexes-of "^1.0.1" - uniq "^1.0.1" - -postcss@^5.0.10, postcss@^5.0.8: - version "5.2.10" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-5.2.10.tgz#b58b64e04f66f838b7bc7cb41f7dac168568a945" - dependencies: - chalk "^1.1.3" - js-base64 "^2.1.9" - source-map "^0.5.6" - supports-color "^3.1.2" +plur@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/plur/-/plur-1.0.0.tgz#db85c6814f5e5e5a3b49efc28d604fec62975156" + +pluralize@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-1.2.1.tgz#d1a21483fd22bb41e58a12fa3421823140897c45" postgres-array@~1.0.0: version "1.0.2" @@ -3077,10 +2122,6 @@ preserve@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" -prettier-bytes@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/prettier-bytes/-/prettier-bytes-1.0.3.tgz#932b31c23efddb36fc66a82dcef362af3122982f" - pretty-ms@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/pretty-ms/-/pretty-ms-2.1.0.tgz#4257c256df3fb0b451d6affaab021884126981dc" @@ -3093,14 +2134,6 @@ process-nextick-args@~1.0.6: version "1.0.7" resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" -process@~0.11.0: - version "0.11.9" - resolved "https://registry.yarnpkg.com/process/-/process-0.11.9.tgz#7bd5ad21aa6253e7da8682264f1e11d11c0318c1" - -process@~0.5.1: - version "0.5.2" - resolved "https://registry.yarnpkg.com/process/-/process-0.5.2.tgz#1638d8a8e34c2f440a91db95ab9aeb677fc185cf" - progress@^1.1.8: version "1.1.8" resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be" @@ -3109,61 +2142,25 @@ pseudomap@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" -public-encrypt@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.0.tgz#39f699f3a46560dd5ebacbca693caf7c65c18cc6" - dependencies: - bn.js "^4.1.0" - browserify-rsa "^4.0.0" - create-hash "^1.1.0" - parse-asn1 "^5.0.0" - randombytes "^2.0.1" - -pump@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/pump/-/pump-1.0.2.tgz#3b3ee6512f94f0e575538c17995f9f16990a5d51" - dependencies: - end-of-stream "^1.1.0" - once "^1.3.1" - -punycode@1.3.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" - punycode@^1.3.2, punycode@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" +qs@~4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-4.0.0.tgz#c31d9b74ec27df75e543a86c78728ed8d4623607" + qs@~6.2.0: version "6.2.1" resolved "https://registry.yarnpkg.com/qs/-/qs-6.2.1.tgz#ce03c5ff0935bc1d9d69a9f14cbd18e568d67625" -qs@~6.3.0: - version "6.3.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.3.0.tgz#f403b264f23bc01228c74131b407f18d5ea5d442" - -querystring-es3@~0.2.0: - version "0.2.1" - resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" - -querystring@0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" - quick-format-unescaped@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/quick-format-unescaped/-/quick-format-unescaped-1.0.0.tgz#d4779757a39d04e31a7f033b9e941ba1c5bde069" dependencies: fast-safe-stringify "^1.0.8" -quote-stream@~0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/quote-stream/-/quote-stream-0.0.0.tgz#cde29e94c409b16e19dc7098b89b6658f9721d3b" - dependencies: - minimist "0.0.8" - through2 "~0.4.1" - -ramda@^0.23.0: +ramda@0.23: version "0.23.0" resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.23.0.tgz#ccd13fff73497a93974e3e86327bfd87bd6e8e2b" @@ -3174,29 +2171,18 @@ randomatic@^1.1.3: is-number "^2.0.2" kind-of "^3.0.2" -randombytes@^2.0.0, randombytes@^2.0.1: - version "2.0.3" - resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.3.tgz#674c99760901c3c4112771a31e521dc349cc09ec" - -rc@~1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/rc/-/rc-1.1.6.tgz#43651b76b6ae53b5c802f1151fa3fc3b059969c9" +raw-body@~2.1.2: + version "2.1.7" + resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.1.7.tgz#adfeace2e4fb3098058014d08c072dcc59758774" dependencies: - deep-extend "~0.4.0" - ini "~1.3.0" - minimist "^1.2.0" - strip-json-comments "~1.0.4" + bytes "2.4.0" + iconv-lite "0.4.13" + unpipe "1.0.0" re-emitter@^1.0.0: version "1.1.3" resolved "https://registry.yarnpkg.com/re-emitter/-/re-emitter-1.1.3.tgz#fa9e319ffdeeeb35b27296ef0f3d374dac2f52a7" -read-only-stream@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/read-only-stream/-/read-only-stream-2.0.0.tgz#2724fd6a8113d73764ac288d4386270c1dbf17f0" - dependencies: - readable-stream "^2.0.2" - read-pkg-up@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" @@ -3212,16 +2198,7 @@ read-pkg@^1.0.0: normalize-package-data "^2.3.2" path-type "^1.0.0" -"readable-stream@>=1.0.33-1 <1.1.0-0", readable-stream@~1.0.17, readable-stream@~1.0.26, readable-stream@~1.0.27-1: - version "1.0.34" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" - -"readable-stream@>=1.1.13-1 <1.2.0-0", readable-stream@^1.1.12, readable-stream@~1.1.9: +readable-stream@^1.1.12: version "1.1.14" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" dependencies: @@ -3230,7 +2207,7 @@ read-pkg@^1.0.0: isarray "0.0.1" string_decoder "~0.10.x" -readable-stream@^2, readable-stream@^2.0.0, "readable-stream@^2.0.0 || ^1.1.13", readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.3, readable-stream@^2.0.5, readable-stream@^2.1.0, readable-stream@^2.1.5, readable-stream@^2.2.2: +readable-stream@^2, readable-stream@^2.0.0, readable-stream@^2.0.2, readable-stream@^2.1.5, readable-stream@^2.2.2: version "2.2.2" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.2.tgz#a9e6fec3c7dda85f8bb1b3ba7028604556fc825e" dependencies: @@ -3242,7 +2219,7 @@ readable-stream@^2, readable-stream@^2.0.0, "readable-stream@^2.0.0 || ^1.1.13", string_decoder "~0.10.x" util-deprecate "~1.0.1" -readable-stream@~2.0.0, readable-stream@~2.0.5: +readable-stream@~2.0.5: version "2.0.6" resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.0.6.tgz#8f90341e68a53ccc928788dacfcd11b36eb9b78e" dependencies: @@ -3253,27 +2230,6 @@ readable-stream@~2.0.0, readable-stream@~2.0.5: string_decoder "~0.10.x" util-deprecate "~1.0.1" -readable-stream@~2.1.4: - version "2.1.5" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.1.5.tgz#66fa8b720e1438b364681f2ad1a63c618448c9d0" - dependencies: - buffer-shims "^1.0.0" - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "~1.0.0" - process-nextick-args "~1.0.6" - string_decoder "~0.10.x" - util-deprecate "~1.0.1" - -readdirp@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78" - dependencies: - graceful-fs "^4.1.2" - minimatch "^3.0.2" - readable-stream "^2.0.2" - set-immediate-shim "^1.0.1" - readline2@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/readline2/-/readline2-1.0.1.tgz#41059608ffc154757b715d9989d199ffbf372e35" @@ -3288,6 +2244,12 @@ rechoir@^0.6.2: dependencies: resolve "^1.1.6" +recursive-readdir@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/recursive-readdir/-/recursive-readdir-2.1.0.tgz#78b7bfd79582d3d7596b8ff1bd29fbd50229f6aa" + dependencies: + minimatch "3.0.2" + regenerator-runtime@^0.10.0: version "0.10.1" resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.1.tgz#257f41961ce44558b18f7814af48c17559f9faeb" @@ -3303,7 +2265,7 @@ repeat-element@^1.1.2: version "1.1.2" resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" -repeat-string@^1.5.2, repeat-string@^1.5.4: +repeat-string@^1.5.2: version "1.6.1" resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" @@ -3339,31 +2301,6 @@ request@2.75.0: tough-cookie "~2.3.0" tunnel-agent "~0.4.1" -request@^2.79.0: - version "2.79.0" - resolved "https://registry.yarnpkg.com/request/-/request-2.79.0.tgz#4dfe5bf6be8b8cdc37fcf93e04b65577722710de" - dependencies: - aws-sign2 "~0.6.0" - aws4 "^1.2.1" - caseless "~0.11.0" - combined-stream "~1.0.5" - extend "~3.0.0" - forever-agent "~0.6.1" - form-data "~2.1.1" - har-validator "~2.0.6" - hawk "~3.1.3" - http-signature "~1.1.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.7" - oauth-sign "~0.8.1" - qs "~6.3.0" - stringstream "~0.0.4" - tough-cookie "~2.3.0" - tunnel-agent "~0.4.1" - uuid "^3.0.0" - require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" @@ -3394,14 +2331,17 @@ resolve-from@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-2.0.0.tgz#9480ab20e94ffa1d9e80a804c7ea147611966b57" -resolve@1.1.7, resolve@~1.1.7: +resolve-path@^1.3.1: + version "1.3.3" + resolved "https://registry.yarnpkg.com/resolve-path/-/resolve-path-1.3.3.tgz#4d83aba6468c2b8e632a575e3f52b0fa0dbe1a5c" + dependencies: + http-errors "~1.5.0" + path-is-absolute "1.0.1" + +resolve@^1.1.6, resolve@^1.1.7, resolve@~1.1.7: version "1.1.7" resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b" -resolve@^1.1.3, resolve@^1.1.4, resolve@^1.1.6, resolve@^1.1.7: - version "1.2.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.2.0.tgz#9589c3f2f6149d1417a40becc1663db6ec6bc26c" - restore-cursor@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" @@ -3421,20 +2361,12 @@ right-align@^0.1.1: dependencies: align-text "^0.1.1" -right-now@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/right-now/-/right-now-1.0.0.tgz#6e89609deebd7dcdaf8daecc9aea39cf585a0918" - -rimraf@2, rimraf@^2.2.8, rimraf@^2.3.3, rimraf@^2.4.3, rimraf@^2.4.4, rimraf@^2.5.4, rimraf@~2.5.1, rimraf@~2.5.4: +rimraf@^2.2.8, rimraf@^2.3.3, rimraf@^2.4.3, rimraf@^2.4.4, rimraf@^2.5.4: version "2.5.4" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.5.4.tgz#96800093cbf1a0c86bd95b4625467535c29dfa04" dependencies: glob "^7.0.5" -ripemd160@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-1.0.1.tgz#93a4bbd4942bc574b69a8fa57c71de10ecca7d6e" - run-async@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/run-async/-/run-async-0.1.0.tgz#c8ad4a5e110661e402a7d21b530e009f25f8e389" @@ -3449,7 +2381,7 @@ rx-lite@^3.1.2: version "3.1.2" resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102" -"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@~5.3.0: +"semver@2 || 3 || 4 || 5", semver@^5.3.0: version "5.3.0" resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" @@ -3457,79 +2389,13 @@ semver@4.3.2: version "4.3.2" resolved "https://registry.yarnpkg.com/semver/-/semver-4.3.2.tgz#c7a07158a80bedd052355b770d82d6640f803be7" -server-router@^4.0.0: - version "4.0.2" - resolved "https://registry.yarnpkg.com/server-router/-/server-router-4.0.2.tgz#2a1354d3654ad1a3254d41499f41dcb232fd0507" - dependencies: - methods "^1.1.1" - pathname-match "^1.1.3" - urlencode "^1.1.0" - wayfarer "^6.1.4" - -server-sink@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/server-sink/-/server-sink-1.0.0.tgz#b3f6e3098c99799dfeadb71cbbab14d599f7a4b8" - dependencies: - http-ndjson "^3.0.0" - size-stream "^1.0.1" - -set-blocking@^2.0.0, set-blocking@~2.0.0: +set-blocking@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" -set-immediate-shim@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" - -sha.js@^2.3.6, sha.js@~2.4.4: - version "2.4.8" - resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.8.tgz#37068c2c476b6baf402d14a49c67f597921f634f" - dependencies: - inherits "^2.0.1" - -shallow-copy@~0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/shallow-copy/-/shallow-copy-0.0.1.tgz#415f42702d73d810330292cc5ee86eae1a11a170" - -shasum@^1.0.0: +setprototypeof@1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/shasum/-/shasum-1.0.2.tgz#e7012310d8f417f4deb5712150e5678b87ae565f" - dependencies: - json-stable-stringify "~0.0.0" - sha.js "~2.4.4" - -sheet-router@^4.0.1: - version "4.2.0" - resolved "https://registry.yarnpkg.com/sheet-router/-/sheet-router-4.2.0.tgz#f16091a4abdba3faa2eaf1fdc97e2f963e5794b7" - dependencies: - global "^4.3.0" - wayfarer "^6.2.1" - xtend "^4.0.1" - -sheetify@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/sheetify/-/sheetify-6.0.1.tgz#b11851aca2f0a149cbc97c7833bd599988d42da5" - dependencies: - falafel "^1.2.0" - insert-css "^2.0.0" - map-limit "0.0.1" - postcss "^5.0.10" - postcss-prefix "^2.0.0" - resolve "^1.1.7" - stack-trace "0.0.9" - static-eval "^1.1.0" - style-resolve "^1.0.0" - through2 "^2.0.0" - xtend "^4.0.1" - -shell-quote@^1.4.2, shell-quote@^1.6.1: - version "1.6.1" - resolved "https://registry.yarnpkg.com/shell-quote/-/shell-quote-1.6.1.tgz#f4781949cce402697127430ea3b3c5476f481767" - dependencies: - array-filter "~0.0.0" - array-map "~0.0.0" - array-reduce "~0.0.0" - jsonify "~0.0.0" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.2.tgz#81a552141ec104b88e89ce383103ad5c66564d08" shelljs@^0.7.5: version "0.7.6" @@ -3547,12 +2413,6 @@ signal-exit@^3.0.0, signal-exit@^3.0.1: version "3.0.2" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" -size-stream@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/size-stream/-/size-stream-1.0.1.tgz#6f31429547c951ea5dddbb385325ea7ac132a6d9" - dependencies: - readable-stream "^2.0.3" - slice-ansi@0.0.4: version "0.0.4" resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" @@ -3567,27 +2427,15 @@ sntp@1.x.x: dependencies: hoek "2.x.x" -"source-map@>= 0.1.2", source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.1, source-map@~0.5.3: - version "0.5.6" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" - -source-map@^0.1.34, source-map@~0.1.33: - version "0.1.43" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.1.43.tgz#c24bc146ca517c1471f5dacbe2571b2b7f9e3346" - dependencies: - amdefine ">=0.0.4" - -source-map@^0.4.4, source-map@~0.4.0, source-map@~0.4.2: +source-map@^0.4.4: version "0.4.4" resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" dependencies: amdefine ">=0.0.4" -source-map@~0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.2.0.tgz#dab73fbcfc2ba819b4de03bd6f6eaa48164b3f9d" - dependencies: - amdefine ">=0.0.4" +source-map@^0.5.0, source-map@^0.5.3, source-map@~0.5.1: + version "0.5.6" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" spawn-wrap@1.2.4: version "1.2.4" @@ -3614,12 +2462,6 @@ spdx-license-ids@^1.0.2: version "1.2.2" resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57" -split2@^0.2.1: - version "0.2.1" - resolved "https://registry.yarnpkg.com/split2/-/split2-0.2.1.tgz#02ddac9adc03ec0bb78c1282ec079ca6e85ae900" - dependencies: - through2 "~0.6.1" - split2@^2.0.1: version "2.1.1" resolved "https://registry.yarnpkg.com/split2/-/split2-2.1.1.tgz#7a1f551e176a90ecd3345f7246a0cfe175ef4fd0" @@ -3651,10 +2493,6 @@ sshpk@^1.7.0: jsbn "~0.1.0" tweetnacl "~0.14.0" -stack-trace@0.0.9: - version "0.0.9" - resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.9.tgz#a8f6eaeca90674c333e7c43953f275b451510695" - stack-utils@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-0.4.0.tgz#940cb82fccfa84e8ff2f3fdf293fe78016beccd1" @@ -3670,7 +2508,7 @@ standard-engine@~5.2.0: minimist "^1.1.0" pkg-config "^1.0.1" -standard@^8.6.0: +standard@8: version "8.6.0" resolved "https://registry.yarnpkg.com/standard/-/standard-8.6.0.tgz#635132be7bfb567c2921005f30f9e350e4752aad" dependencies: @@ -3682,70 +2520,9 @@ standard@^8.6.0: eslint-plugin-standard "~2.0.1" standard-engine "~5.2.0" -static-eval@^1.1.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/static-eval/-/static-eval-1.1.1.tgz#ca8130210354cf13d9a722bc7e923778457bb192" - dependencies: - escodegen "^1.8.1" - -static-eval@~0.2.0: - version "0.2.4" - resolved "https://registry.yarnpkg.com/static-eval/-/static-eval-0.2.4.tgz#b7d34d838937b969f9641ca07d48f8ede263ea7b" - dependencies: - escodegen "~0.0.24" - -static-module@^1.3.0: +"statuses@>= 1.2.1 < 2", "statuses@>= 1.3.1 < 2", statuses@^1.2.0: version "1.3.1" - resolved "https://registry.yarnpkg.com/static-module/-/static-module-1.3.1.tgz#79071d340e4419e4ab5ce87976a9eb67250c8493" - dependencies: - concat-stream "~1.4.5" - duplexer2 "~0.0.2" - escodegen "~1.3.2" - falafel "^1.0.0" - has "^1.0.0" - object-inspect "~0.4.0" - quote-stream "~0.0.0" - readable-stream "~1.0.27-1" - shallow-copy "~0.0.1" - static-eval "~0.2.0" - through2 "~0.4.1" - -stdout-stream@^1.4.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/stdout-stream/-/stdout-stream-1.4.0.tgz#a2c7c8587e54d9427ea9edb3ac3f2cd522df378b" - dependencies: - readable-stream "^2.0.1" - -stream-browserify@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db" - dependencies: - inherits "~2.0.1" - readable-stream "^2.0.2" - -stream-combiner2@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/stream-combiner2/-/stream-combiner2-1.1.1.tgz#fb4d8a1420ea362764e21ad4780397bebcb41cbe" - dependencies: - duplexer2 "~0.1.0" - readable-stream "^2.0.2" - -stream-http@^2.0.0: - version "2.6.2" - resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.6.2.tgz#bdfe40d2ee9262eb6bf2255bb3ad0ec0cdd6526d" - dependencies: - builtin-status-codes "^3.0.0" - inherits "^2.0.1" - readable-stream "^2.1.0" - to-arraybuffer "^1.0.0" - xtend "^4.0.0" - -stream-splicer@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/stream-splicer/-/stream-splicer-2.0.0.tgz#1b63be438a133e4b671cc1935197600175910d83" - dependencies: - inherits "^2.0.1" - readable-stream "^2.0.2" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" string-width@^1.0.1, string-width@^1.0.2: version "1.0.2" @@ -3770,7 +2547,7 @@ string.prototype.trim@~1.1.2: es-abstract "^1.5.0" function-bind "^1.0.2" -string_decoder@~0.10.0, string_decoder@~0.10.x: +string_decoder@~0.10.x: version "0.10.31" resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" @@ -3778,12 +2555,6 @@ stringstream@~0.0.4: version "0.0.5" resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" -strip-ansi@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-0.3.0.tgz#25f48ea22ca79187f3174a4db8759347bb126220" - dependencies: - ansi-regex "^0.2.1" - strip-ansi@^3.0.0, strip-ansi@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" @@ -3800,27 +2571,10 @@ strip-bom@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" -strip-json-comments@~1.0.1, strip-json-comments@~1.0.4: +strip-json-comments@~1.0.1: version "1.0.4" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-1.0.4.tgz#1e15fbcac97d3ee99bf2d73b4c656b082bbafb91" -style-resolve@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/style-resolve/-/style-resolve-1.0.1.tgz#2d2067c944d5fb7f553ca75c4e7947df43796fae" - dependencies: - resolve "^1.1.7" - xtend "^4.0.1" - -subarg@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/subarg/-/subarg-1.0.0.tgz#f62cf17581e996b48fc965699f54c06ae268b8d2" - dependencies: - minimist "^1.1.0" - -supports-color@^0.2.0: - version "0.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-0.2.0.tgz#d92de2694eb3f67323973d7ae3d8b55b4c22190a" - supports-color@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" @@ -3831,12 +2585,6 @@ supports-color@^3.1.2: dependencies: has-flag "^1.0.0" -syntax-error@^1.1.1: - version "1.1.6" - resolved "https://registry.yarnpkg.com/syntax-error/-/syntax-error-1.1.6.tgz#b4549706d386cc1c1dc7c2423f18579b6cade710" - dependencies: - acorn "^2.7.0" - table@^3.7.8: version "3.8.3" resolved "https://registry.yarnpkg.com/table/-/table-3.8.3.tgz#2bbc542f0fda9861a755d3947fefd8b3f513855f" @@ -3881,7 +2629,7 @@ tap-parser@^4.2.2, tap-parser@^4.2.3: optionalDependencies: readable-stream "^2" -tap-spec@^4.1.1: +tap-spec@4: version "4.1.1" resolved "https://registry.yarnpkg.com/tap-spec/-/tap-spec-4.1.1.tgz#e2e9f26f5208232b1f562288c97624d58a88f05a" dependencies: @@ -3894,7 +2642,7 @@ tap-spec@^4.1.1: tap-out "^1.4.1" through2 "^2.0.0" -tap@^9.0.3: +tap@9: version "9.0.3" resolved "https://registry.yarnpkg.com/tap/-/tap-9.0.3.tgz#bd3deecb507f4e368486eeba8f10cd78f42f7283" dependencies: @@ -3918,7 +2666,7 @@ tap@^9.0.3: tap-parser "^4.2.2" tmatch "^3.0.0" -tape@^4.6.3: +tape@4.6: version "4.6.3" resolved "https://registry.yarnpkg.com/tape/-/tape-4.6.3.tgz#637e77581e9ab2ce17577e9bd4ce4f575806d8b6" dependencies: @@ -3936,27 +2684,6 @@ tape@^4.6.3: string.prototype.trim "~1.1.2" through "~2.3.8" -tar-pack@~3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.3.0.tgz#30931816418f55afc4d21775afdd6720cee45dae" - dependencies: - debug "~2.2.0" - fstream "~1.0.10" - fstream-ignore "~1.0.5" - once "~1.3.3" - readable-stream "~2.1.4" - rimraf "~2.5.1" - tar "~2.2.1" - uid-number "~0.0.6" - -tar@~2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" - dependencies: - block-stream "*" - fstream "^1.0.2" - inherits "2" - test-exclude@^3.3.0: version "3.3.0" resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-3.3.0.tgz#7a17ca1239988c98367b0621456dbb7d4bc38977" @@ -3971,35 +2698,26 @@ text-table@~0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" -through2@^1.0.0: - version "1.1.1" - resolved "https://registry.yarnpkg.com/through2/-/through2-1.1.1.tgz#0847cbc4449f3405574dbdccd9bb841b83ac3545" +thenify-all@^1.0.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" dependencies: - readable-stream ">=1.1.13-1 <1.2.0-0" - xtend ">=4.0.0 <4.1.0-0" + thenify ">= 3.1.0 < 4" -through2@^2.0.0, through2@^2.0.1, through2@^2.0.2: +"thenify@>= 3.1.0 < 4": + version "3.2.1" + resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.2.1.tgz#251fd1c80aff6e5cf57cb179ab1fcb724269bd11" + dependencies: + any-promise "^1.0.0" + +through2@^2.0.0, through2@^2.0.2: version "2.0.3" resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.3.tgz#0004569b37c7c74ba39c43f3ced78d1ad94140be" dependencies: readable-stream "^2.1.5" xtend "~4.0.1" -through2@~0.4.1: - version "0.4.2" - resolved "https://registry.yarnpkg.com/through2/-/through2-0.4.2.tgz#dbf5866031151ec8352bb6c4db64a2292a840b9b" - dependencies: - readable-stream "~1.0.17" - xtend "~2.1.1" - -through2@~0.6.1: - version "0.6.5" - resolved "https://registry.yarnpkg.com/through2/-/through2-0.6.5.tgz#41ab9c67b29d57209071410e1d7a7a968cd3ad48" - dependencies: - readable-stream ">=1.0.33-1 <1.1.0-0" - xtend ">=4.0.0 <4.1.0-0" - -through@2, "through@>=2.2.7 <3", through@^2.3.6, through@^2.3.7, through@~2.3.4, through@~2.3.8: +through@2, through@^2.3.6, through@~2.3.4, through@~2.3.8: version "2.3.8" resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" @@ -4009,20 +2727,10 @@ tildify@~1.0.0: dependencies: user-home "^1.0.0" -timers-browserify@^1.0.1: - version "1.4.2" - resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-1.4.2.tgz#c9c58b575be8407375cb5e2462dacee74359f41d" - dependencies: - process "~0.11.0" - tmatch@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/tmatch/-/tmatch-3.0.0.tgz#7d2071dedbbc587f194acda3067bd0747b670991" -to-arraybuffer@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" - to-fast-properties@^1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.2.tgz#f3f5c0c3ba7299a7ef99427e44633257ade43320" @@ -4041,10 +2749,6 @@ tryit@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/tryit/-/tryit-1.0.3.tgz#393be730a9446fd1ead6da59a014308f36c289cb" -tty-browserify@~0.0.0: - version "0.0.0" - resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" - tunnel-agent@~0.4.1: version "0.4.3" resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.4.3.tgz#6373db76909fe570e08d73583365ed828a74eeeb" @@ -4059,11 +2763,18 @@ type-check@~0.3.2: dependencies: prelude-ls "~1.1.2" -typedarray@^0.0.6, typedarray@~0.0.5: +type-is@^1.5.5, type-is@~1.6.6: + version "1.6.14" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.14.tgz#e219639c17ded1ca0789092dd54a03826b817cb2" + dependencies: + media-typer "0.3.0" + mime-types "~2.1.13" + +typedarray@^0.0.6: version "0.0.6" resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" -uglify-js@2.x.x, uglify-js@^2.6: +uglify-js@^2.6: version "2.7.5" resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.7.5.tgz#4612c0c7baaee2ba7c487de4904ae122079f2ca8" dependencies: @@ -4076,51 +2787,10 @@ uglify-to-browserify@~1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" -uglifyify@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/uglifyify/-/uglifyify-3.0.4.tgz#487e080a5a7798880e68e90def9b06681fb13bd2" - dependencies: - convert-source-map "~1.1.0" - extend "^1.2.1" - minimatch "^3.0.2" - through "~2.3.4" - uglify-js "2.x.x" - -uid-number@~0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" - -ulid@^0.1.0: +ulid@0.1: version "0.1.0" resolved "https://registry.yarnpkg.com/ulid/-/ulid-0.1.0.tgz#9044142d2b4b7bb2551ed7d6e2d301c46e1d3725" -umd@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/umd/-/umd-3.0.1.tgz#8ae556e11011f63c2596708a8837259f01b3d60e" - -unassert@^1.3.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/unassert/-/unassert-1.5.1.tgz#cbc88ec387417c5a5e4c02d3cd07be98bd75ff76" - dependencies: - acorn "^4.0.0" - call-matcher "^1.0.1" - deep-equal "^1.0.0" - espurify "^1.3.0" - estraverse "^4.1.0" - esutils "^2.0.2" - object-assign "^4.1.0" - -unassertify@^2.0.3: - version "2.0.4" - resolved "https://registry.yarnpkg.com/unassertify/-/unassertify-2.0.4.tgz#b3ca2ba5f29b4836e35a6dd77e5b20f6dbbf8e52" - dependencies: - acorn "^4.0.0" - convert-source-map "^1.1.1" - escodegen "^1.6.1" - multi-stage-sourcemap "^0.2.1" - through "^2.3.7" - unassert "^1.3.1" - unicode-length@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/unicode-length/-/unicode-length-1.0.3.tgz#5ada7a7fed51841a418a328cf149478ac8358abb" @@ -4132,22 +2802,9 @@ uniq@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" -url-trim@^1.0.0: +unpipe@1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/url-trim/-/url-trim-1.0.0.tgz#40057e2f164b88e5daca7269da47e6d1dd837adc" - -url@~0.11.0: - version "0.11.0" - resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" - dependencies: - punycode "1.3.2" - querystring "0.2.0" - -urlencode@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/urlencode/-/urlencode-1.1.0.tgz#1f2ba26f013c85f0133f7a3ad6ff2730adf7cbb7" - dependencies: - iconv-lite "~0.4.11" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" user-home@^1.0.0, user-home@^1.1.1: version "1.1.1" @@ -4163,16 +2820,6 @@ util-deprecate@~1.0.1: version "1.0.2" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" -util@0.10.3, util@~0.10.1: - version "0.10.3" - resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" - dependencies: - inherits "2.0.1" - -uuid@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.1.tgz#6544bba2dfda8c1cf17e629a3a305e2bb1fee6c1" - v8flags@^2.0.2: version "2.0.11" resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-2.0.11.tgz#bca8f30f0d6d60612cc2c00641e6962d42ae6881" @@ -4186,43 +2833,16 @@ validate-npm-package-license@^3.0.1: spdx-correct "~1.0.0" spdx-expression-parse "~1.0.0" +vary@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.0.tgz#e1e5affbbd16ae768dd2674394b9ad3022653140" + verror@1.3.6: version "1.3.6" resolved "https://registry.yarnpkg.com/verror/-/verror-1.3.6.tgz#cff5df12946d297d2baaefaa2689e25be01c005c" dependencies: extsprintf "1.0.2" -vm-browserify@~0.0.1: - version "0.0.4" - resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-0.0.4.tgz#5d7ea45bbef9e4a6ff65f95438e0a87c357d5a73" - dependencies: - indexof "0.0.1" - -watchify-request@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/watchify-request/-/watchify-request-2.1.0.tgz#ddd5d96abfc54d43952b0e543d6feea775e7fff3" - dependencies: - bl "^0.9.3" - events "^1.0.2" - -watchify@^3.7.0: - version "3.8.0" - resolved "https://registry.yarnpkg.com/watchify/-/watchify-3.8.0.tgz#a5cacc3517ca1e637d7b0af745375cafb597d6bb" - dependencies: - anymatch "^1.3.0" - browserify "^13.0.0" - chokidar "^1.0.0" - defined "^1.0.0" - outpipe "^1.1.0" - through2 "^2.0.0" - xtend "^4.0.0" - -wayfarer@^6.1.4, wayfarer@^6.2.1: - version "6.3.0" - resolved "https://registry.yarnpkg.com/wayfarer/-/wayfarer-6.3.0.tgz#47bf3cca0191d429b2819d46ef69145dd6178b85" - dependencies: - xtend "^4.0.1" - which-module@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" @@ -4233,20 +2853,18 @@ which@^1.2.12, which@^1.2.4, which@^1.2.9: dependencies: isexe "^1.1.1" -wide-align@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.0.tgz#40edde802a71fea1f070da3e62dcda2e7add96ad" - dependencies: - string-width "^1.0.1" - window-size@0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" -wordwrap@0.0.2, wordwrap@~0.0.2: +wordwrap@0.0.2: version "0.0.2" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" +wordwrap@~0.0.2: + version "0.0.3" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.3.tgz#a3d5da6cd5c0bc0008d37234bbaf1bed63059107" + wordwrap@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" @@ -4276,16 +2894,10 @@ write@^0.2.1: dependencies: mkdirp "^0.5.1" -"xtend@>=4.0.0 <4.1.0-0", xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.1: +xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" -xtend@~2.1.1: - version "2.1.2" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-2.1.2.tgz#6efecc2a4dad8e6962c4901b337ce7ba87b5d28b" - dependencies: - object-keys "~0.4.0" - y18n@^3.2.1: version "3.2.1" resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" @@ -4326,19 +2938,3 @@ yargs@~3.10.0: cliui "^2.1.0" decamelize "^1.0.0" window-size "0.1.0" - -yo-yo@^1.2.2: - version "1.3.2" - resolved "https://registry.yarnpkg.com/yo-yo/-/yo-yo-1.3.2.tgz#73b253cc8e24f058ed5c765a3a234c4ab0112393" - dependencies: - bel "^4.0.0" - morphdom "~2.1.0" - -yo-yoify@^3.5.0: - version "3.5.0" - resolved "https://registry.yarnpkg.com/yo-yoify/-/yo-yoify-3.5.0.tgz#b8469e94affdb87dbb61adfb24a8e0ce30c59351" - dependencies: - falafel "^1.2.0" - hyperx "^2.0.3" - on-load "^3.2.0" - through2 "^2.0.1" From 41aa2712ec8117573ee30a6d0270d92a286b723b Mon Sep 17 00:00:00 2001 From: Frederic Gingras Date: Wed, 18 Jan 2017 19:23:34 -0500 Subject: [PATCH 18/27] server: library: database: find --- server.js | 7 ++++++- server/controllers/report.js | 15 +++++++++++++-- server/library/database.js | 18 ++++++++++++++++++ 3 files changed, 37 insertions(+), 3 deletions(-) diff --git a/server.js b/server.js index 376b22577..87d5f1bad 100644 --- a/server.js +++ b/server.js @@ -10,6 +10,7 @@ const Database = require('./server/library/database') const Cache = require('./server/library/cache') const MemoryCache = require('./server/library/memory-cache') + // Setup Container const container = new Container(log.debug.bind(log)) container.set('container', container) @@ -24,6 +25,7 @@ container.load(require('./server/repositories/expenses')) container.load(require('./server/services/import')) container.load(require('./server/services/report')) + // Setup Routes const router = require('koa-router')() @@ -34,6 +36,7 @@ const importController = container.create(require('./server/controllers/import') router.get('/import', importController.import) router.post('/import', koaBody, importController.import) + // Setup Server const staticPath = path.join(__dirname, 'static') const app = new Koa() @@ -44,7 +47,7 @@ app.use(require('koa2-handlebars')({ viewPath: path.join(__dirname, 'views'), layoutPath: path.join(__dirname, 'views'), partialPath: path.join(__dirname, 'views', 'partials') -})) // Setup handlebars for views +})) app.use(require('koa-static')('static', staticPath)) // Serve static files app.use(require('./server/middlewares/force-https')) // Force HTTPS in prod app.use(require('./server/middlewares/request-logger')(log)) // Log requests @@ -52,6 +55,8 @@ app.use(router.routes()) // Router app.use(router.allowedMethods()) // Unhandled method router middleware app.use((ctx) => ctx.render('not-found', {layout: 'layout-error'})) // Handle 404s + +// Start Server if (!module.parent) { const port = process.env.PORT || 8000 app.listen(port) diff --git a/server/controllers/report.js b/server/controllers/report.js index 03ed3aeb1..fb71e99b6 100644 --- a/server/controllers/report.js +++ b/server/controllers/report.js @@ -1,10 +1,21 @@ class ReportController { constructor (reportService) { this.reportService = reportService + + this.report = this.report.bind(this) } - report (ctx) { - ctx.redirect('/import') + async report (ctx) { + const reportEntities = await this.reportService.report() + console.log(reportEntities) + + // If the user didn't import data yet, send him to the import page + if (Object.keys(reportEntities.expenses).length === 0) { + ctx.redirect('/import') + return + } + + ctx.body = 'report' } } diff --git a/server/library/database.js b/server/library/database.js index 85bab1b59..514d12d72 100644 --- a/server/library/database.js +++ b/server/library/database.js @@ -20,6 +20,24 @@ class Database { return new Entity(humps.camelizeKeys(data[0])) } + async find (TABLE, Entity, options = {}) { + let query = this.knex.select().from(TABLE) + + if (options.where) { + query = query.where(humps.decamelizeKeys(options.where)) + } + if (options.limit) { + query = query.limit(1) + } + + const data = await query + + if (!data || data.length === 0) { + return [] + } + return data.map(row => new Entity(humps.camelizeKeys(row))) + } + async create (TABLE, Entity, entity) { entity.id = this.idGenerator() // Assign a new id From 6237d5f45a9d04b8a8dfbf359220dc3801070b0d Mon Sep 17 00:00:00 2001 From: Frederic Gingras Date: Wed, 18 Jan 2017 21:46:37 -0500 Subject: [PATCH 19/27] server: controllers: report view --- Makefile | 3 ++ package.json | 2 - server.js | 10 ++--- server/controllers/import.js | 17 +++++++++ server/controllers/report.js | 54 ++++++++++++++++++++++++++- server/helpers/csv.js | 32 ++++++++++++---- server/library/database.js | 2 +- server/library/promisify.js | 20 ++++++++++ server/middlewares/request-logger.js | 4 +- server/models/employee.js | 2 +- server/models/expense.js | 2 +- server/models/expense_category.js | 2 +- server/repositories/taxes.js | 7 +++- server/services/import.js | 20 ++++++---- server/services/report.js | 9 +++-- support/screenshot2.png | Bin 0 -> 256400 bytes tests/unit/csv_helper.js | 14 ++++++- views/import.hbs | 10 +++-- views/layout.hbs | 9 +++-- views/report.hbs | 41 ++++++++++++++++++++ 20 files changed, 213 insertions(+), 47 deletions(-) create mode 100644 server/library/promisify.js create mode 100644 support/screenshot2.png create mode 100644 views/report.hbs diff --git a/Makefile b/Makefile index b8ba96a83..61f4ea5c3 100644 --- a/Makefile +++ b/Makefile @@ -39,6 +39,9 @@ db-create: ## Creates a new database for the application to use (run once) psql -c "CREATE IF NOT EXIST ROLE wave_challenge WITH SUPERUSER LOGIN PASSWORD 'wave_challenge'" psql -c "CREATE IF NOT EXIST DATABASE wave_challenge WITH OWNER wave_challenge" +db-wipe: ## Creates a new database for the application to use (run once) + psql -d wave_challenge -c "DELETE FROM expenses; DELETE FROM expense_categories; DELETE FROM employees;" + db-migrate: ## Runs all pending migrations againt the database ./node_modules/.bin/knex migrate:latest diff --git a/package.json b/package.json index 577a1980d..53de00f51 100644 --- a/package.json +++ b/package.json @@ -10,8 +10,6 @@ "knex": "0.12", "koa": "2", "koa-body": "2", - "koa-convert": "1.2", - "koa-hbs": "0.9", "koa-router": "7", "koa-static": "https://github.com/kiasaki/koa-static.git", "koa2-handlebars": "https://github.com/kiasaki/koa-handlebars.git", diff --git a/server.js b/server.js index 87d5f1bad..f170ead1e 100644 --- a/server.js +++ b/server.js @@ -1,16 +1,14 @@ const path = require('path') const knex = require('knex') const log = require('pino')() -const convert = require('koa-convert') const Koa = require('koa') -const koaBody = require('koa-body')() +const koaBody = require('koa-body')({multipart: true}) const Container = require('./server/library/container') const Database = require('./server/library/database') const Cache = require('./server/library/cache') const MemoryCache = require('./server/library/memory-cache') - // Setup Container const container = new Container(log.debug.bind(log)) container.set('container', container) @@ -25,7 +23,6 @@ container.load(require('./server/repositories/expenses')) container.load(require('./server/services/import')) container.load(require('./server/services/report')) - // Setup Routes const router = require('koa-router')() @@ -36,7 +33,6 @@ const importController = container.create(require('./server/controllers/import') router.get('/import', importController.import) router.post('/import', koaBody, importController.import) - // Setup Server const staticPath = path.join(__dirname, 'static') const app = new Koa() @@ -46,7 +42,8 @@ app.use(require('koa2-handlebars')({ defaultLayout: 'layout', viewPath: path.join(__dirname, 'views'), layoutPath: path.join(__dirname, 'views'), - partialPath: path.join(__dirname, 'views', 'partials') + partialPath: path.join(__dirname, 'views', 'partials'), + helpers: {num: (n) => (n / 100).toFixed(2)} })) app.use(require('koa-static')('static', staticPath)) // Serve static files app.use(require('./server/middlewares/force-https')) // Force HTTPS in prod @@ -55,7 +52,6 @@ app.use(router.routes()) // Router app.use(router.allowedMethods()) // Unhandled method router middleware app.use((ctx) => ctx.render('not-found', {layout: 'layout-error'})) // Handle 404s - // Start Server if (!module.parent) { const port = process.env.PORT || 8000 diff --git a/server/controllers/import.js b/server/controllers/import.js index 4a29f9b67..5ee92c2f6 100644 --- a/server/controllers/import.js +++ b/server/controllers/import.js @@ -1,9 +1,26 @@ +const fs = require('fs') +const promisify = require('../library/promisify') + class ImportController { constructor (importService) { this.importService = importService + + this.import = this.import.bind(this) } async import (ctx) { + if (ctx.method === 'POST') { + const csvPath = ctx.request.body.files.expenses.path + const csvContents = await promisify(fs.readFile)(csvPath, 'utf8') + + // Pass CSV data to import service + await this.importService.import(csvContents) + + // Send user to report page + ctx.redirect('/') + return + } + await ctx.render('import') } } diff --git a/server/controllers/report.js b/server/controllers/report.js index fb71e99b6..f0ec39cac 100644 --- a/server/controllers/report.js +++ b/server/controllers/report.js @@ -1,3 +1,10 @@ +const R = require('ramda') + +const MONTH_NAMES = [ + 'January', 'February', 'March', 'April', 'May', 'June', + 'July', 'August', 'September', 'October', 'November', 'December' +] + class ReportController { constructor (reportService) { this.reportService = reportService @@ -5,9 +12,32 @@ class ReportController { this.report = this.report.bind(this) } + groupExpensesByMonth (expenses) { + const sortedExpenses = R.sortBy(R.prop('date'), R.values(expenses)) + const months = [] + let lastMonth = -1 + + for (let expense of sortedExpenses) { + if (expense.date.getMonth() !== lastMonth) { + // Add the new month to the list + months.push({ + year: expense.date.getFullYear(), + month: expense.date.getMonth(), + monthName: MONTH_NAMES[expense.date.getMonth()], + expenses: [expense] + }) + lastMonth = expense.date.getMonth() + } else { + // We didn't change months, simply append expense to last logged month + months[months.length - 1].expenses.push(expense) + } + } + + return months + } + async report (ctx) { const reportEntities = await this.reportService.report() - console.log(reportEntities) // If the user didn't import data yet, send him to the import page if (Object.keys(reportEntities.expenses).length === 0) { @@ -15,7 +45,27 @@ class ReportController { return } - ctx.body = 'report' + // Now groups entites by month and sum ammount for easy rendering + const months = this.groupExpensesByMonth(reportEntities.expenses) + + const expenseTax = (e) => e.amount * (reportEntities.taxes[e.taxId].percent / 100) + + // Calculate totals for each month (now we have all expenses grouped) + for (let month of months) { + // First precompute taxes and pretty numbers for expenses + month.expenses = month.expenses.map((e) => R.merge(e, { + employeeName: reportEntities.employees[e.employeeId].name, + categoryName: reportEntities.expenseCategories[e.categoryId].name, + amountTax: expenseTax(e), + amountTotal: e.amount + expenseTax(e) + })) + + month.totalPreTax = R.sum(R.pluck('amount', month.expenses)) + month.totalTax = R.sum(R.pluck('amountTax', month.expenses)) + month.total = month.totalPreTax + month.totalTax + } + + await ctx.render('report', {months: R.reverse(months)}) } } diff --git a/server/helpers/csv.js b/server/helpers/csv.js index 55d101fb9..0e056add7 100644 --- a/server/helpers/csv.js +++ b/server/helpers/csv.js @@ -1,3 +1,5 @@ +/* eslint-disable no-fallthrough */ +const R = require('ramda') const assert = require('assert') class CSVHelper { @@ -14,9 +16,13 @@ class CSVHelper { assert(typeof data === 'string', 'CSVHelper: parse: data needs to be a string') const result = [{}] let columnIndex = 0 + let inString = false for (let i = 0; i < data.length; i++) { const currentRow = result[result.length - 1] + const columnName = columnIndex < columns.length + ? columns[columnIndex] + : String(columnIndex + 1) switch (data[i]) { case '\r': @@ -29,15 +35,23 @@ class CSVHelper { result.push({}) } break - case ',': - // Matching on ',' without a way to include a comma in strings - // or escape it is simplistic but ok for our current needs - columnIndex++ + case '"': + // Skip appending "string" closing double quote + inString = false break + case ',': + // Ignore commas while within a string + if (!inString) { + // Look ahead for "string" start + if (data[i + 1] === '"') { + inString = true + i++ + } + + columnIndex++ + break + } default: - const columnName = columnIndex < columns.length - ? columns[columnIndex] - : String(columnIndex + 1) currentRow[columnName] = (currentRow[columnName] || '') + data[i] break } @@ -51,7 +65,9 @@ class CSVHelper { const lastItemSize = Object.keys(result[result.length - 1]).length const sliceEnd = lastItemSize > 0 ? result.length : result.length - 1 - return result.slice(sliceStart, sliceEnd) + const trimWhitespace = R.mapObjIndexed(R.invoker(0, 'trim')) + + return result.slice(sliceStart, sliceEnd).map(trimWhitespace) } } diff --git a/server/library/database.js b/server/library/database.js index 514d12d72..10b2c1da9 100644 --- a/server/library/database.js +++ b/server/library/database.js @@ -3,7 +3,7 @@ const humps = require('humps') class Database { constructor (knex, idGenerator = ulid) { - this.knex = knex + this.knex = knex // debug: .on('query', q => console.log(q)) this.idGenerator = idGenerator } diff --git a/server/library/promisify.js b/server/library/promisify.js new file mode 100644 index 000000000..7eefda57d --- /dev/null +++ b/server/library/promisify.js @@ -0,0 +1,20 @@ +function promisify (fn) { + return function () { + const args = [].slice.call(arguments) + + return new Promise((resolve, reject) => { + args.push(function (err) { + if (err) { + return reject(err) + } + + const results = [].slice.call(arguments, 1) + resolve((results.length > 1) ? results : results[0]) + }) + + fn(...args) + }) + } +} + +module.exports = promisify diff --git a/server/middlewares/request-logger.js b/server/middlewares/request-logger.js index 23175df7c..cfffd80ca 100644 --- a/server/middlewares/request-logger.js +++ b/server/middlewares/request-logger.js @@ -1,6 +1,6 @@ module.exports = function requestLogger (log) { - return (async (ctx, next) => { + return async (ctx, next) => { log.info({method: ctx.method, url: ctx.url}, 'request') await next() - }) + } } diff --git a/server/models/employee.js b/server/models/employee.js index 99f7b2741..789e9f179 100644 --- a/server/models/employee.js +++ b/server/models/employee.js @@ -8,7 +8,7 @@ class Employee { } toObject () { - return R.pick(this, FIELDS) + return R.pick(FIELDS, this) } } diff --git a/server/models/expense.js b/server/models/expense.js index eb6ddca41..85553e022 100644 --- a/server/models/expense.js +++ b/server/models/expense.js @@ -11,7 +11,7 @@ class Expense { } toObject () { - return R.pick(this, FIELDS) + return R.pick(FIELDS, this) } } diff --git a/server/models/expense_category.js b/server/models/expense_category.js index 0b996d25c..53e23b8c2 100644 --- a/server/models/expense_category.js +++ b/server/models/expense_category.js @@ -8,7 +8,7 @@ class ExpenseCategory { } toObject () { - return R.pick(this, FIELDS) + return R.pick(FIELDS, this) } } diff --git a/server/repositories/taxes.js b/server/repositories/taxes.js index fa62cda61..055c0a3e7 100644 --- a/server/repositories/taxes.js +++ b/server/repositories/taxes.js @@ -29,7 +29,12 @@ class TaxesRepository { // (Returns a promise to be homogenous with how other repo work and // for future proofing) findByName (name) { - return new Promise((resolve) => resolve(this.findByNameSync(name))) + return Promise.resolve(this.findByNameSync(name)) + } + + // Finds a specific tax by id + findById (id) { + return Promise.resolve(TAXES[id] || null) } } diff --git a/server/services/import.js b/server/services/import.js index 21b54fcc0..5b8f9b80e 100644 --- a/server/services/import.js +++ b/server/services/import.js @@ -1,3 +1,4 @@ +const Expense = require('../models/expense') const Employee = require('../models/employee') const ExpenseCategory = require('../models/expense_category') @@ -18,7 +19,7 @@ class ImportService { 'date', 'category', 'employeeName', 'employeeAddress', 'description', 'amount', 'taxName' ] - const rawExpenses = this.csvHelper(columns, csvData) + const rawExpenses = this.csvHelper.parse(columns, csvData) // Now, all data is still strings, let cast those to the right type return rawExpenses.map((e) => { @@ -27,7 +28,7 @@ class ImportService { e.date = new Date(dateY, dateM, dateD) // Parse amount as float - e.amount = parseFloat(e.amount) + e.amount = parseFloat(e.amount) * 100 return e }) @@ -48,12 +49,12 @@ class ImportService { return expenses } - async importExpenseCategory (expenses) { - const findOrCreate = this.expenseCategoriesRepo.findOrCreate + async importExpenseCategories (expenses) { + const ecr = this.expenseCategoriesRepo for (let expense of expenses) { // Create employee - const category = await findOrCreate(new ExpenseCategory({ + const category = await ecr.findOrCreate(new ExpenseCategory({ name: expense.category })) @@ -65,21 +66,24 @@ class ImportService { async importFindTaxIds (expenses) { for (let expense of expenses) { // Create employee - const tax = await this.taxesRepo.findByName(new Employee()) + const tax = await this.taxesRepo.findByName(expense.taxName) expense.taxId = tax.id } } importCreateExpenses (expenses) { + const entitify = values => new Expense(values) const create = this.expensesRepo.create.bind(this.expensesRepo) - return Promise.all(expenses.map(create)) + return Promise.all(expenses.map(entitify).map(create)) } // Parses expense CSV and saves it's content to the database async import (csvData) { // Step 1: Parse CSV Data - const expenses = this.importCSV(csvData) + const expenses = this.importParseCSV(csvData) + + console.log(expenses) // Step 2: Extract employees and save those missing from the database await this.importEmployees(expenses) diff --git a/server/services/report.js b/server/services/report.js index bf73698d6..bcfdecee4 100644 --- a/server/services/report.js +++ b/server/services/report.js @@ -28,17 +28,18 @@ class ReportService { result.expenses = reduce((acc, v) => assoc(v.id, v, acc), {}, expenses) // Fetch related entities & save them on result - const relationsPromises = [] - relationsPromises.concat(expenses.map(async (e) => { + let relationsPromises = [] + + relationsPromises = relationsPromises.concat(expenses.map(async (e) => { const employee = await this.employeesRepo.findById(e.employeeId) result.employees[employee.id] = employee })) - relationsPromises.concat(expenses.map(async (e) => { + relationsPromises = relationsPromises.concat(expenses.map(async (e) => { const ecr = this.expenseCategoriesRepo const category = await ecr.findById(e.categoryId) result.expenseCategories[category.id] = category })) - relationsPromises.concat(expenses.map(async (e) => { + relationsPromises = relationsPromises.concat(expenses.map(async (e) => { const tax = await this.taxesRepo.findById(e.taxId) result.taxes[tax.id] = tax })) diff --git a/support/screenshot2.png b/support/screenshot2.png new file mode 100644 index 0000000000000000000000000000000000000000..c18295f34c31bd0ae6238706468fb70ca8b6fbf0 GIT binary patch literal 256400 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 z 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

unMksomM2di`iK%1%Z0nI3h*s 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 B%~tP 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, category, employee name, employee address, expense description, pre-tax amount, tax name, tax amount

- +
+ - + +
diff --git a/views/layout.hbs b/views/layout.hbs index 78b496899..5ab023df9 100644 --- a/views/layout.hbs +++ b/views/layout.hbs @@ -5,7 +5,7 @@ - Data Import | Wave + Expenses | Wave @@ -17,19 +17,20 @@ Wave
- -
-
-

- Data Import -

-
-
-
-
- -

- Step 1: Select data file -

- -

- The first step in the import process is selecting a CSV file containing expense data. - Once it's uploaded and saved in the database you'll be able to visualize your per-month - expense report. -

- -

- The file needs to include header line and include the following fields: - date, category, employee name, employee address, expense description, pre-tax amount, tax name, tax amount -

- - - - - -
-
-

- Data Import + Expenses

-
+
{{body}} diff --git a/views/report.hbs b/views/report.hbs new file mode 100644 index 000000000..6ee0f91f0 --- /dev/null +++ b/views/report.hbs @@ -0,0 +1,41 @@ +{{#months}} +

{{monthName}}, {{year}}

+ + + + + + + + + + + + + {{#expenses}} + + + + + + + + + {{/expenses}} + + + + + + + + + + + + + + + +
DescriptionCategoryEmployeeAmountTaxesTotal
{{description}}{{categoryName}}{{employeeName}}$ {{num amount}}$ {{num amountTax}}$ {{num amountTotal}}
Total Pre-Tax$ {{num totalPreTax}}
Total Tax$ {{num totalTax}}
Total$ {{num total}}
+{{/months}} From c4fc541ee37d2ab270cc07f44bf52dacad5051fb Mon Sep 17 00:00:00 2001 From: Frederic Gingras Date: Wed, 18 Jan 2017 22:42:56 -0500 Subject: [PATCH 20/27] meta: readme: write developing and testing sections --- Makefile | 4 +- README.md | 107 ++++++++++++++++++++++++++----------- tests/integration/.gitkeep | 0 tests/system/.gitkeep | 0 tests/system/import.js | 12 ----- yarn.lock | 20 +++---- 6 files changed, 87 insertions(+), 56 deletions(-) create mode 100644 tests/integration/.gitkeep create mode 100644 tests/system/.gitkeep delete mode 100644 tests/system/import.js diff --git a/Makefile b/Makefile index 61f4ea5c3..623363bbe 100644 --- a/Makefile +++ b/Makefile @@ -36,8 +36,8 @@ test: ## Run all tests including style checks test: lint test-unit test-integration test-system db-create: ## Creates a new database for the application to use (run once) - psql -c "CREATE IF NOT EXIST ROLE wave_challenge WITH SUPERUSER LOGIN PASSWORD 'wave_challenge'" - psql -c "CREATE IF NOT EXIST DATABASE wave_challenge WITH OWNER wave_challenge" + psql -c "CREATE ROLE wave_challenge WITH SUPERUSER LOGIN PASSWORD 'wave_challenge'" + psql -c "CREATE DATABASE wave_challenge WITH OWNER wave_challenge" db-wipe: ## Creates a new database for the application to use (run once) psql -d wave_challenge -c "DELETE FROM expenses; DELETE FROM expense_categories; DELETE FROM employees;" diff --git a/README.md b/README.md index 7671bc9fd..9220aa812 100644 --- a/README.md +++ b/README.md @@ -2,31 +2,19 @@ ## Intro -**Technology** - -While choosing a set of technologies for this challenge I had two goals in mind: - -1. Using languages, software, and operating systems I have used in the past so - that I can get to a working solution fast and best showcase my skills. -1. Still picking some new tools/libraries for 1-2 thing as this challenge is a - perfect opportunity to better myself and explore new things in a safe environment. - **Goals** The problem at hand is very simplistic but, can be interpreted in a myriad of -ways. Hence the problem here is now ticking the requirement but showing some -depth in the mastery of an aspect of web development you are comfortable with. +ways. Hence the issue at hand here is not merely filling in the requirements, but +showing mastery of a specific aspect of web development you are comfortable with. -A second goal should be thinking about the user, this is what Wave, and many -other great organizations do: start from the user. What is the user trying to -accomplish? How can we make it as easy as possible? How can we delight the -user? Often the answer is by doing your very best in each aspect Design / -Experience / User Interface / Performance / Stability / Iteration Speed / -Innovation. +A second goal should be showing that you have knowledge of more than just you core +competency, there are a lot of skills coming into successful web development and +a full-stack developer owes it to itself to know enough about frontend, UX, documentation, +testing, devops, systems, etc. to help out with those when needed. -Third, thinking of the onsite interview, how can we make sure this project -includes grounds for interesting discussions. How can we make it technically -interesting and easy to change/update/modify. +Third, thinking of the on-site interview, we could keep make sure some parts of the +codebase can act as good grounds for interesting discussions. ## Development @@ -44,17 +32,70 @@ interesting and easy to change/update/modify. - Operations - [Ubuntu](https://www.ubuntu.com/server) - _Easy to work with, wide adoption, package availability, most engineers have experience with it_ - [Runit](http://smarden.org/runit/) - _Simple in design, works well as process manager, include nice guarantees for our use case_ - - [Bash Scripts](https://www.gnu.org/software/bash/) - _Known by most developers, simple, easy to read and update_ - - (If this service was to be ran in production some more heavyweight configuration management tool would most likely be used to make sure deployment scales to multiple servers and happens in a "rolling" fashion. It would also be used to provision new machines. For this challenge we'll do those steps by hand (running bash scripts that is)) + - [Ansible](https://www.ansible.com/) - _Simpler than alternatives, Powerful syntax and plugin system, Agentless_ + +### Developing + +To start with, you will need to have the following installed on your machine _(the version numbers +don't need to be an exact match, it's just to give an idea)_: + +- **node.js** (v7.4.0) (install it using [n](https://github.com/tj/n)) +- **yarn** (v0.19.1) (install it using `npm i -g yarn`) +- **PostgreSQL** (v9.5.5) (install it using your package manager `brew`/`apt`) +- **Ansible** (v2.2.1.0) (install it using `pip install ansible`) + +If you have all these you are all setup! _(Make sure you can run the `psql` command before +continuing)_ + +Before we run the server, let's create a new database and run schema migrations against it: + +``` +$ make db-create +psql -c "CREATE ROLE wave_challenge WITH SUPERUSER LOGIN PASSWORD 'wave_challenge'" +CREATE ROLE +psql -c "CREATE DATABASE wave_challenge WITH OWNER wave_challenge" +CREATE DATABASE + +$ make db-migrate +./node_modules/.bin/knex migrate:latest +Batch 1 run: 3 migrations +/home/[...]/migrations/20170116182027_add_expense_categories_table.js +/home/[...]/migrations/20170116182035_add_employees_table.js +/home/[...]/migrations/20170116182042_add_expenses_table.js -### Building +``` -TODO Talk about dependencies and follow with building instructions. +Hokay! Let start that server and get cookin' + +``` +$ make +node --harmony server.js | ./node_modules/.bin/pino +[2020-12-25T08:00:25.252Z] INFO (17815 on kiasaki-w-vm): started listening on port 8000 +``` + +Let's visit [`http://localhost:8000`](http://localhost:8000/) and it out! ### Testing -TODO Discuss kinds of testing involved (unit, integration, system) and libraries used, touch on how -actually run these. +This application uses the [`tape`](https://github.com/substack/tape) test runner for Node.js and +has a few `make` targets that can run the test suite. + +This application has tests for parts of the actual codebase, that is, because: + +1. This was a coding challenge so I ended up not wanting to spend too much time setting up full + system level testing as it can be time consuming ^^, +1. Some things are worth testing all edge cases (like `server/helpers/csv.js`) others, not so much + (like `server/models/*`, at least as long as the are value objects and have no business logic) + +``` +$ make test # runs the linter + all test suites +$ make test-unit # runs unit tests +``` + +**Coding Style** + +This codebase adopts the JavaScript [standard](http://standardjs.com/), so, whatever that dictates +we follow. To run the code linter use **`make lint`**. ## Production @@ -93,15 +134,21 @@ case but can be automated with Ansible/Tower | Chef/Server | Puppet/Server. ### What I am proud of +### Screenshots + +| Page | Screenshot | +|:---:|:---:| +| Import | | +| Report | | + ### Other considerations - Employees addresses could have been further normalized - Taxes matching is a bit brittle, having only the state 2 letter code means we can match US tax names but would have trouble with other countries / different formats -- On the subject of taxes, assuming they change only yearly and that it's effective on Jan 1 is quite brittle, we migth come to mid-year tax changes, or simply later than exactly Jan 1. +- On the subject of taxes, assuming they change only yearly and that it's effective on Jan 1 is quite brittle, we might come to mid-year tax changes, or simply later than exactly Jan 1. - We are using a memory based cache implementation even in prod, it would be easy to set a Redis backed implementation in the container for the production use case but was overlooked for the sake of time -- Front-end production build is far from being optimal. Should really be static assets served from disk by Nginx, not by Node.js. ### Questions -- Is the only line in the example data, taxed in NY, using 7.5% not 8.875% an error? -- It's not clear as to whether we where supposed to assume the expenses and expense categories from a single file where linked to a specific client of just global. +- There is an expense in the example data, taxed in NY but using 7.5% not 8.875%. Is it an error? +- Where we supposed to think about segregating expenses per client or just leave them be global? diff --git a/tests/integration/.gitkeep b/tests/integration/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/tests/system/.gitkeep b/tests/system/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/tests/system/import.js b/tests/system/import.js deleted file mode 100644 index a6a6bc9d6..000000000 --- a/tests/system/import.js +++ /dev/null @@ -1,12 +0,0 @@ -var test = require('tape') - -test('timing test', function (t) { - t.plan(2) - - t.equal(typeof Date.now, 'function') - var start = Date.now() - - setTimeout(function () { - t.equal(Date.now() - start, 100) - }, 100) -}) diff --git a/yarn.lock b/yarn.lock index f982361eb..fc0182b6d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -228,7 +228,7 @@ bl@~1.1.2: dependencies: readable-stream "~2.0.5" -bluebird@^3.3.1, bluebird@^3.4.0, bluebird@^3.4.6: +bluebird@^3.3.1, bluebird@^3.4.6: version "3.4.7" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.4.7.tgz#f72d760be09b7f76d08ed8fae98b289a8d05fab3" @@ -1552,20 +1552,13 @@ koa-compose@^3.0.0: dependencies: any-promise "^1.1.0" -koa-convert@1.2, koa-convert@^1.2.0: +koa-convert@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/koa-convert/-/koa-convert-1.2.0.tgz#da40875df49de0539098d1700b50820cebcd21d0" dependencies: co "^4.6.0" koa-compose "^3.0.0" -koa-hbs@0.9: - version "0.9.0" - resolved "https://registry.yarnpkg.com/koa-hbs/-/koa-hbs-0.9.0.tgz#c8a2af2933a49acaa47a197e2c279f8b2ecdb76e" - dependencies: - glob "^7.0.5" - handlebars "^4.0.5" - koa-is-json@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/koa-is-json/-/koa-is-json-1.0.0.tgz#273c07edcdcb8df6a2c1ab7d59ee76491451ec14" @@ -1597,9 +1590,8 @@ koa-send@^3.3.0: "koa2-handlebars@https://github.com/kiasaki/koa-handlebars.git": version "1.0.8" - resolved "https://github.com/kiasaki/koa-handlebars.git#b68827ea16296484a578965d783968204ed86a25" + resolved "https://github.com/kiasaki/koa-handlebars.git#bd31d992b251f51da0b3d2bd1c17e21b01c61a12" dependencies: - bluebird "^3.4.0" debug "^2.2.0" handlebars "^4.0.5" lru-cache "^4.0.1" @@ -1867,10 +1859,14 @@ oauth-sign@~0.8.1: version "0.8.2" resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" -object-assign@4.1.0, object-assign@^4.0.1, object-assign@^4.1.0: +object-assign@4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.0.tgz#7a3b3d0e98063d43f4c03f2e8ae6cd51a86883a0" +object-assign@^4.0.1, object-assign@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + object-inspect@~1.2.1: version "1.2.1" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.2.1.tgz#3b62226eb8f6d441751c7d8f22a20ff80ac9dc3f" From bfe9be126e05540d12c0162c9f95c1e3b66a3ba5 Mon Sep 17 00:00:00 2001 From: Frederic Gingras Date: Thu, 19 Jan 2017 12:07:48 -0500 Subject: [PATCH 21/27] ops: provision: initial tasks and make targets --- .gitignore | 2 ++ Makefile | 13 ++++++++++ README.md | 19 ++++++++++++++ support/inventory.ini | 2 ++ support/provision.yml | 60 +++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 96 insertions(+) create mode 100644 support/inventory.ini create mode 100644 support/provision.yml diff --git a/.gitignore b/.gitignore index c2658d7d1..3b7622f43 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ node_modules/ +support/provision.retry +support/deploy.retry diff --git a/Makefile b/Makefile index 623363bbe..4798253fb 100644 --- a/Makefile +++ b/Makefile @@ -7,6 +7,8 @@ YARN := yarn TAPE := $(NODE) --harmony ./node_modules/.bin/tape TAPSPEC := tap-spec STANDARD := standard +ANSIBLE := ansible +ANSIBLEPLAYBOOK := ansible-playbook run: ## Start the application server node --harmony server.js | ./node_modules/.bin/pino @@ -53,3 +55,14 @@ db-rollback: ## Reverts the last migration # make db-create-migration NAME=add-users-table db-create-migration: ## Create a new migration file ./node_modules/.bin/knex migrate:make $(NAME) + +ops-ping: ## Runs the "ping" module against all host to test connectivity + $(ANSIBLE) all -u op -i support/inventory.ini -m ping + +# Ex: +# make ops-run CMD=uptime +ops-run: ## Run command against all hosts, provide a $CMD var to make + $(ANSIBLE) all -u op -i support/inventory.ini -a "$(CMD)" + +ops-provision: ## Runs provision command against a server + $(ANSIBLEPLAYBOOK) support/provision.yml -u op -i "$(IP)," diff --git a/README.md b/README.md index 9220aa812..ba7835706 100644 --- a/README.md +++ b/README.md @@ -112,6 +112,25 @@ software or Ansible/Chef/Puppet/SaltStack. Touch on database migrations. TODO Talk about host choice, server distro, `scripts/provision.sh`, touch on run manually in this case but can be automated with Ansible/Tower | Chef/Server | Puppet/Server. + +``` +#cloud-config +users: + - name: op + ssh-authorized-keys: + - ssh-rsa ... + sudo: ['ALL=(ALL) NOPASSWD:ALL'] + groups: sudo + shell: /bin/bash +packages: + - python +runcmd: + - sed -i -e '/^PermitRootLogin/s/^.*$/PermitRootLogin no/' /etc/ssh/sshd_config + - sed -i -e '/^PasswordAuthentication/s/^.*$/PasswordAuthentication no/' /etc/ssh/sshd_config + - sed -i -e '$aAllowUsers op' /etc/ssh/sshd_config + - service ssh restart +``` + ### Understanding day-to-day operations **Server** diff --git a/support/inventory.ini b/support/inventory.ini new file mode 100644 index 000000000..c37315a96 --- /dev/null +++ b/support/inventory.ini @@ -0,0 +1,2 @@ +[web] +wave-challenge-web1 ansible_host=159.203.3.214 diff --git a/support/provision.yml b/support/provision.yml new file mode 100644 index 000000000..140fd746a --- /dev/null +++ b/support/provision.yml @@ -0,0 +1,60 @@ +--- +- hosts: all + become: yes + become_method: sudo + vars: + root_password: "$6$rounds=656000$EqagmknlH0zM475c$OXgDbuJaa4XvojHjZO8ZoZC9emeWYSalOieF7d5ttCk/plnXUqPfU1KYDivsoUutODCayZM5vExxfcbUoK/jW1" + tasks: + - name: set root password for recovery + user: name=root password={{root_password}} + + - name: update apt + apt: update_cache=yes + - name: upgrade server + apt: upgrade=dist + + - name: install essential packages + apt: name={{item}} state=present + with_items: + - ufw + - fail2ban + - git + - vim + - mosh + - tmux + - curl + - htop + - gzip + - build-essential + + - name: firewall - enable + ufw: state=enabled policy=deny + - name: firewall - allow all outgoing traffic + ufw: policy=allow direction=outgoing + - name: firewall - allow incomming in port 22 + ufw: rule=allow direction=in port=22 + - name: firewall - allow incomming in port 80 + ufw: rule=allow direction=in port=80 + - name: firewall - allow incomming in port 443 + ufw: rule=allow direction=in port=443 + - name: firewall - allow mosh traffic + ufw: rule=allow proto=udp port=60000:60100 + + - name: nodejs - check existance + command: which node + register: node_present + ignore_errors: True + - name: nodejs - setup PPA 1 + get_url: url=https://deb.nodesource.com/setup_7.x dest=/tmp/setup7 + when: node_present|failed + - name: nodejs - setup PPA 2 + command: bash /tmp/setup7 + when: node_present|failed + - name: nodejs - setup PPA 3 + file: path=/tmp/setup7 state=absent + when: node_present|failed + - name: nodejs - install + apt: name=nodejs state=present + when: node_present|failed + - name: nodejs - install yarn + command: npm i -g yarn From 13c462069009bc31301bba2e5c50f60ae5462e97 Mon Sep 17 00:00:00 2001 From: Frederic Gingras Date: Thu, 19 Jan 2017 17:32:29 -0500 Subject: [PATCH 22/27] ops: provision: app/nginx/runit/config etc --- Makefile | 7 + README.md | 13 ++ support/nginx-site.conf | 47 +++++++ support/provision.yml | 100 +++++++++++++- support/vault.yml | 284 ++++++++++++++++++++++++++++++++++++++++ 5 files changed, 450 insertions(+), 1 deletion(-) create mode 100644 support/nginx-site.conf create mode 100644 support/vault.yml diff --git a/Makefile b/Makefile index 4798253fb..506ed65fd 100644 --- a/Makefile +++ b/Makefile @@ -56,6 +56,10 @@ db-rollback: ## Reverts the last migration db-create-migration: ## Create a new migration file ./node_modules/.bin/knex migrate:make $(NAME) + +ANSIBLE_VAULT_PASSWORD_FILE=${HOME}/wave-vault-pass.txt +export ANSIBLE_VAULT_PASSWORD_FILE + ops-ping: ## Runs the "ping" module against all host to test connectivity $(ANSIBLE) all -u op -i support/inventory.ini -m ping @@ -66,3 +70,6 @@ ops-run: ## Run command against all hosts, provide a $CMD var to make ops-provision: ## Runs provision command against a server $(ANSIBLEPLAYBOOK) support/provision.yml -u op -i "$(IP)," + +ops-vault-edit: + ansible-vault edit support/vault.yml diff --git a/README.md b/README.md index ba7835706..f9f4acc5b 100644 --- a/README.md +++ b/README.md @@ -149,10 +149,23 @@ runcmd: **Disaster recovery** +**SSL** + +The SSL certificate currently in use is stored in ansible's `vault.yml` file. + +If ever you need to generate a new self-signed certificate those two commands should come in handy: + +``` +$ openssl genrsa -out ssl.key 4096 +$ openssl req -new -x509 -key ssl.key -out ssl.crt -days 1095 -subj '/CN=' +``` + ## Footnotes ### What I am proud of + + ### Screenshots | Page | Screenshot | diff --git a/support/nginx-site.conf b/support/nginx-site.conf new file mode 100644 index 000000000..8399ab6ac --- /dev/null +++ b/support/nginx-site.conf @@ -0,0 +1,47 @@ +charset utf-8; +client_max_body_size 50M; + +server { + listen 80; + listen [::]:80 default_server ipv6only=on; + return 301 https://$host$request_uri; +} + +server { + listen 443; + server_name wave-challenge.kiasaki.com; + + add_header Strict-Transport-Security "max-age=31536000; includeSubdomains"; + + ssl on; + ssl_certificate /var/wave/challenge/ssl.crt; + ssl_certificate_key /var/wave/challenge/ssl.key; + ssl_session_timeout 5m; + ssl_protocols TLSv1 TLSv1.1 TLSv1.2; + ssl_prefer_server_ciphers on; + ssl_ciphers 'EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH'; + + location /static { + alias /var/wave/challenge/repo/static; + } + + error_page 502 /502.html; + error_page 503 /503.html; + error_page 504 /504.html; + location ~* ^/50[234].html { + # TODO actually have error pages in that folder + root /var/wave/challenge/error_pages; + internal; + } + + location / { + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Nginx-Proxy true; + proxy_pass http://localhost:8000/; + proxy_ssl_session_reuse off; + proxy_set_header Host $http_host; + proxy_cache_bypass $http_upgrade; + proxy_redirect off; + } +} diff --git a/support/provision.yml b/support/provision.yml index 140fd746a..a08eb37dd 100644 --- a/support/provision.yml +++ b/support/provision.yml @@ -2,17 +2,43 @@ - hosts: all become: yes become_method: sudo + vars_files: + - vault.yml vars: - root_password: "$6$rounds=656000$EqagmknlH0zM475c$OXgDbuJaa4XvojHjZO8ZoZC9emeWYSalOieF7d5ttCk/plnXUqPfU1KYDivsoUutODCayZM5vExxfcbUoK/jW1" + app_root: /var/wave/challenge + app_host: wave-challenge.kiasaki.com + service_run: | + #!/bin/bash + exec 2>&1 + set -o allexport + source /var/wave/challenge/config + set +o allexport + cd /var/wave/challenge/repo + exec chpst -u app node --harmony server.js + service_log: | + #!/bin/sh + exec chpst -u app svlogd -tt /var/log/wave-challenge tasks: + # Set a password for `root` user + # This password can't be used over SSH the way SSHD is configured, it's purely so we can + # still access the box using DigitalOcen's web console (in the event we lock ourselves out + # by misconfiguring the firewall) - name: set root password for recovery user: name=root password={{root_password}} + # Make sure the host is up to date - name: update apt apt: update_cache=yes - name: upgrade server apt: upgrade=dist + # Install some basic packages + # - ufw needs to be there, we configure it just under + # - fail2ban comes well configured out of the box + # - git is needed to clone the codebase's repo + # - vim, tmux, curl, htop, gzip are all useful when managing the host + # - mosh can come useful if administering the host over a flaky network + # - build-essential is needed to build native nodejs modules - name: install essential packages apt: name={{item}} state=present with_items: @@ -27,6 +53,7 @@ - gzip - build-essential + # Configure UFW letting only SSH, HTTP, HTTPS, and mosh over udp come in - name: firewall - enable ufw: state=enabled policy=deny - name: firewall - allow all outgoing traffic @@ -40,10 +67,13 @@ - name: firewall - allow mosh traffic ufw: rule=allow proto=udp port=60000:60100 + # Check if node is installed so we can skip the lengthy process of installing it - name: nodejs - check existance command: which node register: node_present ignore_errors: True + # Fetch and run the official node PPA setup script + # (not using shell and a pipe to apease ansible) - name: nodejs - setup PPA 1 get_url: url=https://deb.nodesource.com/setup_7.x dest=/tmp/setup7 when: node_present|failed @@ -53,8 +83,76 @@ - name: nodejs - setup PPA 3 file: path=/tmp/setup7 state=absent when: node_present|failed + # Install nodejs 7.x using apt - name: nodejs - install apt: name=nodejs state=present when: node_present|failed + + # Check if yarn exists so we can skip the length npm i call + - name: nodejs - check yarn existance + command: which yarn + register: yarn_present + ignore_errors: True + # Install yarn when missing - name: nodejs - install yarn command: npm i -g yarn + when: yarn_present|failed + + # Create a non-admin group and user than will own and run the app + - name: app - group + group: name=app state=present + - name: app - user + user: name=app group=app + - name: app - add operator to app group + user: name=op append=yes groups=app + - name: app - folder + file: name={{app_root}} state=directory mode=0775 owner=app group=app + + # Create a file containing all the env variable the application needs + - name: app - environment variables - file exists + file: name={{app_root}}/config state=touch mode=0775 owner=app group=app + - name: app - environment variables - PORT + lineinfile: name={{app_root}}/config line='PORT="8000"' + - name: app - environment variables - NODE_ENV + lineinfile: name={{app_root}}/config line='NODE_ENV="production"' + - name: app - environment variables - DATABASE_URL + lineinfile: name={{app_root}}/config line='DATABASE_URL="{{database_url}}"' + + - name: app - repo - clone + become_user: app + git: + repo: https://github.com/kiasaki/wave-challenge.git + dest: "{{app_root}}/repo" + - name: app - repo - permissions and owner + file: name={{app_root}}/repo state=directory owner=app group=app recurse=yes + - name: app - repo - dependencies + become_user: app + command: chdir={{app_root}}/repo yarn + + # Install nginx + - name: nginx - install + apt: name=nginx state=present + - name: nginx - copy ssl key + copy: content="{{ssl_key}}" dest={{app_root}}/ssl.key + - name: nginx - copy ssl crt + copy: content="{{ssl_crt}}" dest={{app_root}}/ssl.crt + - name: nginx - remove default site + file: path=/etc/nginx/sites-enabled/default state=absent + - name: nginx - copy site config + template: src=nginx-site.conf dest=/etc/nginx/sites-enabled/default owner=www-data group=www-data + - name: nginx - restart + service: name=nginx state=restarted + + # Install runit and copy our app's config + - name: runit - install + apt: name=runit state=present + - name: runit - log folder + file: path=/var/log/wave-challenge state=directory owner=app + - name: runit - app folder + file: path=/etc/service/wave-challenge/log state=directory + - name: runit - app config - run + copy: content="{{service_run}}" dest=/etc/service/wave-challenge/run mode=755 + - name: runit - app config - log + copy: content="{{service_log}}" dest=/etc/service/wave-challenge/log/run mode=755 + - name: runit - restart + service: name=runit state=restarted diff --git a/support/vault.yml b/support/vault.yml new file mode 100644 index 000000000..990da27be --- /dev/null +++ b/support/vault.yml @@ -0,0 +1,284 @@ +$ANSIBLE_VAULT;1.1;AES256 +62663332383962336138613737643234663235376436356565346430656632633337326164666532 +3263646162323633333764616362313331383434623635660a346563303633626534303435633135 +66346164333235353364363434313062343639666636373465366238306136336536393237653166 +3030653437653438660a636638383530326532306332316135306131323932396634306530343466 +66666632663662326239666439306166313638306663373131336535366462636134323962373239 +61353330393764643834363765303733346165646135323438396666343831653062646335656565 +62313265343639376362333761343137663662666135663662306335383035383266343564646164 +30653932656235323266356531323338626337363132386236666361366634626338323332366632 +37343866343461306632373833313437316562393633346662346566323864353661666138653139 +37353736663737383863663063316465336333613064326461623762333131386363633063373664 +37633965306134393634356261306566343363656336616132616632373235643266633930646432 +30613565363866353833653934376631316535643165373366356162373735613930396431356266 +65633864383665363534663933643639613263333132316437643563663132383335343632383036 +34313837646461323464336231373838313338393661366637616661646439326236363839636364 +35616135626464326432356362316363343833306234623665613838323661303165373739366337 +61396664336136373662616662623138396661613262373632353634343866323165393562323661 +39363365366338363831626365666266373338613361613961623465646661633933376639653636 +37643866333137643761396266663131633963323363383333306561656339646638623738393131 +30343064396136643961656539373431303031396163616230636365303261363939353438336537 +32316137333066386162383636316234653531326435646165393430383838363337363833373234 +39353334623965326131393335316633323461373064376265343334356166313139333638643031 +34666562333565333133386630303962393864663961383233636531653333383964656433396262 +33653434326339653234323465336237323231623539353161653433316364666365656636393437 +32303431653933646639663837346433323862306635646237663564336461323662616165663439 +37383336613034383334363032376331633965363736303535633662393131393236343736336266 +38626432346131666435643735313930326535663633313138336233633466393666633135313834 +66356430396137653864343464363565316637666536336664616665386663343435396136643037 +34306239666533386264613632303138643563643033663230623664306133626130303930383266 +35626435333536653534323237363966663861343866356466623038366165646462306435326439 +66383433303762393636636534306166343962653263373035616631303866393239633062363464 +35323632393536656565323338383134623933656263393032333237623263363834303235383636 +62366362636137663962653932346664636631313538333462376339623762616134646264396662 +66363162653362323830623938333066393539613932313034623863393261613966333330666338 +37323233353363373137353830613836626363623932646230346339356566636265393833333464 +31613937373062303334663234316433386235363238626432353066336162393536636131383364 +35353737363430626332333964373964663533386137396132363738643462323761353131373230 +38626638666361343430323532666562383261643563613730363665616663626465656239663032 +31313266323963653435383337306134386332316435616630616136366262303532386162633338 +64336235316566363930623630393734393539356330323665393132386134386664663162656133 +32333533343837373166626432653135306236663564656433373333363730656163393537313137 +31623239386231396665323437633464656263386536363733346261353637333839326365323632 +34616634313934636432336563306432653563343365393164333733333731336131323662353739 +39336666383561653938393061393361383039643034376665376165323336663462363333633630 +64613539303564373965653464326461643135326136366662306265616230643065373164386134 +35616162633938343264376234616364633664616631326362346230333237636566316235663037 +62313630616537353761346534613662393538356437616239646437383638383032353831616638 +30323937616238656430343763316565313061383635303539623337623131633530383234343338 +62623166626563333964626131346165383335303136313461623338356431646334313732306536 +38343235613130323030353565336231376631346131316363363831663061303737346530616432 +66336232656432366138643366646338656434613036313636623036386561643137656632636232 +61653733383838353766623738316135623338653932626266333161386532303166333531333936 +63656238643162623734353166623061303832653934363433663362333864303431666161313530 +64303663356661643366363138386561616138633931373438313138306561633139623034313761 +34666130623065353034336334653964643439396236366539333538363139333666613066663761 +63353632626334613264663834636133373939343661656436393764633037323334383366333236 +30306237623030363231653765353466643835396166333439656434326638343863616636636231 +64346463333636373130313066646339396535643531373764616337653931663134366434363730 +37613034646538633232643334383639386439343738356632333831386130383561316331663238 +35646336316561633835343235363431653134613330646430376262303564303230346137326264 +62323661306666353935383162656130303235393565653963663539633036653639623438313562 +38623230376630623937366265366664633063643666656534613239636363376565363266313461 +61633231393766383734366162353766616330353665306631313464303462396563326533316637 +34643666303336326134386538313763613634623062383339313337336237333939616432626434 +35323133646332363264386466303964643962373661663535613266633335376461336261333763 +38346561323831623565636461383662353135373066376438623264313430636235653536646238 +33303139313534613563386462623839633739313339646534666533646633636336303231313665 +65653934613032356235363839616331616161363233323865316664313763393964383136363263 +62386164363662366437613933393231306438303062313331343431366262383435366337663664 +62623033663036306331386634323566393237633966376562373734646432386437343335376336 +31343161373361343233386339326431633436653166613862626634656261323738623735633737 +61633335316435303666363365363031363434333037363865393036623366663431656530396637 +31643737643737636634353335303161353639323735383239353739303836643431383434643337 +33633366363434396637363038336633663735653665656135323433663237633663313666333631 +31336161393332376264343766643263653330626633366363356135363038376137666132656133 +61376232396162626661353834363939333565393933396361663239653136633337343565633066 +32646363656338653232626362666336666231356334376264613035363437613961353764383135 +61396164316235313363623063383761386335376630363563336532663665393936373761333565 +39393366393066336366373739336262376331353432376362363163356337316461386434663039 +37316239633631653336626661353663636437303565613439316139366533323735363336653039 +33646331373365396361356534316132393866346332643762386539633839343338613436656536 +31363765383161303232326537346436386639653538376230373163356532333633666634383632 +38613966656534383631393532383537343563313835346265653638363265313835636165303037 +66373866626338313236663737633433343939623638643538613033613634383534383438613633 +63396332653961626363316438313438303266646435303336323164326364613838393438313164 +35613838383764613430366433353462663265336435666132343439656538313731636436373536 +37623762666537343635333663653733346461383666623139646137353737383838343439336131 +64393332386134626163633162383364666262313865656564613139353830393038613963393365 +63346632393533363438353564353331386363323665663261653564613461366338366463646166 +38323536616164326634366530613034613063383636326431346563666162336566613831316434 +37376138343133336432343035333232653534343161383738363135626464303237633931323938 +33363065643665666330616366643231336139623761323561353338643661393161376638343566 +33393539313731383831376138393863366637323238666561323832663934646136663036636237 +65393738326165393833373161646362633539343638663432626662366137363761653332306434 +61666466323030343439383239636538316131386631626164646231353730653135396633623063 +63646136343866316434356564346132316136326530316662646266363766656432653132643338 +66313765366362303233346433333138316633313764356165346463343035616664313931333335 +66393433336466313938316235346133343363653030303061633830383932353333623637366338 +35396233366566663365336138633866383531653361353965393266343534356465326530356338 +64366261323264343262656330386232373464326565366365386262646466646139363862343830 +31376530333966393635383562663662383632303131306134343763366166303936623838326530 +63383465333163363431333464656137356139396662636534356463343931636166633835393739 +32373332653832373932633737663964646462373564626633616338373766333432613464613136 +34643336326666616331323765383965373334636234396566376561643466326236346562306630 +32353266306565383362663064373133373237366232396133646134353739326663333534646664 +38363963386131333335366134613165643939626666326436653937303031373961373064666634 +37306336326331643130326538333361623664623030303263623361353834303662396130396430 +32313734653566333036326636643431356635623962303233323232363961616338366231373964 +65393566663462663032326134313939303931303433366264653361643937396232306165396463 +37643963373037333365663135633766633435633833333137303264623266326635366334336131 +33666133626665383336343835623632313939653134663764306137393961623137626262346537 +37346139363537656232383236613064653063313233386130366462326438643835393066353762 +36323233323232616532326561313562343639616439616434316237386461323264386666626661 +30646231366139666263396362306136366434636663663664396161326662356639303732363632 +32316131396438386266666263383637363339656431633964373731316535396533323339336563 +38316531633434633164613430353539366439666562646564393834386436333264373764633066 +62396631623938356138633638373239376264373538646236396536383062323832396465343531 +37646530333932623737383033396136343062323135393931343264383936646532393734343537 +35626564353537386633383962373063356337663438313161303435363037393036383830396665 +31363764323038313161613035633965306533613632313433323939306133323431383732363963 +38653437666131383630643663393432393538623738623334356362623862396666343832636633 +34663566333565386534373137313361373266393965346565333437303764376234363939636462 +30663530616134373938653831326361643365326162303336393133663262643837363730316262 +66656364663939306332623461613934363466396135313365613861383937643932623463383236 +64316263303164663230356265623164323035396364393538326166313738306166396337623161 +32666639303632356439323830613532633265643762616133363338623264333234373834373066 +34316666383562353466313231323263653865353537626466666534363563663630626633613439 +65316434306530383338383064366533343332313030616337386266366365616362356466373566 +34343939333963656530336535366364366333366163633438393661376137356462623833623734 +63323962623965653561376661366634396639306638313832323836323836366630653332386335 +65323932653661383831393435373536653762333535303733353865663930343637656565353134 +35386162333035363436393839313234323133656539323731353332653763653565663733316436 +62363266326238373830623465316234626366373962326431386339636162623837376466653234 +33333466333439313737356164636563356462396333656330396436386338393535343930363664 +32356534376164663362613366333766333965613533373538656235336339366530373730623837 +36336531333838386132306538306262616534393165653666343639343763316631353965396361 +37313737643236633038333239643664346231303761323836326430356435393036346534393164 +66386561373331363839663162626630353433656237616365663865623363343063393432353865 +30373234613735343863343836623230343739306432656237363166353939616530343333636264 +30353437363965383161323966396266313666636436653038333161343466613435356662613735 +61666438643864386266386263636134663161633739383231613338656562303734356537363564 +65663965353336343431383161383936636131333162623366626237623234613964333864383862 +35626463396531643531666130656436373537646364323333356635366231646330343865396563 +35376437636565643462306163386465303832333663613739393834373039363739396436653066 +30623339353038323236656536363838313333336636373031633537336539323335636438363462 +33666438623562626565663266633139383039626135393636353332386335383131366364653135 +30643333383465313463323864346337386561383133353665653063393333313532376661393339 +36386535623037613831313436323937653630323264623437343934333331653564333163396533 +61313837623164633932363633653032313335666431393331386430393936616333666436313662 +35383663666238336631653466633734616262336366636234326530316333376566336238653335 +63396630383237356530653964653637323832323739373138323833633636353132323631363536 +37313433336463333536356164663966386230636635346137633663323231663165373739396134 +62323335636462646230346335376530346234396432393038346238623138346237333734666532 +66623436613831373733383466373061363332303162373638613434623266393239656434323430 +63383566663563613035373439363363393439356565303061323161363263653433636566353530 +30363366633565343137336364613239636336366266353764623461386533326337373435356638 +32363137386232653036613565333136356338643335313535663433343439656366613030303534 +61333330306664663930643931656464616164643032613230303661303231326435303863346166 +61323864626662356430353065346265633466313862333132323834323736646231326439633865 +31613531623937653738333363633664373163393163643538303539643764653630616634326237 +66366162663335313936646233363332626365366130313839333637323430633038633661396665 +30636234396163626630623632393463663761383066646461643562396364643832306462356632 +66393331363366613230633337666538663734623039616435376663343863306365366666356565 +32633937616635333962613261623034623461353133363966663036313632316132343361333663 +62343265653738356261316631363933323462326266333437653062396138666463326261363030 +36376565343863366665643536656530313435383661353165613334616339363930376236303333 +62333638663633353337666339653964393962393863353662656437646566353238613266343233 +33336262343735393134663433393863333637373361383031343734663334316433646463376138 +35383838343164376565366334623532356130353062313962346637636362626435383536303332 +30303839386362616461396138656439313131343136323161383639623832643363623965343632 +63353739643762343266313562666265373661383837313839656666383537366231643737353635 +62656563346437353332396265646431323663323737633132643836333862363064653835386630 +30636431333339376437666265353036356164643665383064316137353236613730373037366437 +35373362643461623039323239393161613166326534323362643632393237643333666237326435 +35353836383165323366646435383361636133663935316361623262313930316363643332323863 +36353861613166386232393133313833663063643634373966666564323834326338383864346365 +31326666663836636238383239636137366133326461613235373566623933326561666162336533 +65636530373366613761613832653935346666643930363563323465653461383137383439333837 +36373839333037656334656435656466363061353831363866656330616134653539613561663236 +30316466623961643763646266636565613564643165623232393330353530656262393330366362 +34626561653635613163663965373465376337666432376364393762373433343538356264613465 +30366533666231396533626465326638343363376166336565353030333933333739343666623135 +63643339333932353262396430376431333733336366353762366434306564656264366434316261 +66323030636431623237303036373033323233393961623133363266396566336539636533643063 +31313438646334363731336433303338323939343431643063373866633063616365633633666634 +62316130333862326662343162353061313639393437656235616363326230363165386436663462 +31393030386339336265306165613562313733656137313834353064623639616461623136306261 +62366435316263313335653463383031376439393838613061343433626430303634646365313030 +37373761323331623833303663393331393432643832616566663034376231376532343134343136 +65326431313861623238383631336361363062633461386234386337393836373038356232396239 +39326661643835316131326332633932336632373663373734643532343432336333386633303265 +32366363623365356531653637363264386562313466363834656461653563393066353734396139 +64616235356435666366313231313634343366383865316631363337326635656136643834363563 +36333830623632613634613162336530306437646134313638326662656663626366363439643064 +38366536643162393136656262396430313431623234356561333066373861363030653661616266 +66333638363535633137646431313966666530333963383834643536303432323662333863326631 +66366132313735353965326635663435333035636165326236386435623336633564636139383237 +38623461313963313765356232663331343939333236646638343336343832626466643338626131 +32343837666535346261623762396266303034666365373261666266366235336336323635613433 +61376366386163383735376330356138363337363263656363353562616631306639366566313362 +30613233346163383032376262336632666665323832373935636130626562366137613331613762 +35386336626132643137623833653838613733656131616336613136323535333130363637323962 +63653434336130303964373232646463353635313933383262396535653662633162663161356133 +63343833613138363362353236393038353364646537353539613930323666643863383266656636 +36323138323565353562643337356563363136666530383662663266393036356166666230643764 +37643366313635393330303330643164643537376462343538326164633566653830643331653764 +37333963323163366662353531366663613337613835313834646439633032656561373762643665 +32663235333337663133383061616430623931336234326532313861363162623865323366333563 +36633564666536616666653963323338386363366539663236666363313862656434396163666233 +32633531646231306165663966353434323738306534396639323035383030653566613031366132 +63353638623162326339363664616265363935386365336439356361626239383662343539326165 +64656534333665333064363865383965323861663032383138646638396566353631623039373030 +30363636383562303738353864313466653039383033623761303435316164326233366638653332 +32653036383033323233396134646164323035343130616264353534396261386438386434663335 +66303438336664383035343232643939323161643035666266663161623337316434666237666665 +33306633336637653937346462646261616165336239303866316437386530346432393163666239 +37376463393039346330366364376330616535376339663638663330323039326531393230353266 +37383933333332663832306239346663623033366530343363363865646137313432623337386131 +66336133396532383065386365353932663636386462616235636434646265636136313665336663 +65343863663262396439356366623732363038376234333536383633316566306161666163323865 +37623864663137343962363338383764636231316638303063303963666465613938666664623739 +39643739643362326239376566656533343534343163346232353039383138363231353730336637 +64633539396631323039346365666363316438616161326535376337613139313762336131653866 +64333462383230373461356265343263326137653438643936373331386338666337376432663366 +64326433613631383964396237376565353132363335383531323264353961616264303965663134 +34333564623563336530303630663834386231393636306662653536646266396465313162383531 +33363238616335393935313965366664366538306536336131313136346564323030306434326136 +35363430646135346636663732626332316638643336626538623830643237366132303932616532 +62346564313063656338373164653361393336303065313136376633653934356466373865303830 +63363139316265343434653137316638653964396561626539653161333033626432633364613635 +32613239646536353264653637616165356131666461326330643165346134626133376261356639 +64626662313961383662626464383538633735316265636435363932303365613735313031666336 +64373061313139646635643337376261326261376336316134643966323362343865666138336438 +62336537373333386531623032646336613935303138393234326635636661336232313538313732 +63663131666533386635386666666133633366346339373038343764303966383732623832356136 +36393964393530656236363434383430643834373735336130633163666166373935313230633633 +33326561313336616361633562636663616536326432356562636238636439656135616265613537 +39336533306230373162623436633039636335316331363661643166373465346466316165343037 +38306531663264326462643261316634323963656535383839343936653138346238333361353431 +66306464393764613535643765363538376631383530326135356564643531323666333536333966 +62396437323164313830336565333639653164363831633636353430366564326433333833383436 +36373134326261326138306164386233376265343739386530366461653364653231313663613337 +33373236343831386537373235656439373931323263653738306663306632333738323437666137 +38313638386132646331373362633336376433323631656130663562366438353266396561373732 +31383233356132653331333161346665653364383864623734373865333135346237303437666334 +65386139363835323466333961613864613530613532643532666565396366636439373439623338 +38303338313264303031633338393662356363376431316335336664353930626263633061613033 +61653264306531326662343962643565663861366239343961396239383962323734343931626333 +61393138623961356539636435306639616362643438386234356336373930313363363132373933 +63386533613433653331333664636231623232633963356263383932336261393430636130313933 +36396535343964376333623736396634373765383539653935326265646338383961343064653766 +32333038643866646363613364306461326265383330346633613230313939623165363337613664 +62643034396433656631323030383131346435653830333566643234363438303062666662653333 +33353731323736303965386563636536646333383662663430336536356337623130366433333463 +61613662663930366336393639646562666130303730386133306539303164303038363539376130 +36303864373361663066363630633434306530306166323030653232383530663262663938633434 +30346234666533326630633662633764373362623461653832636265303935373033646237663638 +61343932353033656163643437396134633032613038383331393761663661616166613931646661 +61623134623966646337623930316131386231613465666232383135626336306431663237303463 +37613161356366356433653938323036333332306230633934663663386137336465323430643263 +32313632306435373338373437643532646262376163343336663235376365646434633964656165 +34346436633462616136666134633738643564393031646666376631363939313336363739653630 +36306464353265376439316336373661323939633332613139646438316464633831333331626561 +33646133393866313565333733663539393466363337353537616138393066646332646362326235 +38616364383731343432613561366432353738343662356465313833303531336230623538306332 +32366165393034373934383133306632386264383032366238303566633466633666353335633038 +39393632313636373931663063306635393263346162323135303265376361303965323039626563 +65323161353338356239626635663838396238663366333663383366326336336635326337353463 +32623465656565633666366566313966303761346431323261326134356537356131353133626330 +63353931303664613238366230373133323735653936333961303931383839663966663138386563 +62643533323837343834386563353731366463373362616561646239643933326162643937623264 +32326539643439613066633131663934656134303130313766623230336362306364643363666466 +37333931373065393538343839323233373438383930383937616531633263333539663664663339 +65366638663037306133353137643561643661636635623639353965306533333833663237336437 +37346534386161366561303833323738303832326532336465623031306164633561316561333039 +31353161373838376339383932306265323865626432613239373334623465656539366331306430 +66376130663630306337636263656239393638653632333261333362613939623032313133653730 +63633631643365383565643630653966653263386663613835666463376138646333333764636636 +30323966376435313266613037616664353432383966313339633733333134353865326131336536 +63313235393935616539303434373562343335653331323235636639306162303132393434376563 +63643332333566343961636335666264373763383332656234313962323966636131343434353837 +61363262306261333538323865343136336364343137373437366362626634376634636333333239 +61393362633964633634653131356533353561613866363361663136633866336133613632376138 +326465313839393338653864336264653263 From 565f12156de3569ec09afe4ed92db4af6858368f Mon Sep 17 00:00:00 2001 From: Frederic Gingras Date: Thu, 19 Jan 2017 17:34:18 -0500 Subject: [PATCH 23/27] service: don't force https now that nginx takes care of it --- server.js | 1 - server/middlewares/force-https.js | 6 ------ 2 files changed, 7 deletions(-) delete mode 100644 server/middlewares/force-https.js diff --git a/server.js b/server.js index f170ead1e..7960de2e1 100644 --- a/server.js +++ b/server.js @@ -46,7 +46,6 @@ app.use(require('koa2-handlebars')({ helpers: {num: (n) => (n / 100).toFixed(2)} })) app.use(require('koa-static')('static', staticPath)) // Serve static files -app.use(require('./server/middlewares/force-https')) // Force HTTPS in prod app.use(require('./server/middlewares/request-logger')(log)) // Log requests app.use(router.routes()) // Router app.use(router.allowedMethods()) // Unhandled method router middleware diff --git a/server/middlewares/force-https.js b/server/middlewares/force-https.js deleted file mode 100644 index 3a8017ae0..000000000 --- a/server/middlewares/force-https.js +++ /dev/null @@ -1,6 +0,0 @@ -module.exports = async function forceHTTPS (ctx, next) { - if (!ctx.secure && process.env.NODE_ENV === 'production') { - return ctx.redirect('https://' + ctx.host) - } - await next() -} From b8903cad3929cac2c648fbd64d27f213580a489a Mon Sep 17 00:00:00 2001 From: Frederic Date: Thu, 19 Jan 2017 18:24:34 -0500 Subject: [PATCH 24/27] meta: readme: document deploying --- README.md | 69 +++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 52 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index f9f4acc5b..b631cd907 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,10 @@ # Wave Software Development Challenge -## Intro - -**Goals** +## Goals The problem at hand is very simplistic but, can be interpreted in a myriad of ways. Hence the issue at hand here is not merely filling in the requirements, but -showing mastery of a specific aspect of web development you are comfortable with. +showing skill in specific aspects of web development you are comfortable with. A second goal should be showing that you have knowledge of more than just you core competency, there are a lot of skills coming into successful web development and @@ -44,12 +42,12 @@ don't need to be an exact match, it's just to give an idea)_: - **PostgreSQL** (v9.5.5) (install it using your package manager `brew`/`apt`) - **Ansible** (v2.2.1.0) (install it using `pip install ansible`) -If you have all these you are all setup! _(Make sure you can run the `psql` command before -continuing)_ +If you have all these you are all setup! _(Make sure you can run the `psql` command without errors +before continuing)_ Before we run the server, let's create a new database and run schema migrations against it: -``` +```sh $ make db-create psql -c "CREATE ROLE wave_challenge WITH SUPERUSER LOGIN PASSWORD 'wave_challenge'" CREATE ROLE @@ -62,18 +60,17 @@ Batch 1 run: 3 migrations /home/[...]/migrations/20170116182027_add_expense_categories_table.js /home/[...]/migrations/20170116182035_add_employees_table.js /home/[...]/migrations/20170116182042_add_expenses_table.js - ``` -Hokay! Let start that server and get cookin' +Hokay! Let's start that server and get cookin' -``` +```sh $ make node --harmony server.js | ./node_modules/.bin/pino [2020-12-25T08:00:25.252Z] INFO (17815 on kiasaki-w-vm): started listening on port 8000 ``` -Let's visit [`http://localhost:8000`](http://localhost:8000/) and it out! +We can now visit [`http://localhost:8000`](http://localhost:8000/) and try it out! ### Testing @@ -87,7 +84,7 @@ This application has tests for parts of the actual codebase, that is, because: 1. Some things are worth testing all edge cases (like `server/helpers/csv.js`) others, not so much (like `server/models/*`, at least as long as the are value objects and have no business logic) -``` +```sh $ make test # runs the linter + all test suites $ make test-unit # runs unit tests ``` @@ -99,20 +96,58 @@ we follow. To run the code linter use **`make lint`**. ## Production -TODO Overview of what's discussed in this section and how some subject where simplified for the -exercise but could be expanded upon. Note lack of Nginx but obvious need for it. +Like hinted in the tech stack section, this app is deployed on **Ubuntu**, using **Ansible**. For the time being +some aspects of a production deployment where ommited for the sake of time but most decisions where +made keeping in mind scaling this project to more servers, sitting behind a load balancer, or using an +in house database setup instead of a third party. ### Deploying changes -TODO Talk about `scripts/deploy.sh` and it could be scaled/automated in production using some custom -software or Ansible/Chef/Puppet/SaltStack. Touch on database migrations. +Deploying changes is such a critical part the process of developing a product that it deserves a quality, +non-flaky and simple to use solution. Ideally you have deploys happening automatically as tests pass in +CI on the master branch. + +For this application deploys are made using an ansible playbook. + +There is 2 requirements to be able to run it: + +- Have a `~/wave-vault-pass.txt` file containing the Ansible Vault password +- Have the SSH private key used for deployment in you key agent (`ssh-add ~/.ssh/wave`) + +To deploy the latest commit from master use the following: + +``` +$ make ops-deploy +ansible-playbook support/deploy.yml -u op -i support/inventory.ini + +PLAY [web] ********************************************************************* + +TASK [setup] ******************************************************************* +ok: [wave-challenge-web1] + +TASK [app - fetch lastest commits] ********************************************* +ok: [wave-challenge-web1] + +TASK [app - update dependencies] *********************************************** +changed: [wave-challenge-web1] + +TASK [app - run migrations] **************************************************** +changed: [wave-challenge-web1] + +TASK [app - restart] *********************************************************** +changed: [wave-challenge-web1] + +PLAY RECAP ********************************************************************* +wave-challenge-web1 : ok=5 changed=3 unreachable=0 failed=0 +``` + +That's it! ### Provisioning new servers TODO Talk about host choice, server distro, `scripts/provision.sh`, touch on run manually in this case but can be automated with Ansible/Tower | Chef/Server | Puppet/Server. - ``` #cloud-config users: From 07aeae29a25bff237e8ed5162412b59b0e5fe6b7 Mon Sep 17 00:00:00 2001 From: Frederic Date: Thu, 19 Jan 2017 19:19:25 -0500 Subject: [PATCH 25/27] meta: readme: done --- README.md | 128 ++++++++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 111 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index b631cd907..25912e677 100644 --- a/README.md +++ b/README.md @@ -145,45 +145,130 @@ That's it! ### Provisioning new servers -TODO Talk about host choice, server distro, `scripts/provision.sh`, touch on run manually in this -case but can be automated with Ansible/Tower | Chef/Server | Puppet/Server. +Right now servers are hosted on **Digital Ocean**, to provision a new server you can navigate +to the web page for creating a new one and fill in the following: + +- **Distribution**: Ubuntu 16.04.1 x64 +- **Size**: 1GB/1CPU +- **Region**: Toronto 1 +- **User data**: + ``` + #cloud-config + users: + - name: op + ssh-authorized-keys: + - ssh-rsa ... + sudo: ['ALL=(ALL) NOPASSWD:ALL'] + groups: sudo + shell: /bin/bash + packages: + - python + runcmd: + - sed -i -e '/^PermitRootLogin/s/^.*$/PermitRootLogin no/' /etc/ssh/sshd_config + - sed -i -e '/^PasswordAuthentication/s/^.*$/PasswordAuthentication no/' /etc/ssh/sshd_config + - sed -i -e '$aAllowUsers op' /etc/ssh/sshd_config + - service ssh restart + ``` +- **SSH Key**: Wave +- **Hostname**: wave-challenge-web0 (where 0 is the number that follows the last host created) + +Now that we have a fresh host with an operator user configured, let's run an ansible playbook against it +to install all the required software and dependencies for our app to run. ``` -#cloud-config -users: - - name: op - ssh-authorized-keys: - - ssh-rsa ... - sudo: ['ALL=(ALL) NOPASSWD:ALL'] - groups: sudo - shell: /bin/bash -packages: - - python -runcmd: - - sed -i -e '/^PermitRootLogin/s/^.*$/PermitRootLogin no/' /etc/ssh/sshd_config - - sed -i -e '/^PasswordAuthentication/s/^.*$/PasswordAuthentication no/' /etc/ssh/sshd_config - - sed -i -e '$aAllowUsers op' /etc/ssh/sshd_config - - service ssh restart +$ make ops-provision IP="" ``` +If that completes sucessfully the server is ready to be deployed against and put in rotation under the load balancer +(there is no load balancer yet, but you would have one in a production scenario) + ### Understanding day-to-day operations **Server** +The servers are currently hosted on DigitalOcean and have Ubuntu 16.04 installed on them. + +Access is possible over SSH as the user `op` (for operator), only public key authentication +is enabled. sshd listens on the default port, 22. + +If ever you have a problem accessing a host, it's possible to troubleshoot the issue using +the web console and logging in as root using a password, ask a collegue for it ;) + **Application process** +The two processes we really want to keep running at all times are nginx and our node.js app. + +Nginx is started by systemd at boot time and runs as a daemon so it's very rare it's parent proccess exits. + +On the other hand our Node.js app is a bit more brittle, that's why **runit** is installed and started at boot +time to watch on our app. It's default behavious is to restart the app anytime it stop, forever. Which is nice +is it doesn't make you worried the process would stop restarting after few failures due to external factor +(and then requrire manual intervention). The scripts that configure this runit service are located in the +default directory: `/etc/service`. + **Database** +The production PostgreSQL database is currently hosted on Compose.io, so it's that less to worry about. +If any incidents happen of we need to scale it, the compose.io website has ways of restoring backups or +agmenting ressources/capacity. + **Logging** +Centralized logging would be a needed addition for production but for the moment the interesting logs are: + +- Node.js App - `/var/log/wave-challenge/current` +- Nginx - `/var/log/nginx/{access,error}.log` +- Fail2Ban - `/var/log/fail2ban.log` + **Performance monitoring** +Nothing is istalled yet but I've seen DataDog and collectd fill in that role pretty well. + **User monitoring** +On the backend something like StatHat, DataDog or StatD (and a backing store for it, e.g. InfluxDB) +seem like clear winners. + +On the frontend: Mixpanel is what I have experience with. Paired with Google Analytics or Gaug.es for +visitor statistics. + +**Error Reporting** + +Setting up one of the following great options would save a lot of debugging time: Sentry, Raygun, Bugsnag, or Opbeat + **Security** +Here's what has been done, there is space for improvment but it's the basics: + +- Upgrade servers periodically +- Fail2ban installed +- Firewall configured to only let needed traffic in (22, 80, 443) +- Password based SSH authentication disabled +- Root login over SSH disabled +- Application running as non-priviledged user +- No secrets as plain-text in source code +- Deploys only possible to developers that have the server's ssh key +- HTTPS forced on all request +- SQL injection more than unlikely the way database access works + +A few more items related to authentication are not on the list as there is no authentication implemented +for the app at the moment. + +CSRF is also missing :/ + **Disaster recovery** +If ever something really bad happen, the servers are stateless and disposable. The one really important +piece of state is the database, and it being handled by a third party with automated backups is reassuring. + +If you where to rebuild a server fleet the process would be similar to provisionning a new server, expect, +it would be possible to provision all servers at once by passing in a list of IPs to `make ops-provision`. + +Once the `support/inventory.ini` updated with new IPs we should be good to attempt a **deploy**. + +The CDN records point to a floating IP address in Digital Ocean, so, updating the droplet that IP point to +would be required (but it would have saved us from needing to update DNS and wait for propagation). + **SSL** The SSL certificate currently in use is stored in ansible's `vault.yml` file. @@ -199,7 +284,16 @@ $ openssl req -new -x509 -key ssl.key -out ssl.crt -days 1095 -subj '/CN= Date: Thu, 19 Jan 2017 19:19:52 -0500 Subject: [PATCH 26/27] ops: deploy --- Makefile | 8 +- support/deploy.yml | 37 +++ support/provision.yml | 4 +- support/vault.yml | 562 +++++++++++++++++++++--------------------- 4 files changed, 325 insertions(+), 286 deletions(-) create mode 100644 support/deploy.yml diff --git a/Makefile b/Makefile index 506ed65fd..266dc9381 100644 --- a/Makefile +++ b/Makefile @@ -8,6 +8,7 @@ TAPE := $(NODE) --harmony ./node_modules/.bin/tape TAPSPEC := tap-spec STANDARD := standard ANSIBLE := ansible +ANSIBLEVAULT := ansible-vault ANSIBLEPLAYBOOK := ansible-playbook run: ## Start the application server @@ -71,5 +72,8 @@ ops-run: ## Run command against all hosts, provide a $CMD var to make ops-provision: ## Runs provision command against a server $(ANSIBLEPLAYBOOK) support/provision.yml -u op -i "$(IP)," -ops-vault-edit: - ansible-vault edit support/vault.yml +ops-deploy: ## Deploys the application from the repo's master branch + $(ANSIBLEPLAYBOOK) support/deploy.yml -u op -i support/inventory.ini + +ops-vault-edit: ## Opens ansible's vault for editing + $(ANSIBLEVAULT) edit support/vault.yml diff --git a/support/deploy.yml b/support/deploy.yml new file mode 100644 index 000000000..7df948762 --- /dev/null +++ b/support/deploy.yml @@ -0,0 +1,37 @@ +--- +- hosts: web + become: yes + become_method: sudo + vars_files: + - vault.yml + vars: + git_url: https://github.com/kiasaki/wave-challenge.git + git_branch: master + app_root: /var/wave/challenge + tasks: + # Fetch the latest commits + - name: app - fetch lastest commits + become_user: app + git: + repo: "{{git_url}}" + dest: "{{app_root}}/repo" + accept_hostkey: yes + update: yes + version: "{{git_branch}}" + + # Update node modules + - name: app - update dependencies + become_user: app + command: chdir={{app_root}}/repo yarn + + # Run migrations + - name: app - run migrations + become_user: app + shell: | + cd {{app_root}}/repo && + eval $(cat ../config | awk '{print "export " $0}') && + make db-migrate + + # Restart app + - name: app - restart + command: sv restart wave-challenge diff --git a/support/provision.yml b/support/provision.yml index a08eb37dd..3778dee5e 100644 --- a/support/provision.yml +++ b/support/provision.yml @@ -5,6 +5,7 @@ vars_files: - vault.yml vars: + git_url: https://github.com/kiasaki/wave-challenge.git app_root: /var/wave/challenge app_host: wave-challenge.kiasaki.com service_run: | @@ -121,8 +122,9 @@ - name: app - repo - clone become_user: app git: - repo: https://github.com/kiasaki/wave-challenge.git + repo: "{{git_url}}" dest: "{{app_root}}/repo" + accept_hostkey: yes - name: app - repo - permissions and owner file: name={{app_root}}/repo state=directory owner=app group=app recurse=yes - name: app - repo - dependencies diff --git a/support/vault.yml b/support/vault.yml index 990da27be..c6d3d7ec6 100644 --- a/support/vault.yml +++ b/support/vault.yml @@ -1,284 +1,280 @@ $ANSIBLE_VAULT;1.1;AES256 -62663332383962336138613737643234663235376436356565346430656632633337326164666532 -3263646162323633333764616362313331383434623635660a346563303633626534303435633135 -66346164333235353364363434313062343639666636373465366238306136336536393237653166 -3030653437653438660a636638383530326532306332316135306131323932396634306530343466 -66666632663662326239666439306166313638306663373131336535366462636134323962373239 -61353330393764643834363765303733346165646135323438396666343831653062646335656565 -62313265343639376362333761343137663662666135663662306335383035383266343564646164 -30653932656235323266356531323338626337363132386236666361366634626338323332366632 -37343866343461306632373833313437316562393633346662346566323864353661666138653139 -37353736663737383863663063316465336333613064326461623762333131386363633063373664 -37633965306134393634356261306566343363656336616132616632373235643266633930646432 -30613565363866353833653934376631316535643165373366356162373735613930396431356266 -65633864383665363534663933643639613263333132316437643563663132383335343632383036 -34313837646461323464336231373838313338393661366637616661646439326236363839636364 -35616135626464326432356362316363343833306234623665613838323661303165373739366337 -61396664336136373662616662623138396661613262373632353634343866323165393562323661 -39363365366338363831626365666266373338613361613961623465646661633933376639653636 -37643866333137643761396266663131633963323363383333306561656339646638623738393131 -30343064396136643961656539373431303031396163616230636365303261363939353438336537 -32316137333066386162383636316234653531326435646165393430383838363337363833373234 -39353334623965326131393335316633323461373064376265343334356166313139333638643031 -34666562333565333133386630303962393864663961383233636531653333383964656433396262 -33653434326339653234323465336237323231623539353161653433316364666365656636393437 -32303431653933646639663837346433323862306635646237663564336461323662616165663439 -37383336613034383334363032376331633965363736303535633662393131393236343736336266 -38626432346131666435643735313930326535663633313138336233633466393666633135313834 -66356430396137653864343464363565316637666536336664616665386663343435396136643037 -34306239666533386264613632303138643563643033663230623664306133626130303930383266 -35626435333536653534323237363966663861343866356466623038366165646462306435326439 -66383433303762393636636534306166343962653263373035616631303866393239633062363464 -35323632393536656565323338383134623933656263393032333237623263363834303235383636 -62366362636137663962653932346664636631313538333462376339623762616134646264396662 -66363162653362323830623938333066393539613932313034623863393261613966333330666338 -37323233353363373137353830613836626363623932646230346339356566636265393833333464 -31613937373062303334663234316433386235363238626432353066336162393536636131383364 -35353737363430626332333964373964663533386137396132363738643462323761353131373230 -38626638666361343430323532666562383261643563613730363665616663626465656239663032 -31313266323963653435383337306134386332316435616630616136366262303532386162633338 -64336235316566363930623630393734393539356330323665393132386134386664663162656133 -32333533343837373166626432653135306236663564656433373333363730656163393537313137 -31623239386231396665323437633464656263386536363733346261353637333839326365323632 -34616634313934636432336563306432653563343365393164333733333731336131323662353739 -39336666383561653938393061393361383039643034376665376165323336663462363333633630 -64613539303564373965653464326461643135326136366662306265616230643065373164386134 -35616162633938343264376234616364633664616631326362346230333237636566316235663037 -62313630616537353761346534613662393538356437616239646437383638383032353831616638 -30323937616238656430343763316565313061383635303539623337623131633530383234343338 -62623166626563333964626131346165383335303136313461623338356431646334313732306536 -38343235613130323030353565336231376631346131316363363831663061303737346530616432 -66336232656432366138643366646338656434613036313636623036386561643137656632636232 -61653733383838353766623738316135623338653932626266333161386532303166333531333936 -63656238643162623734353166623061303832653934363433663362333864303431666161313530 -64303663356661643366363138386561616138633931373438313138306561633139623034313761 -34666130623065353034336334653964643439396236366539333538363139333666613066663761 -63353632626334613264663834636133373939343661656436393764633037323334383366333236 -30306237623030363231653765353466643835396166333439656434326638343863616636636231 -64346463333636373130313066646339396535643531373764616337653931663134366434363730 -37613034646538633232643334383639386439343738356632333831386130383561316331663238 -35646336316561633835343235363431653134613330646430376262303564303230346137326264 -62323661306666353935383162656130303235393565653963663539633036653639623438313562 -38623230376630623937366265366664633063643666656534613239636363376565363266313461 -61633231393766383734366162353766616330353665306631313464303462396563326533316637 -34643666303336326134386538313763613634623062383339313337336237333939616432626434 -35323133646332363264386466303964643962373661663535613266633335376461336261333763 -38346561323831623565636461383662353135373066376438623264313430636235653536646238 -33303139313534613563386462623839633739313339646534666533646633636336303231313665 -65653934613032356235363839616331616161363233323865316664313763393964383136363263 -62386164363662366437613933393231306438303062313331343431366262383435366337663664 -62623033663036306331386634323566393237633966376562373734646432386437343335376336 -31343161373361343233386339326431633436653166613862626634656261323738623735633737 -61633335316435303666363365363031363434333037363865393036623366663431656530396637 -31643737643737636634353335303161353639323735383239353739303836643431383434643337 -33633366363434396637363038336633663735653665656135323433663237633663313666333631 -31336161393332376264343766643263653330626633366363356135363038376137666132656133 -61376232396162626661353834363939333565393933396361663239653136633337343565633066 -32646363656338653232626362666336666231356334376264613035363437613961353764383135 -61396164316235313363623063383761386335376630363563336532663665393936373761333565 -39393366393066336366373739336262376331353432376362363163356337316461386434663039 -37316239633631653336626661353663636437303565613439316139366533323735363336653039 -33646331373365396361356534316132393866346332643762386539633839343338613436656536 -31363765383161303232326537346436386639653538376230373163356532333633666634383632 -38613966656534383631393532383537343563313835346265653638363265313835636165303037 -66373866626338313236663737633433343939623638643538613033613634383534383438613633 -63396332653961626363316438313438303266646435303336323164326364613838393438313164 -35613838383764613430366433353462663265336435666132343439656538313731636436373536 -37623762666537343635333663653733346461383666623139646137353737383838343439336131 -64393332386134626163633162383364666262313865656564613139353830393038613963393365 -63346632393533363438353564353331386363323665663261653564613461366338366463646166 -38323536616164326634366530613034613063383636326431346563666162336566613831316434 -37376138343133336432343035333232653534343161383738363135626464303237633931323938 -33363065643665666330616366643231336139623761323561353338643661393161376638343566 -33393539313731383831376138393863366637323238666561323832663934646136663036636237 -65393738326165393833373161646362633539343638663432626662366137363761653332306434 -61666466323030343439383239636538316131386631626164646231353730653135396633623063 -63646136343866316434356564346132316136326530316662646266363766656432653132643338 -66313765366362303233346433333138316633313764356165346463343035616664313931333335 -66393433336466313938316235346133343363653030303061633830383932353333623637366338 -35396233366566663365336138633866383531653361353965393266343534356465326530356338 -64366261323264343262656330386232373464326565366365386262646466646139363862343830 -31376530333966393635383562663662383632303131306134343763366166303936623838326530 -63383465333163363431333464656137356139396662636534356463343931636166633835393739 -32373332653832373932633737663964646462373564626633616338373766333432613464613136 -34643336326666616331323765383965373334636234396566376561643466326236346562306630 -32353266306565383362663064373133373237366232396133646134353739326663333534646664 -38363963386131333335366134613165643939626666326436653937303031373961373064666634 -37306336326331643130326538333361623664623030303263623361353834303662396130396430 -32313734653566333036326636643431356635623962303233323232363961616338366231373964 -65393566663462663032326134313939303931303433366264653361643937396232306165396463 -37643963373037333365663135633766633435633833333137303264623266326635366334336131 -33666133626665383336343835623632313939653134663764306137393961623137626262346537 -37346139363537656232383236613064653063313233386130366462326438643835393066353762 -36323233323232616532326561313562343639616439616434316237386461323264386666626661 -30646231366139666263396362306136366434636663663664396161326662356639303732363632 -32316131396438386266666263383637363339656431633964373731316535396533323339336563 -38316531633434633164613430353539366439666562646564393834386436333264373764633066 -62396631623938356138633638373239376264373538646236396536383062323832396465343531 -37646530333932623737383033396136343062323135393931343264383936646532393734343537 -35626564353537386633383962373063356337663438313161303435363037393036383830396665 -31363764323038313161613035633965306533613632313433323939306133323431383732363963 -38653437666131383630643663393432393538623738623334356362623862396666343832636633 -34663566333565386534373137313361373266393965346565333437303764376234363939636462 -30663530616134373938653831326361643365326162303336393133663262643837363730316262 -66656364663939306332623461613934363466396135313365613861383937643932623463383236 -64316263303164663230356265623164323035396364393538326166313738306166396337623161 -32666639303632356439323830613532633265643762616133363338623264333234373834373066 -34316666383562353466313231323263653865353537626466666534363563663630626633613439 -65316434306530383338383064366533343332313030616337386266366365616362356466373566 -34343939333963656530336535366364366333366163633438393661376137356462623833623734 -63323962623965653561376661366634396639306638313832323836323836366630653332386335 -65323932653661383831393435373536653762333535303733353865663930343637656565353134 -35386162333035363436393839313234323133656539323731353332653763653565663733316436 -62363266326238373830623465316234626366373962326431386339636162623837376466653234 -33333466333439313737356164636563356462396333656330396436386338393535343930363664 -32356534376164663362613366333766333965613533373538656235336339366530373730623837 -36336531333838386132306538306262616534393165653666343639343763316631353965396361 -37313737643236633038333239643664346231303761323836326430356435393036346534393164 -66386561373331363839663162626630353433656237616365663865623363343063393432353865 -30373234613735343863343836623230343739306432656237363166353939616530343333636264 -30353437363965383161323966396266313666636436653038333161343466613435356662613735 -61666438643864386266386263636134663161633739383231613338656562303734356537363564 -65663965353336343431383161383936636131333162623366626237623234613964333864383862 -35626463396531643531666130656436373537646364323333356635366231646330343865396563 -35376437636565643462306163386465303832333663613739393834373039363739396436653066 -30623339353038323236656536363838313333336636373031633537336539323335636438363462 -33666438623562626565663266633139383039626135393636353332386335383131366364653135 -30643333383465313463323864346337386561383133353665653063393333313532376661393339 -36386535623037613831313436323937653630323264623437343934333331653564333163396533 -61313837623164633932363633653032313335666431393331386430393936616333666436313662 -35383663666238336631653466633734616262336366636234326530316333376566336238653335 -63396630383237356530653964653637323832323739373138323833633636353132323631363536 -37313433336463333536356164663966386230636635346137633663323231663165373739396134 -62323335636462646230346335376530346234396432393038346238623138346237333734666532 -66623436613831373733383466373061363332303162373638613434623266393239656434323430 -63383566663563613035373439363363393439356565303061323161363263653433636566353530 -30363366633565343137336364613239636336366266353764623461386533326337373435356638 -32363137386232653036613565333136356338643335313535663433343439656366613030303534 -61333330306664663930643931656464616164643032613230303661303231326435303863346166 -61323864626662356430353065346265633466313862333132323834323736646231326439633865 -31613531623937653738333363633664373163393163643538303539643764653630616634326237 -66366162663335313936646233363332626365366130313839333637323430633038633661396665 -30636234396163626630623632393463663761383066646461643562396364643832306462356632 -66393331363366613230633337666538663734623039616435376663343863306365366666356565 -32633937616635333962613261623034623461353133363966663036313632316132343361333663 -62343265653738356261316631363933323462326266333437653062396138666463326261363030 -36376565343863366665643536656530313435383661353165613334616339363930376236303333 -62333638663633353337666339653964393962393863353662656437646566353238613266343233 -33336262343735393134663433393863333637373361383031343734663334316433646463376138 -35383838343164376565366334623532356130353062313962346637636362626435383536303332 -30303839386362616461396138656439313131343136323161383639623832643363623965343632 -63353739643762343266313562666265373661383837313839656666383537366231643737353635 -62656563346437353332396265646431323663323737633132643836333862363064653835386630 -30636431333339376437666265353036356164643665383064316137353236613730373037366437 -35373362643461623039323239393161613166326534323362643632393237643333666237326435 -35353836383165323366646435383361636133663935316361623262313930316363643332323863 -36353861613166386232393133313833663063643634373966666564323834326338383864346365 -31326666663836636238383239636137366133326461613235373566623933326561666162336533 -65636530373366613761613832653935346666643930363563323465653461383137383439333837 -36373839333037656334656435656466363061353831363866656330616134653539613561663236 -30316466623961643763646266636565613564643165623232393330353530656262393330366362 -34626561653635613163663965373465376337666432376364393762373433343538356264613465 -30366533666231396533626465326638343363376166336565353030333933333739343666623135 -63643339333932353262396430376431333733336366353762366434306564656264366434316261 -66323030636431623237303036373033323233393961623133363266396566336539636533643063 -31313438646334363731336433303338323939343431643063373866633063616365633633666634 -62316130333862326662343162353061313639393437656235616363326230363165386436663462 -31393030386339336265306165613562313733656137313834353064623639616461623136306261 -62366435316263313335653463383031376439393838613061343433626430303634646365313030 -37373761323331623833303663393331393432643832616566663034376231376532343134343136 -65326431313861623238383631336361363062633461386234386337393836373038356232396239 -39326661643835316131326332633932336632373663373734643532343432336333386633303265 -32366363623365356531653637363264386562313466363834656461653563393066353734396139 -64616235356435666366313231313634343366383865316631363337326635656136643834363563 -36333830623632613634613162336530306437646134313638326662656663626366363439643064 -38366536643162393136656262396430313431623234356561333066373861363030653661616266 -66333638363535633137646431313966666530333963383834643536303432323662333863326631 -66366132313735353965326635663435333035636165326236386435623336633564636139383237 -38623461313963313765356232663331343939333236646638343336343832626466643338626131 -32343837666535346261623762396266303034666365373261666266366235336336323635613433 -61376366386163383735376330356138363337363263656363353562616631306639366566313362 -30613233346163383032376262336632666665323832373935636130626562366137613331613762 -35386336626132643137623833653838613733656131616336613136323535333130363637323962 -63653434336130303964373232646463353635313933383262396535653662633162663161356133 -63343833613138363362353236393038353364646537353539613930323666643863383266656636 -36323138323565353562643337356563363136666530383662663266393036356166666230643764 -37643366313635393330303330643164643537376462343538326164633566653830643331653764 -37333963323163366662353531366663613337613835313834646439633032656561373762643665 -32663235333337663133383061616430623931336234326532313861363162623865323366333563 -36633564666536616666653963323338386363366539663236666363313862656434396163666233 -32633531646231306165663966353434323738306534396639323035383030653566613031366132 -63353638623162326339363664616265363935386365336439356361626239383662343539326165 -64656534333665333064363865383965323861663032383138646638396566353631623039373030 -30363636383562303738353864313466653039383033623761303435316164326233366638653332 -32653036383033323233396134646164323035343130616264353534396261386438386434663335 -66303438336664383035343232643939323161643035666266663161623337316434666237666665 -33306633336637653937346462646261616165336239303866316437386530346432393163666239 -37376463393039346330366364376330616535376339663638663330323039326531393230353266 -37383933333332663832306239346663623033366530343363363865646137313432623337386131 -66336133396532383065386365353932663636386462616235636434646265636136313665336663 -65343863663262396439356366623732363038376234333536383633316566306161666163323865 -37623864663137343962363338383764636231316638303063303963666465613938666664623739 -39643739643362326239376566656533343534343163346232353039383138363231353730336637 -64633539396631323039346365666363316438616161326535376337613139313762336131653866 -64333462383230373461356265343263326137653438643936373331386338666337376432663366 -64326433613631383964396237376565353132363335383531323264353961616264303965663134 -34333564623563336530303630663834386231393636306662653536646266396465313162383531 -33363238616335393935313965366664366538306536336131313136346564323030306434326136 -35363430646135346636663732626332316638643336626538623830643237366132303932616532 -62346564313063656338373164653361393336303065313136376633653934356466373865303830 -63363139316265343434653137316638653964396561626539653161333033626432633364613635 -32613239646536353264653637616165356131666461326330643165346134626133376261356639 -64626662313961383662626464383538633735316265636435363932303365613735313031666336 -64373061313139646635643337376261326261376336316134643966323362343865666138336438 -62336537373333386531623032646336613935303138393234326635636661336232313538313732 -63663131666533386635386666666133633366346339373038343764303966383732623832356136 -36393964393530656236363434383430643834373735336130633163666166373935313230633633 -33326561313336616361633562636663616536326432356562636238636439656135616265613537 -39336533306230373162623436633039636335316331363661643166373465346466316165343037 -38306531663264326462643261316634323963656535383839343936653138346238333361353431 -66306464393764613535643765363538376631383530326135356564643531323666333536333966 -62396437323164313830336565333639653164363831633636353430366564326433333833383436 -36373134326261326138306164386233376265343739386530366461653364653231313663613337 -33373236343831386537373235656439373931323263653738306663306632333738323437666137 -38313638386132646331373362633336376433323631656130663562366438353266396561373732 -31383233356132653331333161346665653364383864623734373865333135346237303437666334 -65386139363835323466333961613864613530613532643532666565396366636439373439623338 -38303338313264303031633338393662356363376431316335336664353930626263633061613033 -61653264306531326662343962643565663861366239343961396239383962323734343931626333 -61393138623961356539636435306639616362643438386234356336373930313363363132373933 -63386533613433653331333664636231623232633963356263383932336261393430636130313933 -36396535343964376333623736396634373765383539653935326265646338383961343064653766 -32333038643866646363613364306461326265383330346633613230313939623165363337613664 -62643034396433656631323030383131346435653830333566643234363438303062666662653333 -33353731323736303965386563636536646333383662663430336536356337623130366433333463 -61613662663930366336393639646562666130303730386133306539303164303038363539376130 -36303864373361663066363630633434306530306166323030653232383530663262663938633434 -30346234666533326630633662633764373362623461653832636265303935373033646237663638 -61343932353033656163643437396134633032613038383331393761663661616166613931646661 -61623134623966646337623930316131386231613465666232383135626336306431663237303463 -37613161356366356433653938323036333332306230633934663663386137336465323430643263 -32313632306435373338373437643532646262376163343336663235376365646434633964656165 -34346436633462616136666134633738643564393031646666376631363939313336363739653630 -36306464353265376439316336373661323939633332613139646438316464633831333331626561 -33646133393866313565333733663539393466363337353537616138393066646332646362326235 -38616364383731343432613561366432353738343662356465313833303531336230623538306332 -32366165393034373934383133306632386264383032366238303566633466633666353335633038 -39393632313636373931663063306635393263346162323135303265376361303965323039626563 -65323161353338356239626635663838396238663366333663383366326336336635326337353463 -32623465656565633666366566313966303761346431323261326134356537356131353133626330 -63353931303664613238366230373133323735653936333961303931383839663966663138386563 -62643533323837343834386563353731366463373362616561646239643933326162643937623264 -32326539643439613066633131663934656134303130313766623230336362306364643363666466 -37333931373065393538343839323233373438383930383937616531633263333539663664663339 -65366638663037306133353137643561643661636635623639353965306533333833663237336437 -37346534386161366561303833323738303832326532336465623031306164633561316561333039 -31353161373838376339383932306265323865626432613239373334623465656539366331306430 -66376130663630306337636263656239393638653632333261333362613939623032313133653730 -63633631643365383565643630653966653263386663613835666463376138646333333764636636 -30323966376435313266613037616664353432383966313339633733333134353865326131336536 -63313235393935616539303434373562343335653331323235636639306162303132393434376563 -63643332333566343961636335666264373763383332656234313962323966636131343434353837 -61363262306261333538323865343136336364343137373437366362626634376634636333333239 -61393362633964633634653131356533353561613866363361663136633866336133613632376138 -326465313839393338653864336264653263 +31626261316238643130313034663435326439333632396363393366313336363532316663633835 +6239653832386136343537626435303237623931306161620a363934666265343166306234386530 +33343964626336333439656666643064336562393232383138346135306432653932303863626335 +3937323562393431370a386461623664613633616334393961366532626632613266366533653538 +38623036376434666564616639613436383635666233313762393965346531356366333836656164 +66366366633838613932353566633530626363666430376232643132356566356134303839633133 +39323431333233666133616461626332626136353739643733336637633764646631633139616330 +32386363636135323938333932363337623764323164353238663634363634396437633939393331 +36663138383466623063356461366634323964323762383333343936643233323236386262323161 +34373031323633656632613166346661666532373365343633333535326566666135333234353436 +61336436323530386338396164653138643333366532393766323131643934623738666264623136 +64303966396438366363306361653038316531666535623665653464386664346233336439333335 +35666462316665626636663935353061653266616439613066616338323539306531333035653033 +35393834373261373863316439363936386366613462316131376633393135303139623333356431 +37303632396662643735366630623734366565333363366362633533303138396238623565646262 +39386664396564366137666131363066333733643635333738326431306266306439643963303038 +64313339346135633232316334306636333033666437366231633339343034376339313038303234 +32623133636230396562646162386362353438353036623666393736633962353234396634343437 +61313930303131373137306535343465633633653631646135326566316431613463656332383430 +63306432653563383663356137623836383332303731653936303238396330353636623230356632 +37386431623330326463383437323836376561643536323730613933323236643135363161356534 +65653166653137383030323939373733333263353466663766643335336265643065306433363462 +38373332636361636566333963633537666630336261626365393335373339386536346236393138 +64343965376539333232306632313063363939666463333138383866353937353133626230303632 +36303462646664303664383730316265646631323331613439616338663665633435383932373839 +35346666666161383730343161653566653664346536303631373038376538623763616261356139 +30363164393762366636656666623839376535313464373934386332343765316162653464323737 +31303563396461653866356465373135356463383164303331323633613733346232313334383266 +61386664383431353831663038303766326166613066636264363730656132363934343862363664 +61353030623437653032623335363162336564383630333631353466323035393637303636313537 +39303731623932356531663730303234306434646663623532376265666335373166626230303462 +34666364346239343231613931363231343662623435663861636435326436653730663633393039 +65306532636234343161343431616439383561316166363630373333636162373565353631666436 +35353163633331323234383935326565323364643230663363386565316432323230663066636161 +62623332346238636263313731333835383461303530663161313932333064333863633936623166 +61313561383234316437366332626463636530613566333562363361373734626436363436633536 +62346363333664386536636165363136623365363335396136386564303138646635666437376462 +61376433613930396161336531613865666632316538363061346535393433653664316630303938 +32346433643765646231623761646566613663306133333531613332613831613264356566323932 +39623466313664343336373066626135646533643737356536376236613864326136666633616330 +63613536393833303739386364313231313233393135656538393862663635613637646239633334 +37343533633431393133363231313736373530316661393366303631396433303839633161323962 +66343762373439316432376433626236663865616534613366313335663739326632646632326332 +39633236656364626534663838313835383236646638353465663663356335356130303236306231 +62303536366630363137633965363239663034646639326164306463306330643064353337366438 +37306463366339633263363231656365303237393034386431376566643263633836646166616132 +64363434373930656164376363336239623338323230383430643834613739663563343133303538 +30646237636534613766313662626163386166376235336533396566623037366561366565333835 +65313239396464346531623636363231303861306566393733326331373964346334613036376137 +30343630306562363366626336383336306539643039623839373033316361366632386561643338 +62323538613065643964613130646234613731376532326361343363633539656266623439626539 +35393935346662666439656537386465323036653634666365343233303230346238653339636639 +61396561353933643465643537306465633562303632313631356366393662333633386266643730 +66633736663133343331643162333836363536333536613334343235393434303462356132303664 +35613161366266363664346136653836616137383463623537363437386537383332646537653065 +37626631663435613663626130633939663138663239363863343139333165336533623730326337 +39653632303634333638636231643264316337313237373433393939633564633663333134363464 +34306134623934383765353562363364323233633363326661383733633631616633323565346365 +32353565646632373238666534656565373161626535326364343039646166306335613563393361 +37653239613438373130346132346161616334323134313632383134653331623434326536343261 +34636636353035623436613230306265356230303338336263646662643562666234333634336464 +36623034663538333566386362326234323436306336626563376634313766363262623038313562 +32386161336432386163663834363431373066663464363138353761383330336166626334383565 +31623463303736613162376335393366353162306262663565313835393130376536306538643437 +37353062336238643639646364386361663065376264373231343062653836616533393936376663 +61663961383632333632363538343063326164613631666239323137356434323037323937323133 +36323161393065373735306334363930303363313035396364333632616637306662343835646464 +39353162373130626236313833643866623037356463633536386561646561636330363132306461 +65333863393239306164643965353365343030363730393963393539646664616266333335663735 +66633838373763653663616564656365343730376230653532646336343835373266623431616138 +35303438653266333065313237346536636466313136386436366335333030623338306636626236 +62666361313539646631626334353637623731363461306431666232666264373133613935323239 +36393135393864653437326230656435613436326539666662393938626364323934313637323338 +62353638653935616561633536623332633732663936663431663938616634376364356566663734 +66333466316165643362613162643630373763323131316237616533386635626337613431666137 +63316466336337666362343432373162303066656438633666633430363265343231323337663834 +30363439626135363136323936303233373830303263633635383537613639333864316539633536 +39656666396630393764336530653933666161616331333830376363363963626136616665356661 +64366433363736343333633237663732346333643731616634326532343838396666376263383361 +64333233643231363834623632396562353031393139663265363665363937633238343038616632 +65616261386235356463633038643738353638613363356631363731366664663939663262636566 +31386433633232633537313036306565356437626465386435653431636362626164306638353236 +39396535303561303734643435393530316666633437653562333162633266333836616632396138 +65653337343738303032626632373266336633653734373161363962343539643536323938353430 +34343032386262393936386666613636646336643137343964393665313134333338653364373366 +39306466666663613132363766363133353032376638646537623639376661646232653739316434 +62353464323930393436613039343538313434633362373562353930643266363037396161633230 +63363736336537636434353537643234633230666335613162623362343461376363616562616637 +37353935383239386663663437343962613232366234643233353562666566323331343335363666 +30626632623939323166663565346235613632373163666136616234343966646663646161303963 +32353433313764323638653337336166633666333337326639396262333038363266366661323230 +38343537313731613237356530653861636362393935363035633739386134353536363661313063 +63633762643733643033623338653830383538343630313237363638343865356266333037393766 +31613332363862366262616434306466653730323961353966343364323934646537393861653239 +65376462633035316261626632623131343338323065303365343066323961323130343962333635 +35373763646630316463326136393463316135386537636439646433333238643865393065663264 +65343831353737623833363036376131613734613130316534393463313361656331373037613530 +65323134396565303736303735346431666631376236353962393862663537323831303335373635 +31623965623137653934393665313366333539616338623361393338613863383036316232663066 +33306533666139386333613231346232323663663737383164643739336365643731646365616536 +65353034336134356366313934353130666331373131333135336232613865663033623066613134 +31663666373163336161656635633364643436613834316532636562363835656338333063303664 +63396630326265313030666435346132326230343031383030376236616466346334643436336361 +31663265656661626464633235396430653637323664373133326562653265666436613834363836 +34323430363431616462303936623861633837323266356434343162356639653630333533653763 +61353431313233303461343238373966343532353033316632646133313737643139643064313733 +64316431666339386438663066613334653939613165383162303039373830303834343339396661 +65323063623633373036323737383563653961613830633163353364313861653231386664636134 +30373966343565323430386532626233643163636536313537393632396232643832653532616439 +33376633613633613266636466353130633636336132313237663166653931383137626230333438 +33393663633532633934343962383363643431626633353432613336366264346436383334383634 +32376532303166643132323962363566356261316666643330386366613035646636383133336239 +65353336366363383935393366666633323737323465336337616535663339623463653434313536 +65326138353035653266313539333631343733623737373766376466373739326165616231653933 +63613732623462353666623536306130613237366263363030373166643666373938303733353234 +65376530646634303235326564663738323461353239663237306361343762346362353861656131 +34623833316333633563613733643834373334396534386361346431303931643639663634373539 +36616262353761323138383933616138666631373132326166383561613835316335306437323565 +35333162343737393066663965373366313936613637313731633737303362376334393766656334 +33366231613361636233333065656537376537363666313430373231613066643164373864623337 +61303934626137643865613538653436363038613532353730376430353862613136643039313364 +30333864376439303039623161386631373535373034633735643464643536633965323233646462 +34346362643936313935626434366666653962383237613537306136363865323832386433383432 +39643233643034633132353734353135333566353439656339396332646464613462306563623238 +62356135336138356333356364643839313430303163663039656532303863633164386130333337 +65616565656534643166366665393166666431376134373932353435396365303334316436626162 +39323733383236303066383563636238373862313533366663663535623663313930383431626639 +66626330626164396634666464343534333263616339656131346266333764383964323731336466 +33633961643663306636663731623839363964383635626264326461303762386130656135323735 +31316363376165656432333035326230326263633861373231356533356162646433653861646235 +38663936616439393832616438313665616666663936393931303764303735316536363133663538 +32626665366336323864353237343036613932363636623063336633623865623637396638373039 +63613536363366666262373365643233366466643631646265633665316563346166346166333438 +34323039326237373061616234363639323032623035333663623336626631653236396434333133 +32336638646535316538333238346332396664363766626561323261393135613737633634386134 +35663666623135346366373562653038373363333537383332353537366630646331306464393035 +37396365373932633861373162373562393236623230623563613662373565353465376632326130 +38633436396333313637336262393439613434616339636530646337393661363833386461663036 +34346632623732636338366533316337383938623261313664626536636431643965306237623232 +65616534646537376634323733343333303164666266643630343938643033646434663334343965 +30383832653765353466613735646161343962343538303166353536306437633939393735356261 +33643763643761366137653635336265326638303834656666666635366663383239343065383566 +33313034353862653736646563313532386539633430653530613932353263653039646261663438 +38313430333530393366333634366634646266666533396435663966333564336163323638353934 +63336263613236313763386465633133663666316363633539393530636435326530393732303639 +66343162646262646339373362636130376339306162646433316333636335363933633730396337 +62623337396364323866396634323234383837313531323232626464356336353439336630323061 +30396163303037366365356331643766343335663061646137666530323435333134346230303438 +37313563376135393933353031613936623362373662643133333035613262396431323032646137 +63326432653333616230373639353064396265626166626530326230626435313137643139343961 +34623432616535376262303961306265393864643032626531306336626564396563333463626461 +31316530396361626166393262656231663235313238326166343237333436303265656461633465 +37663466313831626236326537313733326565623565623266656139646538656435316537383963 +39323639323336666162333164383737306564383235623737313331643166306464333863343131 +35346163336461386433616461626238356633646663653032353766613361346466363039653631 +65666663383565633533323339636563383931333264613933353435383438303634356263656533 +66323364656562333932306535303963306163376261383435313033356636633832376263636338 +39303462633830313330386334343735646461333065386635643831316366343830366233363464 +35663030623039633865316135313636616332313536626539616264303135313238653836626133 +62383563353365663533616330306463643861626662306533626334346234633365353834613864 +32306666346165643436323861316238343630393839643366326334313637373532616338623637 +66643335643364323338626565363530653666313133653234306238383465623761323363343763 +33653437386236356165303135363166663836623861383763313364636232646334663466356333 +34626465356534616563373236393431623230356261366464303537386434366463366331323264 +63393936623362393835393938313933353238353632363035613262646563383931386332323233 +33663161363666363336656638346334636335623761303931646137333235333732336163306635 +63633966386139306366666434613233336330306165633534396564313363366463373139636130 +30323332396262386332626133616138393032333562373061333062326230613666326634306364 +35353361366461666164626362356630666565323930613836313261643761393835616234306230 +35613662666437663366656664353837363761343136323563633439386434646139616365366136 +38636338313666643236653732646266623832616139393265383830373032376334623037396262 +37386462636563373230636265323436633039373565616165343133343031646135306438386538 +66663834633361356330353337326131616437396665326434643136346634303334316634656232 +38353761376463376337386361623830346438656365333939393038323130343766343861363062 +62303663633464373639653035383265303137356437656434626236356465313334656264613664 +65343161366637373631623530353866633338313333373662303537653139643538326665633064 +36323533333631336663663566633964393161373538303564613938363734323236643363613736 +38663264353963313862336536353663353934613739633130383832626132343430336230393436 +32376639386365323234643263613133303066323730323863313335646139393065346638613536 +33363233353464303562626134383038663633316539353964663331383563323466646537666264 +38656338666462396365356461633762343562363864636461393761663430633761373466343364 +39353539386536616431376230366463336133373564383866353131376366386438356565363165 +36643838363631633533613538303933666437643766373666663634653661633366373664373734 +35663232653839663234316131666236353438316265393761643462313161383164346334626161 +62333837656432306661643736346334663534343464636165633135346537366433653265363735 +35386531643738303265636638313831303133626330303239396463396134383931336534366364 +35356330653965666339393136383463663561663739366438633765336365663635343138663935 +65383964663663386230303733333037653233653463353836643332306162626565633362393265 +38396132333362613833623132396663323036323337343231376262663832383665623332346438 +38393238353763353062363066653230396233306533666131613664633431386436313331316634 +32623366383562613833646262316535383762616265643532303662346430633939623531313232 +31333565643366346234373830373431333461623165613031313638313764303532663461386432 +35663964646133373662346562376564386231356631653832313339636333656336383066643766 +34656639366234623533626233626435373236386533613935616161643061663062613463383862 +34623563626438656434343065366130383633663964313737323634346636366530386636646133 +65306464613166353038303630383031313138306633376530393762396232396462633534663930 +62373733313738343135323066306164623538376366333937326533656435396361393361653332 +39323238376433653533626163346530653534643539393964306364663037653061653236343161 +33366539373533613932653834386365663961616139313638616638646232646536646466626163 +34333535643236316238323231306436656132666463393439383833356535623834366637386538 +63623932336631303065323264666663333265333765313262313536643830393034316163623263 +36636361333466326361646663613332356638623836633465663338353434663466623465363139 +38383966303766313931346262353961366437393134316338303465323233633130303134613335 +65633835626134653639636166663865353632643864656633323136353734366238326161616237 +34323738363464646634313430303766396266633538333063623333396664346266356461393361 +37666562336539373531383934303166623063373735326435616666366264303632326662303939 +66343061393765303139383463626565643335383262646661626461306632653363363336656534 +31613738333064346139333935386361343435326335626336376539656663363034616431313766 +65636533376137373536353438623034343563636535363331653030616432356138316235393036 +63633938303836623139653461623130656266343537623261366530396266663463386633306132 +37633933653766376639373932356563663164626135396239306238336562313831316531626434 +34663636353830633164313666363466353766313233363534656562646662646636313734636232 +31316565666133613932393165653266653461353536663736616363383033636262366238336662 +32353537353063353963313532616131313766316631616232646134663966383361366533363664 +61333933343836386465636335656364356133326463306563626433623232346238323438616436 +36666263393330303163373236323431376561646161386236623133653431666131396637633339 +66646332353539356364333464633763656433383831393861636138646133356132353633313665 +62303235633661653038306434653736616333333932636534346161393965633265353436383231 +31343263656631336266636466336138383232643865366365383262613135393531313937663064 +65303437623231623562313237313535366135653661383031333731623933663133316261323164 +65323735636164646532656364306238316165333632626663366132323739386138616634363464 +36626466333663613763653236663234323131656330376530346537653166633839313766653430 +63366630373333646263626364356438663138323832623037346131393431336535636135366138 +62393630393030363639363439326535333636656636663462326164393461366166316263313335 +36333932633939616134633234393065323331353864333932303232396536646461366663396437 +37353039346566363739343530663034613837626234326639666665653466623732636365303661 +38346130346634346433323362646430313261663964643434663834353830613035316430643737 +64636561373437393932316631623032616534653732383233396661646362353634353330656337 +37303136353631373632646362613361376133313533636437656264386236346637623534303630 +62376664333332646231326334616239666461653931653237656430646337303235306633396633 +64616266333033393762656431633634383966383637313337343463326134343964346361303235 +61396261363636383632616434613634393063653266353063343137356166353736616438656366 +35336466343931653639666233386439373038396366353338336665643362333132343232616530 +63346533366130636234323533633536313461623437353865376263313562386630316565336639 +37336565356631306538616538326132353939396338373038323939343534653335393835636234 +38393130363830353461343731656332336532303731303464656463356165323531306366623261 +61353234636166316337383936316637396634313061323337383732666336663830376561323134 +64663961313334663466636365333264623330623932633933643730383635663737643231353030 +66626630323230646636386161656566646531316532373432356533366166353062613738643534 +30343034623831303638336430333738643939393362386333643431643764646364653734643462 +35326336303733636532363161303563616263616332373264303663646665393438383439346234 +65376538646666333533613465666538303161303862353166343866373732633766366234343230 +37303330306464643233333433383964613437643038353330646631313637343163393962323033 +62313261326237326434653634313664346237636330613535346665386262386139653737663163 +33386232646566333536306438653461656538333164353236383734653362663366383238666261 +62336164613737636362346666363361306536663230333865663462656365636265663835383663 +38303037323334313036363336646139646433393762373538643561333633643239663464613861 +32333363363133303336363062393936333064363566373562346264336135326364663335343335 +63326362663530326461316231373966386432666439313030386666303562633837316534326666 +38386437313866323937346434353039663835623333396334383038333866303364633339353434 +39323838633735336535346539376365323037616433653434663463313733333265353230373764 +37373939636664363536326166343930663465326632343436656435386139636264613136326139 +33383035356234336234376638316439383764623934316535336265303335333265303231306365 +37396564366636653635333561663935323039336635316137303764623334383534666532313862 +66323231333266353337663964376439376639326237643738623434623564633632333366343736 +62353334656437323731393261663761313864626632303865393039336432346565666430633639 +35303465333139333266663465383135653163643137376661613066323564313337383663656266 +62636434303264396536323862633138633930356665623334373735346666656566623062656536 +66353064323263313666363031636531356332623562356136633564633235663131633037366135 +66663239356533303531313636353465383838646232396161646461386563303864356663373331 +62353366343131613161343937343232386663396138353038363462373830363036393036633732 +61303364306233633934333032623830333933343731333034383962636361363565343830656235 +61646432636161313164633236303338356531663366386236633337633832613832386263313562 +37373935393731363232653833316361326365646134643732303866333864616638363733643561 +36633936663838333831393638376637653563663336363939373531623063353862383736313062 +30623939373834633930363266333765383661396335376438613935316632613965343432316261 +38313263666535373961653435653336643664306432656463373233636364663065613836313130 +61613136636333643038383032343662363430353137353337353137323830663535393662613738 +33646337613232313435663330303031303235613634373538653136303430336361623566613339 +34313936616130356234363336303630656639663231623965663962666239653931613832646365 +33666265396465336338366333666438306639393465666462383962643936643361363666396136 +39663436303334363065333733626233633161316331653061636363323261343433623839393862 +62363661306165393661613430376330346130653635643138636165363833373538643730376161 +65653633373834613933303166366532343938343765333532663963326262373566306663366163 +30356237653938663237626138313435383236343738626531363130653839346133363038656664 +61633739373863336266343964333264396263393764616561633336313963323163653636363966 +65626363386463616632363063303865386139646536353134353938386565303235643430656666 +61383035346433393637383232326230636265333039366461633837646262623335363935343564 +386130373763656437623631663933376133 From d9f9d0ebaf17e45a30218283536adb4b059c0077 Mon Sep 17 00:00:00 2001 From: Frederic Gingras Date: Fri, 20 Jan 2017 14:09:37 -0500 Subject: [PATCH 27/27] meta: readme: fix typos --- README.md | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 25912e677..39c12efb1 100644 --- a/README.md +++ b/README.md @@ -97,7 +97,7 @@ we follow. To run the code linter use **`make lint`**. ## Production Like hinted in the tech stack section, this app is deployed on **Ubuntu**, using **Ansible**. For the time being -some aspects of a production deployment where ommited for the sake of time but most decisions where +some aspects of a production deployment where omitted for the sake of time but most decisions where made keeping in mind scaling this project to more servers, sitting behind a load balancer, or using an in house database setup instead of a third party. @@ -179,7 +179,7 @@ to install all the required software and dependencies for our app to run. $ make ops-provision IP="" ``` -If that completes sucessfully the server is ready to be deployed against and put in rotation under the load balancer +If that completes successfully the server is ready to be deployed against and put in rotation under the load balancer (there is no load balancer yet, but you would have one in a production scenario) ### Understanding day-to-day operations @@ -192,25 +192,25 @@ Access is possible over SSH as the user `op` (for operator), only public key aut is enabled. sshd listens on the default port, 22. If ever you have a problem accessing a host, it's possible to troubleshoot the issue using -the web console and logging in as root using a password, ask a collegue for it ;) +the web console and logging in as root using a password, ask a colleague for it ;) **Application process** The two processes we really want to keep running at all times are nginx and our node.js app. -Nginx is started by systemd at boot time and runs as a daemon so it's very rare it's parent proccess exits. +Nginx is started by systemd at boot time and runs as a daemon so it's very rare it's parent process exits. On the other hand our Node.js app is a bit more brittle, that's why **runit** is installed and started at boot -time to watch on our app. It's default behavious is to restart the app anytime it stop, forever. Which is nice +time to watch on our app. It's default behaviour is to restart the app anytime it stop, forever. Which is nice is it doesn't make you worried the process would stop restarting after few failures due to external factor -(and then requrire manual intervention). The scripts that configure this runit service are located in the +(and then require manual intervention). The scripts that configure this runit service are located in the default directory: `/etc/service`. **Database** The production PostgreSQL database is currently hosted on Compose.io, so it's that less to worry about. If any incidents happen of we need to scale it, the compose.io website has ways of restoring backups or -agmenting ressources/capacity. +augmenting resources/capacity. **Logging** @@ -222,7 +222,7 @@ Centralized logging would be a needed addition for production but for the moment **Performance monitoring** -Nothing is istalled yet but I've seen DataDog and collectd fill in that role pretty well. +Nothing is installed yet but I've seen DataDog and collectd fill in that role pretty well. **User monitoring** @@ -238,14 +238,14 @@ Setting up one of the following great options would save a lot of debugging time **Security** -Here's what has been done, there is space for improvment but it's the basics: +Here's what has been done, there is space for improvement but it's the basics: - Upgrade servers periodically - Fail2ban installed - Firewall configured to only let needed traffic in (22, 80, 443) - Password based SSH authentication disabled - Root login over SSH disabled -- Application running as non-priviledged user +- Application running as non-privileged user - No secrets as plain-text in source code - Deploys only possible to developers that have the server's ssh key - HTTPS forced on all request @@ -261,7 +261,7 @@ CSRF is also missing :/ If ever something really bad happen, the servers are stateless and disposable. The one really important piece of state is the database, and it being handled by a third party with automated backups is reassuring. -If you where to rebuild a server fleet the process would be similar to provisionning a new server, expect, +If you where to rebuild a server fleet the process would be similar to provisioning a new server, expect, it would be possible to provision all servers at once by passing in a list of IPs to `make ops-provision`. Once the `support/inventory.ini` updated with new IPs we should be good to attempt a **deploy**. @@ -285,15 +285,15 @@ $ openssl req -new -x509 -key ssl.key -out ssl.crt -days 1095 -subj '/CN=