Explorar o código

refactor(frontend): upgraded Vue.js, implemented Vuex on a basic level

Signed-off-by: Jonathan <theflametrooper@gmail.com>
Jonathan %!s(int64=5) %!d(string=hai) anos
pai
achega
7f57c83cce
Modificáronse 58 ficheiros con 15006 adicións e 14567 borrados
  1. 104 97
      README.md
  2. 3 1
      backend/logic/actions/apis.js
  3. 6 2
      frontend/.babelrc
  4. 2 2
      frontend/.eslintrc
  5. 377 291
      frontend/App.vue
  6. 4 3
      frontend/Dockerfile
  7. 1 0
      frontend/build/index.tpl.html
  8. 21 19
      frontend/components/404.vue
  9. 288 0
      frontend/components/Admin/EditStation.vue
  10. 293 219
      frontend/components/Admin/News.vue
  11. 133 104
      frontend/components/Admin/Punishments.vue
  12. 165 137
      frontend/components/Admin/QueueSongs.vue
  13. 101 97
      frontend/components/Admin/Reports.vue
  14. 151 139
      frontend/components/Admin/Songs.vue
  15. 288 208
      frontend/components/Admin/Stations.vue
  16. 1 1
      frontend/components/Admin/Statistics.vue
  17. 102 88
      frontend/components/Admin/Users.vue
  18. 152 149
      frontend/components/MainHeader.vue
  19. 124 116
      frontend/components/Modals/AddSongToPlaylist.vue
  20. 163 136
      frontend/components/Modals/AddSongToQueue.vue
  21. 120 81
      frontend/components/Modals/CreateCommunityStation.vue
  22. 12 12
      frontend/components/Modals/EditNews.vue
  23. 603 524
      frontend/components/Modals/EditSong.vue
  24. 269 198
      frontend/components/Modals/EditStation.vue
  25. 185 129
      frontend/components/Modals/EditUser.vue
  26. 56 47
      frontend/components/Modals/IssuesModal.vue
  27. 79 64
      frontend/components/Modals/Login.vue
  28. 2 2
      frontend/components/Modals/MobileAlert.vue
  29. 39 32
      frontend/components/Modals/Modal.vue
  30. 87 72
      frontend/components/Modals/Playlists/Create.vue
  31. 349 250
      frontend/components/Modals/Playlists/Edit.vue
  32. 109 81
      frontend/components/Modals/Register.vue
  33. 9 9
      frontend/components/Modals/Report.vue
  34. 61 58
      frontend/components/Modals/ViewPunishment.vue
  35. 2 2
      frontend/components/Modals/WhatIsNew.vue
  36. 185 153
      frontend/components/Sidebars/Playlist.vue
  37. 212 160
      frontend/components/Sidebars/SongsList.vue
  38. 52 44
      frontend/components/Sidebars/UsersList.vue
  39. 360 308
      frontend/components/Station/CommunityHeader.vue
  40. 373 317
      frontend/components/Station/OfficialHeader.vue
  41. 746 641
      frontend/components/Station/Station.vue
  42. 116 92
      frontend/components/User/ResetPassword.vue
  43. 275 202
      frontend/components/User/Settings.vue
  44. 120 92
      frontend/components/User/Show.vue
  45. 1 1
      frontend/components/pages/About.vue
  46. 131 131
      frontend/components/pages/Admin.vue
  47. 465 376
      frontend/components/pages/Home.vue
  48. 1 1
      frontend/components/pages/News.vue
  49. 149 100
      frontend/main.js
  50. 0 8548
      frontend/package-lock.json
  51. 29 25
      frontend/package.json
  52. 18 0
      frontend/store/index.js
  53. 100 0
      frontend/store/modules/admin.js
  54. 59 0
      frontend/store/modules/modals.js
  55. 32 0
      frontend/store/modules/station.js
  56. 31 0
      frontend/store/modules/user.js
  57. 12 6
      frontend/webpack.config.js
  58. 7078 0
      frontend/yarn.lock

+ 104 - 97
README.md

@@ -1,4 +1,5 @@
 # MusareNode
+
 This is a rewrite of the original [Musare](https://github.com/Musare/MusareMeteor)
 in NodeJS, Express, SocketIO and VueJS. Everything is ran in it's own docker container, but you can also run it without Docker.
 
@@ -6,19 +7,21 @@ The site is available at [https://musare.com](https://musare.com).
 
 ### Our Stack
 
-   * NodeJS
-   * MongoDB
-   * Redis
-   * Nginx (not required)
-   * VueJS
+- NodeJS
+- MongoDB
+- Redis
+- Nginx (not required)
+- VueJS
 
 ### Frontend
+
 The frontend is a [vue-cli](https://github.com/vuejs/vue-cli) generated,
 [vue-loader](https://github.com/vuejs/vue-loader) single page app, that's
 served over Nginx or express. The Nginx server not only serves the frontend, but
 also serves as a load balancer for requests going to the backend.
 
 ### Backend
+
 The backend is a scalable NodeJS / Redis / MongoDB app. Each backend
 server handles a group of SocketIO connections. User sessions are stored
 in a central Redis server. All data is stored in a central MongoDB server.
@@ -28,17 +31,21 @@ which can become the primary node if the current primary node goes down.
 We currently only have 1 backend, 1 MongoDB server and 1 Redis server running for production, though it is relatively easy to expand.
 
 ## Requirements
+
 Option 1: (not recommended for Windows users)
- * [Docker](https://www.docker.com/)
+
+- [Docker](https://www.docker.com/)
 
 Option 2:
- * [NodeJS](https://nodejs.org/en/download/)
- 	* nodemon: `npm install -g nodemon`
- 	* [node-gyp](https://github.com/nodejs/node-gyp#installation): `npm install -g node-gyp`
- * [MongoDB](https://www.mongodb.com/download-center) Currently version 4.0
- * [Redis (Windows)](https://github.com/MSOpenTech/redis/releases/tag/win-3.2.100) [Redis (Unix)](https://redis.io/download)
+
+- [NodeJS](https://nodejs.org/en/download/)
+  _ nodemon: `yarn global add nodemon`
+  _ [node-gyp](https://github.com/nodejs/node-gyp#installation): `yarn global add node-gyp`
+- [MongoDB](https://www.mongodb.com/download-center) Currently version 4.0
+- [Redis (Windows)](https://github.com/MSOpenTech/redis/releases/tag/win-3.2.100) [Redis (Unix)](https://redis.io/download)
 
 ## Getting Started
+
 Once you've installed the required tools:
 
 1. `git clone https://github.com/Musare/MusareNode.git`
@@ -47,39 +54,39 @@ Once you've installed the required tools:
 
 3. `cp backend/config/template.json backend/config/default.json`
 
-	Values:  
-   	The `secret` key can be whatever. It's used by express's session module.  
-   	The `domain` should be the url where the site will be accessible from, usually `http://localhost` for non-Docker.  
-   	The `serverDomain` should be the url where the backend will be accessible from, usually `http://localhost:8080` for non-Docker.  
-   	The `serverPort` should be the port where the backend will listen on, usually `8080` for non-Docker.  
-   	`isDocker` if you are using Docker or not.  
-   	The `apis.youtube.key` value can be obtained by setting up a [YouTube API Key](https://developers.google.com/youtube/v3/getting-started). You need to use the YouTube Data API v3, and create an API key.   
-   	The `apis.recaptcha.secret` value can be obtained by setting up a [ReCaptcha Site](https://www.google.com/recaptcha/admin).  
-   	The `apis.github` values can be obtained by setting up a [GitHub OAuth Application](https://github.com/settings/developers). You need to fill in some values to create the OAuth application. The homepage is the homepage of frontend. The authorization callback url is the backend url with `/auth/github/authorize/callback` added at the end. For example `http://localhost:8080/auth/github/authorize/callback`.  
-    *Discord is currently unsupported*  
-   	The `apis.discord.token` is the token for the Discord bot.  
-   	The `apis.discord.loggingServer` is the Discord logging server id.  
-   	The `apis.discord.loggingChannel` is the Discord logging channel id.  
-   	The `apis.mailgun` values can be obtained by setting up a [Mailgun account](http://www.mailgun.com/).  
-   	The `redis.url` url should be left alone for Docker, and changed to `redis://localhost:6379/0` for non-Docker.  
-   	The `redis.password` should be the Redis password you either put in your `startRedis.cmd` file for Windows, or `.env` for docker.  
-   	The `mongo.url` needs to have the proper password for the MongoDB musare user, and for non-Docker you need to replace `@musare:27017` with `@localhost:27017`.  
-   	The `cookie.domain` value should be the ip or address you use to access the site, without protocols (http/https), so for example `localhost`.   
-   	The `cookie.secure` value should be `true` for SSL connections, and `false` for normal http connections.  
+Values:  
+ The `secret` key can be whatever. It's used by express's session module.
+The `domain` should be the url where the site will be accessible from, usually `http://localhost` for non-Docker.
+The `serverDomain` should be the url where the backend will be accessible from, usually `http://localhost:8080` for non-Docker.
+The `serverPort` should be the port where the backend will listen on, usually `8080` for non-Docker.
+`isDocker` if you are using Docker or not.
+The `apis.youtube.key` value can be obtained by setting up a [YouTube API Key](https://developers.google.com/youtube/v3/getting-started). You need to use the YouTube Data API v3, and create an API key.
+The `apis.recaptcha.secret` value can be obtained by setting up a [ReCaptcha Site](https://www.google.com/recaptcha/admin).
+The `apis.github` values can be obtained by setting up a [GitHub OAuth Application](https://github.com/settings/developers). You need to fill in some values to create the OAuth application. The homepage is the homepage of frontend. The authorization callback url is the backend url with `/auth/github/authorize/callback` added at the end. For example `http://localhost:8080/auth/github/authorize/callback`.
+_Discord is currently unsupported_
+The `apis.discord.token` is the token for the Discord bot.
+The `apis.discord.loggingServer` is the Discord logging server id.
+The `apis.discord.loggingChannel` is the Discord logging channel id.
+The `apis.mailgun` values can be obtained by setting up a [Mailgun account](http://www.mailgun.com/).
+The `redis.url` url should be left alone for Docker, and changed to `redis://localhost:6379/0` for non-Docker.
+The `redis.password` should be the Redis password you either put in your `startRedis.cmd` file for Windows, or `.env` for docker.
+The `mongo.url` needs to have the proper password for the MongoDB musare user, and for non-Docker you need to replace `@musare:27017` with `@localhost:27017`.
+The `cookie.domain` value should be the ip or address you use to access the site, without protocols (http/https), so for example `localhost`.
+The `cookie.secure` value should be `true` for SSL connections, and `false` for normal http connections.
 
 4. `cp frontend/build/config/template.json frontend/build/config/default.json`
 
-	Values:  
-   	The `serverDomain` should be the url where the backend will be accessible from, usually `http://localhost:8080` for non-Docker.   
-   	The `recaptcha.key` value can be obtained by setting up a [ReCaptcha Site](https://www.google.com/recaptcha/admin).  
-   	The `cookie.domain` value should be the ip or address you use to access the site, without protocols (http/https), so for example `localhost`.   
-   	The `cookie.secure` value should be `true` for SSL connections, and `false` for normal http connections.  
+   Values:  
+   The `serverDomain` should be the url where the backend will be accessible from, usually `http://localhost:8080` for non-Docker.
+   The `recaptcha.key` value can be obtained by setting up a [ReCaptcha Site](https://www.google.com/recaptcha/admin).
+   The `cookie.domain` value should be the ip or address you use to access the site, without protocols (http/https), so for example `localhost`.
+   The `cookie.secure` value should be `true` for SSL connections, and `false` for normal http connections.
 
 Now you have different paths here.
 
 ### Docker
 
-*Configuration*
+_Configuration_
 
 To configure docker simply `cp .env.template .env` and configure the .env file to match your settings in `backend/config/default.json`
 
@@ -89,103 +96,102 @@ To configure docker simply `cp .env.template .env` and configure the .env file t
 
 2. Set up the MongoDB database
 
-	1. Disable auth
+   1. Disable auth
 
-		In `docker-compose.yml` remove `--auth` from the line `command: "--auth"` for mongo.
+      In `docker-compose.yml` remove `--auth` from the line `command: "--auth"` for mongo.
 
-	2. Start the database
+   2. Start the database
 
-		`docker-compose up mongo`
+      `docker-compose up mongo`
 
-	3. Connect to Mongo
+   3. Connect to Mongo
 
-		`docker-compose exec mongo mongo admin`
+      `docker-compose exec mongo mongo admin`
 
-	4. Create an admin user
+   4. Create an admin user
 
-		`db.createUser({user: 'admin', pwd: 'PASSWORD_HERE', roles: [{role: 'root', db: 'admin'}]})`
+      `db.createUser({user: 'admin', pwd: 'PASSWORD_HERE', roles: [{role: 'root', db: 'admin'}]})`
 
-	5. Connect to the Musare database
+   5. Connect to the Musare database
 
-		`use musare`
+      `use musare`
 
-	6. Create the musare user
+   6. Create the musare user
 
-		`db.createUser({user: 'musare', pwd: 'OTHER_PASSWORD_HERE', roles: [{role: 'readWrite', db: 'musare'}]})`
+      `db.createUser({user: 'musare', pwd: 'OTHER_PASSWORD_HERE', roles: [{role: 'readWrite', db: 'musare'}]})`
 
-	7. Exit
+   7. Exit
 
-		`exit`
+      `exit`
 
-	8. Add back authentication
+   8. Add back authentication
 
-		In `docker-compose.yml` add back `--auth` on the line `command: ""` for mongo.
+      In `docker-compose.yml` add back `--auth` on the line `command: ""` for mongo.
 
-
-3. Start the databases and tools in the background, as we usually don't need to monitor these for errors
+3) Start the databases and tools in the background, as we usually don't need to monitor these for errors
 
    `docker-compose up -d mongo mongoclient redis`
 
-4. Start the backend and frontend in the foreground, so we can watch for errors during development
+4) Start the backend and frontend in the foreground, so we can watch for errors during development
 
    `docker-compose up backend frontend`
 
-5. You should now be able to begin development! The backend is auto reloaded when
+5) You should now be able to begin development! The backend is auto reloaded when
    you make changes and the frontend is auto compiled and live reloaded by webpack
    when you make changes. You should be able to access Musare in your local browser
    at `http://<docker-machine-ip>:8080/` where `<docker-machine-ip>` can be found below:
 
-   * Docker for Windows / Mac: This is just `localhost`
+   - Docker for Windows / Mac: This is just `localhost`
 
-   * Docker ToolBox: The output of `docker-machine ip default`
+   - Docker ToolBox: The output of `docker-machine ip default`
 
 ### Non-docker
 
 Steps 1-4 are things you only have to do once. The steps to start servers follow.
 
-1. In the main folder, create a folder called `.database`
+1.  In the main folder, create a folder called `.database`
 
-2. Create a file called `startMongo.cmd` in the main folder with the contents:
+2.  Create a file called `startMongo.cmd` in the main folder with the contents:
 
-		"C:\Program Files\MongoDB\Server\3.2\bin\mongod.exe" --dbpath "D:\Programming\HTML\MusareNode\.database"
+        "C:\Program Files\MongoDB\Server\3.2\bin\mongod.exe" --dbpath "D:\Programming\HTML\MusareNode\.database"
 
-	Make sure to adjust your paths accordingly.
+    Make sure to adjust your paths accordingly.
 
-3. Set up the MongoDB database
+3.  Set up the MongoDB database
 
-	1. Start the database by executing the script `startMongo.cmd` you just made
+    1. Start the database by executing the script `startMongo.cmd` you just made
 
-	2. Connect to Mongo from a command prompt
+    2. Connect to Mongo from a command prompt
 
-		`mongo admin`
+       `mongo admin`
 
-	3. Create an admin user
+    3. Create an admin user
 
-		`db.createUser({user: 'admin', pwd: 'PASSWORD_HERE', roles: [{role: 'userAdminAnyDatabase', db: 'admin'}]})`
+       `db.createUser({user: 'admin', pwd: 'PASSWORD_HERE', roles: [{role: 'userAdminAnyDatabase', db: 'admin'}]})`
 
-	4. Connect to the Musare database
+    4. Connect to the Musare database
 
-		`use musare`
+       `use musare`
 
-	5. Create the musare user
+    5. Create the musare user
 
-		`db.createUser({user: 'musare', pwd: 'OTHER_PASSWORD_HERE', roles: [{role: 'readWrite', db: 'musare'}]})`
+       `db.createUser({user: 'musare', pwd: 'OTHER_PASSWORD_HERE', roles: [{role: 'readWrite', db: 'musare'}]})`
 
-	6. Exit
+    6. Exit
 
-		`exit`
+       `exit`
 
-	7. Add the authentication
+    7. Add the authentication
 
-		In `startMongo.cmd` add ` --auth` at the end of the first line
+       In `startMongo.cmd` add `--auth` at the end of the first line
 
-4. In the folder where you installed Redis, edit the `redis.windows.conf` file. In there, look for the property `notify-keyspace-events`. Make sure that property is uncommented and has the value `Ex`. It should look like `notify-keyspace-events Ex` when done.
+4.  In the folder where you installed Redis, edit the `redis.windows.conf` file. In there, look for the property `notify-keyspace-events`. Make sure that property is uncommented and has the value `Ex`. It should look like `notify-keyspace-events Ex` when done.
 
-5. Create a file called `startRedis.cmd` in the main folder with the contents:
+5.  Create a file called `startRedis.cmd` in the main folder with the contents:
 
-		"D:\Redis\redis-server.exe" "D:\Redis\redis.windows.conf" "--requirepass" "PASSWORD"
+        "D:\Redis\redis-server.exe" "D:\Redis\redis.windows.conf" "--requirepass" "PASSWORD"
 
-	And again, make sure that the paths lead to the proper config and executable. Replace `PASSWORD` with your Redis password.
+    And again, make sure that the paths lead to the proper config and executable. Replace `PASSWORD` with your Redis password.
 
 ### Non-docker start servers
 
@@ -197,7 +203,7 @@ Steps 1-4 are things you only have to do once. The steps to start servers follow
 
 1. Run `startRedis.cmd` and `startMongo.cmd` to start Redis and Mongo.
 
-2. In a command prompt with the pwd of frontend, run `npm run development-watch`
+2. In a command prompt with the pwd of frontend, run `yarn run development-watch`
 
 3. In a command prompt with the pwd of backend, run `nodemon`
 
@@ -220,24 +226,25 @@ of the following commands to give Docker Toolbox access to those files.
 
    `"C:\Program Files\Oracle\VirtualBox\VBoxManage.exe" sharedfolder add default --name "d/Projects/MusareNode" --hostpath "D:\Projects\MusareNode" --automount`
 
-2. Now start the machine back up and ssh into it
+1. Now start the machine back up and ssh into it
 
    `docker-machine start default && docker-machine ssh default`
 
-3. Tell boot2docker to mount our volume at startup, by appending to its startup script
-	```bash
-	sudo tee -a /mnt/sda1/var/lib/boot2docker/profile >/dev/null <<EOF
+1. Tell boot2docker to mount our volume at startup, by appending to its startup script
+
+   ```bash
+   sudo tee -a /mnt/sda1/var/lib/boot2docker/profile >/dev/null <<EOF
 
-	mkdir -p /d/Projects/MusareNode
-	mount -t vboxsf -o uid=1000,gid=50 d/Projects/MusareNode /d/Projects/MusareNode
-	EOF
-	```
+   mkdir -p /d/Projects/MusareNode
+   mount -t vboxsf -o uid=1000,gid=50 d/Projects/MusareNode /d/Projects/MusareNode
+   EOF
+   ```
 
-4. Restart the docker machine so that it uses the new shared folder
+1. Restart the docker machine so that it uses the new shared folder
 
    `docker-machine restart default`
 
-5. You now should be good to go!
+1. You now should be good to go!
 
 ### Fixing the "couldn't connect to docker daemon" error
 
@@ -253,17 +260,17 @@ Run this command in your shell. You will have to do this command for every shell
 
 2. Install nodemon globally
 
-   `npm install nodemon -g`
+   `yarn global add nodemon`
 
 3. Install webpack globally
 
-   `npm install webpack -g`
+   `yarn global add webpack`
 
 4. Install node-gyp globally (first check out https://github.com/nodejs/node-gyp#installation)
 
-   `npm install node-gyp -g`.
+   `yarn global add node-gyp`.
 
-5. In both `frontend` and `backend` folders, do `npm install`.
+5. In both `frontend` and `backend` folders, do `yarn install`.
 
 6. `nodemon backend/index.js`
 
@@ -272,8 +279,8 @@ Run this command in your shell. You will have to do this command for every shell
 You can call Toasts using our custom package, [`vue-roaster`](https://github.com/atjonathan/vue-roaster), using the following code:
 
 ```js
-import { Toast } from 'vue-roaster';
-Toast.methods.addToast('', 0);
+import { Toast } from "vue-roaster";
+Toast.methods.addToast("", 0);
 ```
 
 ### Set user role

+ 3 - 1
backend/logic/actions/apis.js

@@ -35,7 +35,9 @@ module.exports = {
 				next(null, JSON.parse(body));
 			}
 		], (err, data) => {
-			if (err) {
+			console.log(data.error);
+			if (err || data.error) {
+				if (!err) err = data.error.message;
 				err = utils.getError(err);
 				logger.error("APIS_SEARCH_YOUTUBE", `Searching youtube failed with query "${query}". "${err}"`);
 				return cb({status: 'failure', message: err});

+ 6 - 2
frontend/.babelrc

@@ -1,5 +1,9 @@
 {
-	"presets": ["es2015"],
-	"plugins": ["transform-runtime"],
+	"presets": ["@babel/preset-env"],
+	"plugins": [
+		"@babel/plugin-transform-runtime",
+		"@babel/plugin-syntax-dynamic-import",
+		"@babel/plugin-proposal-object-rest-spread"
+	],
 	"comments": false
 }

+ 2 - 2
frontend/.eslintrc

@@ -3,10 +3,10 @@
 		"indent": [2, "tab", { "SwitchCase": 1 }]
 	},
 	"parserOptions": {
-		"ecmaVersion": 6,
+		"ecmaVersion": 2018,
 		"sourceType": "module"
 	},
-	"plugins": [ "html" ],
+	"plugins": ["html"],
 	"settings": {
 		"html/indent": "tab",
 		"html/report-bad-indent": 2

+ 377 - 291
frontend/App.vue

@@ -1,298 +1,384 @@
 <template>
-	<banned v-if="banned"></banned>
-	<div v-else>
-		<h1 v-if="!socketConnected" class="alert">Could not connect to the server.</h1>
-		<router-view></router-view>
-		<toast></toast>
-		<what-is-new></what-is-new>
-		<mobile-alert></mobile-alert>
-		<login-modal v-if='isLoginActive'></login-modal>
-		<register-modal v-if='isRegisterActive'></register-modal>
-	</div>
+  <div>
+    <banned v-if="banned"></banned>
+    <div v-else>
+      <h1 v-if="!socketConnected" class="alert">Could not connect to the server.</h1>
+      <!-- should be a persistant toast -->
+      <router-view></router-view>
+      <toast></toast>
+      <what-is-new></what-is-new>
+      <mobile-alert></mobile-alert>
+      <login-modal v-if="modals.header.login"></login-modal>
+      <register-modal v-if="modals.header.register"></register-modal>
+    </div>
+  </div>
 </template>
 
 <script>
-	import { Toast } from 'vue-roaster';
-
-	import Banned from './components/pages/Banned.vue';
-	import WhatIsNew from './components/Modals/WhatIsNew.vue';
-	import MobileAlert from './components/Modals/MobileAlert.vue';
-	import LoginModal from './components/Modals/Login.vue';
-	import RegisterModal from './components/Modals/Register.vue';
-	import auth from './auth';
-	import io from './io';
-	import validation from './validation';
-
-	export default {
-		replace: false,
-		data() {
-			return {
-				banned: false,
-				ban: {},
-				register: {
-					email: '',
-					username: '',
-					password: ''
-				},
-				login: {
-					email: '',
-					password: ''
-				},
-				loggedIn: false,
-				role: '',
-				username: '',
-				userId: '',
-				isRegisterActive: false,
-				isLoginActive: false,
-				serverDomain: '',
-				socketConnected: true,
-				userIdMap: {},
-				currentlyGettingUsernameFrom: {}
-			}
-		},
-		methods: {
-			logout: function () {
-				let _this = this;
-				_this.socket.emit('users.logout', result => {
-					if (result.status === 'success') {
-						document.cookie = 'SID=;expires=Thu, 01 Jan 1970 00:00:01 GMT;';
-						location.reload();
-					} else Toast.methods.addToast(result.message, 4000);
-				});
-			},
-			'submitOnEnter': (cb, event) => {
-				if (event.which == 13) cb();
-			},
-			getUsernameFromId: function(userId) {
-			    if (typeof this.userIdMap[userId] !== 'string' && !this.currentlyGettingUsernameFrom[userId]) {
-					this.currentlyGettingUsernameFrom[userId] = true;
-			        io.getSocket(socket => {
-			            socket.emit('users.getUsernameFromId', userId, (data) => {
-			                if (data.status === 'success') this.$set(`userIdMap.Z${userId}`, data.data);
-							this.currentlyGettingUsernameFrom[userId] = false;
-						});
-					});
-				}
-			}
-		},
-		ready: function () {
-			let _this = this;
-			if (localStorage.getItem('github_redirect')) {
-			    this.$router.go(localStorage.getItem('github_redirect'));
-			    localStorage.removeItem('github_redirect');
-			}
-			auth.isBanned((banned, ban) => {
-				_this.ban = ban;
-				_this.banned = banned;
-			});
-			auth.getStatus((authenticated, role, username, userId) => {
-				_this.socket = window.socket;
-				_this.loggedIn = authenticated;
-				_this.role = role;
-				_this.username = username;
-				_this.userId = userId;
-			});
-			io.onConnect(true, () => {
-				_this.socketConnected = true;
-			});
-			io.onConnectError(true, () => {
-				_this.socketConnected = false;
-			});
-			io.onDisconnect(true, () => {
-				_this.socketConnected = false;
-			});
-			lofig.get('serverDomain', res => {
-				_this.serverDomain = res;
-			});
-			if (_this.$route.query.err) {
-				let err = _this.$route.query.err;
-				err = err.replace(new RegExp('<', 'g'), '&lt;').replace(new RegExp('>', 'g'), '&gt;');
-				Toast.methods.addToast(err, 20000);
-			}
-			io.getSocket(true, socket => {
-				socket.on('keep.event:user.session.removed', () => {
-					location.reload();
-				});
-			});
-
-		},
-		events: {
-			'register': function (recaptchaId) {
-				let { register: { email, username, password } } = this;
-				let _this = this;
-				if (!email || !username || !password) return Toast.methods.addToast('Please fill in all fields', 8000);
-
-
-				if (!validation.isLength(email, 3, 254)) return Toast.methods.addToast('Email must have between 3 and 254 characters.', 8000);
-				if (email.indexOf('@') !== email.lastIndexOf('@') || !validation.regex.emailSimple.test(email)) return Toast.methods.addToast('Invalid email format.', 8000);
-
-
-				if (!validation.isLength(username, 2, 32)) return Toast.methods.addToast('Username must have between 2 and 32 characters.', 8000);
-				if (!validation.regex.azAZ09_.test(username)) return Toast.methods.addToast('Invalid username format. Allowed characters: a-z, A-Z, 0-9 and _.', 8000);
-
-
-				if (!validation.isLength(password, 6, 200)) return Toast.methods.addToast('Password must have between 6 and 200 characters.', 8000);
-				if (!validation.regex.password.test(password)) return Toast.methods.addToast('Invalid password format. Must have one lowercase letter, one uppercase letter, one number and one special character.', 8000);
-
-				this.socket.emit('users.register', username, email, password, grecaptcha.getResponse(recaptchaId), result => {
-					if (result.status === 'success') {
-						Toast.methods.addToast(`You have successfully registered.`, 4000);
-						if (result.SID) {
-							lofig.get('cookie', cookie => {
-								let date = new Date();
-								date.setTime(new Date().getTime() + (2 * 365 * 24 * 60 * 60 * 1000));
-								let secure = (cookie.secure) ? 'secure=true; ' : '';
-								document.cookie = `SID=${result.SID}; expires=${date.toGMTString()}; domain=${cookie.domain}; ${secure}path=/`;
-								location.reload();
-							});
-						} else _this.$router.go('/login');
-					} else Toast.methods.addToast(result.message, 8000);
-				});
-			},
-			'login': function () {
-				let { login: { email, password } } = this;
-				let _this = this;
-				this.socket.emit('users.login', email, password, result => {
-					if (result.status === 'success') {
-						lofig.get('cookie', cookie => {
-							let date = new Date();
-							date.setTime(new Date().getTime() + (2 * 365 * 24 * 60 * 60 * 1000));
-							let secure = (cookie.secure) ? 'secure=true; ' : '';
-							let domain = '';
-							if (cookie.domain !== 'localhost') domain = ` domain=${cookie.domain};`;
-							document.cookie = `SID=${result.SID}; expires=${date.toGMTString()}; ${domain}${secure}path=/`;
-							Toast.methods.addToast(`You have been successfully logged in`, 2000);
-							location.reload();
-						});
-					} else Toast.methods.addToast(result.message, 2000);
-				});
-			},
-			'toggleModal': function (type) {
-				switch(type) {
-					case 'register':
-						this.isRegisterActive = !this.isRegisterActive;
-						break;
-					case 'login':
-						this.isLoginActive = !this.isLoginActive;
-						break;
-				}
-			},
-			'closeModal': function() {
-				this.$broadcast('closeModal');
-			}
-		},
-		components: { Toast, WhatIsNew, MobileAlert, LoginModal, RegisterModal, Banned }
-	}
+import { mapState, mapActions } from "vuex";
+
+import { Toast } from "vue-roaster";
+
+import Banned from "./components/pages/Banned.vue";
+import WhatIsNew from "./components/Modals/WhatIsNew.vue";
+import MobileAlert from "./components/Modals/MobileAlert.vue";
+import LoginModal from "./components/Modals/Login.vue";
+import RegisterModal from "./components/Modals/Register.vue";
+import auth from "./auth";
+import io from "./io";
+import validation from "./validation";
+
+export default {
+  replace: false,
+  data() {
+    return {
+      banned: false,
+      ban: {},
+      register: {
+        email: "",
+        username: "",
+        password: ""
+      },
+      login: {
+        email: "",
+        password: ""
+      },
+      loggedIn: false,
+      role: "",
+      username: "",
+      userId: "",
+      serverDomain: "",
+      socketConnected: true,
+      userIdMap: {},
+      currentlyGettingUsernameFrom: {}
+    };
+  },
+  computed: mapState({
+    modals: state => state.modals.modals,
+    currentlyActive: state => state.modals.currentlyActive
+  }),
+  methods: {
+    logout: function() {
+      let _this = this;
+      _this.socket.emit("users.logout", result => {
+        if (result.status === "success") {
+          document.cookie = "SID=;expires=Thu, 01 Jan 1970 00:00:01 GMT;";
+          location.reload();
+        } else Toast.methods.addToast(result.message, 4000);
+      });
+    },
+    submitOnEnter: (cb, event) => {
+      if (event.which == 13) cb();
+    },
+    getUsernameFromId: function(userId) {
+      // refactor
+      if (
+        typeof this.userIdMap[userId] !== "string" &&
+        !this.currentlyGettingUsernameFrom[userId]
+      ) {
+        this.currentlyGettingUsernameFrom[userId] = true;
+        io.getSocket(socket => {
+          socket.emit("users.getUsernameFromId", userId, res => {
+            if (res.status === "success") {
+              this.$set(this.userIdMap, `Z${userId}`, res.data);
+            }
+            this.currentlyGettingUsernameFrom[userId] = false;
+          });
+        });
+      }
+    },
+    ...mapActions("modals", ["closeCurrentModal"])
+  },
+  mounted: function() {
+    document.onkeydown = event => {
+      event = event || window.event;
+      if (
+        event.keyCode === 27 &&
+        Object.keys(this.currentlyActive).length !== 0
+      )
+        this.closeCurrentModal();
+    };
+
+    let _this = this;
+    if (localStorage.getItem("github_redirect")) {
+      this.$router.go(localStorage.getItem("github_redirect"));
+      localStorage.removeItem("github_redirect");
+    }
+    auth.isBanned((banned, ban) => {
+      _this.ban = ban;
+      _this.banned = banned;
+    });
+    auth.getStatus((authenticated, role, username, userId) => {
+      _this.socket = window.socket;
+      _this.loggedIn = authenticated;
+      _this.role = role;
+      _this.username = username;
+      _this.userId = userId;
+    });
+    io.onConnect(true, () => {
+      _this.socketConnected = true;
+    });
+    io.onConnectError(true, () => {
+      _this.socketConnected = false;
+    });
+    io.onDisconnect(true, () => {
+      _this.socketConnected = false;
+    });
+    lofig.get("serverDomain", res => {
+      _this.serverDomain = res;
+    });
+    if (_this.$route.query.err) {
+      let err = _this.$route.query.err;
+      err = err
+        .replace(new RegExp("<", "g"), "&lt;")
+        .replace(new RegExp(">", "g"), "&gt;");
+      Toast.methods.addToast(err, 20000);
+    }
+    io.getSocket(true, socket => {
+      socket.on("keep.event:user.session.removed", () => {
+        location.reload();
+      });
+    });
+  },
+  events: {
+    register: function(recaptchaId) {
+      let {
+        register: { email, username, password }
+      } = this;
+      let _this = this;
+      if (!email || !username || !password)
+        return Toast.methods.addToast("Please fill in all fields", 8000);
+
+      if (!validation.isLength(email, 3, 254))
+        return Toast.methods.addToast(
+          "Email must have between 3 and 254 characters.",
+          8000
+        );
+      if (
+        email.indexOf("@") !== email.lastIndexOf("@") ||
+        !validation.regex.emailSimple.test(email)
+      )
+        return Toast.methods.addToast("Invalid email format.", 8000);
+
+      if (!validation.isLength(username, 2, 32))
+        return Toast.methods.addToast(
+          "Username must have between 2 and 32 characters.",
+          8000
+        );
+      if (!validation.regex.azAZ09_.test(username))
+        return Toast.methods.addToast(
+          "Invalid username format. Allowed characters: a-z, A-Z, 0-9 and _.",
+          8000
+        );
+
+      if (!validation.isLength(password, 6, 200))
+        return Toast.methods.addToast(
+          "Password must have between 6 and 200 characters.",
+          8000
+        );
+      if (!validation.regex.password.test(password))
+        return Toast.methods.addToast(
+          "Invalid password format. Must have one lowercase letter, one uppercase letter, one number and one special character.",
+          8000
+        );
+
+      this.socket.emit(
+        "users.register",
+        username,
+        email,
+        password,
+        grecaptcha.getResponse(recaptchaId),
+        result => {
+          if (result.status === "success") {
+            Toast.methods.addToast(`You have successfully registered.`, 4000);
+            if (result.SID) {
+              lofig.get("cookie", cookie => {
+                let date = new Date();
+                date.setTime(
+                  new Date().getTime() + 2 * 365 * 24 * 60 * 60 * 1000
+                );
+                let secure = cookie.secure ? "secure=true; " : "";
+                document.cookie = `SID=${
+                  result.SID
+                }; expires=${date.toGMTString()}; domain=${
+                  cookie.domain
+                }; ${secure}path=/`;
+                location.reload();
+              });
+            } else _this.$router.go("/login");
+          } else Toast.methods.addToast(result.message, 8000);
+        }
+      );
+    },
+    login: function() {
+      let {
+        login: { email, password }
+      } = this;
+      let _this = this;
+      this.socket.emit("users.login", email, password, result => {
+        if (result.status === "success") {
+          lofig.get("cookie", cookie => {
+            let date = new Date();
+            date.setTime(new Date().getTime() + 2 * 365 * 24 * 60 * 60 * 1000);
+            let secure = cookie.secure ? "secure=true; " : "";
+            let domain = "";
+            if (cookie.domain !== "localhost")
+              domain = ` domain=${cookie.domain};`;
+            document.cookie = `SID=${
+              result.SID
+            }; expires=${date.toGMTString()}; ${domain}${secure}path=/`;
+            Toast.methods.addToast(
+              `You have been successfully logged in`,
+              2000
+            );
+            location.reload();
+          });
+        } else Toast.methods.addToast(result.message, 2000);
+      });
+    }
+  },
+  components: {
+    Toast,
+    WhatIsNew,
+    MobileAlert,
+    LoginModal,
+    RegisterModal,
+    Banned
+  }
+};
 </script>
 
-<style type='scss'>
-	.center { text-align: center; }
-
-	#toast-container { z-index: 10000 !important; }
-
-	html {
-		overflow: auto !important;
-	}
-
-	.modal-card {
-		margin: 0 !important;
-	}
-
-	.absolute-a {
-		width: 100%;
-		height: 100%;
-		position: absolute;
-		top: 0;
-		left: 0;
-	}
-
-	.alert {
-		padding: 20px;
-		color: white;
-		background-color: red;
-		position: fixed;
-		top: 50px;
-		right: 50px;
-		font-size: 2em;
-		border-radius: 5px;
-		z-index: 10000000;
-	}
-
-	.tooltip {
-		position: relative;
-
-		&:after {
-			 position: absolute;
-			 min-width: 80px;
-			 margin-left: -75%;
-			 text-align: center;
-			 padding: 7.5px 6px;
-			 border-radius: 2px;
-			 background-color: #323232;
-			 font-size: .9em;
-			 color: #fff;
-			 content: attr(data-tooltip);
-			 opacity: 0;
-			 transition: all .2s ease-in-out .1s;
-			 visibility: hidden;
-		}
-
-		&:hover:after {
-			 opacity: 1;
-			 visibility: visible;
-		}
-	}
-
-	.tooltip-top {
-		&:after {
-			 bottom: 150%;
-		}
-
-		&:hover {
-			&:after { bottom: 120%; }
-		}
-	}
-
-
-	.tooltip-bottom {
-		&:after {
-			 top: 155%;
-		}
-
-		&:hover {
-			&:after { top: 125%; }
-		}
-	}
-
-	.tooltip-left {
-		&:after {
-			 bottom: -10px;
-			 right: 130%;
-			 min-width: 100px;
-		}
-
-		&:hover {
-			&:after { right: 110%; }
-		}
-	}
-
-	.tooltip-right {
-		&:after {
-			 bottom: -10px;
-			 left: 190%;
-			 min-width: 100px;
-		}
-
-		&:hover {
-			 &:after { left: 200%; }
-		}
-	}
-
-	.button:focus, .button:active { border-color: #dbdbdb !important; }
-	.input:focus, .input:active { border-color: #03a9f4 !important; }
-	button.delete:focus { background-color: rgba(10, 10, 10, 0.3); }
-
-	.tag { padding-right: 6px !important; }
-
-	.button.is-success { background-color: #00B16A !important; }
+<style lang='scss'>
+.center {
+  text-align: center;
+}
+
+#toast-container {
+  z-index: 10000 !important;
+}
+
+html {
+  overflow: auto !important;
+}
+
+.modal-card {
+  margin: 0 !important;
+}
+
+.absolute-a {
+  width: 100%;
+  height: 100%;
+  position: absolute;
+  top: 0;
+  left: 0;
+}
+
+.alert {
+  padding: 20px;
+  color: white;
+  background-color: red;
+  position: fixed;
+  top: 50px;
+  right: 50px;
+  font-size: 2em;
+  border-radius: 5px;
+  z-index: 10000000;
+}
+
+.tooltip {
+  position: relative;
+
+  &:after {
+    position: absolute;
+    min-width: 80px;
+    margin-left: -75%;
+    text-align: center;
+    padding: 7.5px 6px;
+    border-radius: 2px;
+    background-color: #323232;
+    font-size: 0.9em;
+    color: #fff;
+    content: attr(data-tooltip);
+    opacity: 0;
+    transition: all 0.2s ease-in-out 0.1s;
+    visibility: hidden;
+  }
+
+  &:hover:after {
+    opacity: 1;
+    visibility: visible;
+  }
+}
+
+.tooltip-top {
+  &:after {
+    bottom: 150%;
+  }
+
+  &:hover {
+    &:after {
+      bottom: 120%;
+    }
+  }
+}
+
+.tooltip-bottom {
+  &:after {
+    top: 155%;
+  }
+
+  &:hover {
+    &:after {
+      top: 125%;
+    }
+  }
+}
+
+.tooltip-left {
+  &:after {
+    bottom: -10px;
+    right: 130%;
+    min-width: 100px;
+  }
+
+  &:hover {
+    &:after {
+      right: 110%;
+    }
+  }
+}
+
+.tooltip-right {
+  &:after {
+    bottom: -10px;
+    left: 190%;
+    min-width: 100px;
+  }
+
+  &:hover {
+    &:after {
+      left: 200%;
+    }
+  }
+}
+
+.button:focus,
+.button:active {
+  border-color: #dbdbdb !important;
+}
+.input:focus,
+.input:active {
+  border-color: #03a9f4 !important;
+}
+button.delete:focus {
+  background-color: rgba(10, 10, 10, 0.3);
+}
+
+.tag {
+  padding-right: 6px !important;
+}
+
+.button.is-success {
+  background-color: #00b16a !important;
+}
 </style>

+ 4 - 3
frontend/Dockerfile

@@ -3,16 +3,17 @@ FROM node
 RUN apt-get update
 RUN apt-get install nginx -y
 
-RUN npm install -g webpack@1.14.0
+RUN npm install -g yarn
+RUN yarn global add webpack@1.14.0
 
 RUN mkdir -p /opt
 WORKDIR /opt
 ADD package.json /opt/package.json
 
-RUN npm install
+RUN yarn install
 
 RUN mkdir -p /run/nginx
 
 EXPOSE 80
 
-CMD nginx -c /opt/app/nginx.conf; cd /opt/app; npm run development-watch
+CMD nginx -c /opt/app/nginx.conf; cd /opt/app; yarn run development-watch

+ 1 - 0
frontend/build/index.tpl.html

@@ -51,6 +51,7 @@
 	</script>
 </head>
 <body>
+	<div id="root"></div>
 	<script src='https://www.google.com/recaptcha/api.js'></script>
 </body>
 </html>

+ 21 - 19
frontend/components/404.vue

@@ -1,25 +1,27 @@
 <template>
-	<div class="wrapper">
-		<h3><strong>404</strong>&nbsp;Not Found</h3>
-		<button class="button is-black" @click="$router.go('/')">Back to Home</button>
-	</div>
+  <div class="wrapper">
+    <h3>
+      <strong>404</strong>&nbsp;Not Found
+    </h3>
+    <router-link class="button is-black" to="/">Back to Home</router-link>
+  </div>
 </template>
 
-<style type="scss" scoped>
-	* {
-		margin: 0;
-		padding: 0;
-	}
+<style lang="scss" scoped>
+* {
+  margin: 0;
+  padding: 0;
+}
 
-	.wrapper {
-		height: 100vh;
-		display: flex;
-		align-items: center;
-		justify-content: center;
-		flex-direction: column;
-	}
+.wrapper {
+  height: 100vh;
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  flex-direction: column;
+}
 
-	button {
-		margin-top: 15px;
-	}
+a {
+  margin-top: 15px;
+}
 </style>

+ 288 - 0
frontend/components/Admin/EditStation.vue

@@ -0,0 +1,288 @@
+<template>
+  <modal title="Edit Station">
+    <template v-slot:body>
+      <label class="label">Name</label>
+      <p class="control">
+        <input class="input" type="text" placeholder="Station Name" v-model="editing.name" />
+      </p>
+      <label class="label">Display name</label>
+      <p class="control">
+        <input
+          class="input"
+          type="text"
+          placeholder="Station Display Name"
+          v-model="editing.displayName"
+        />
+      </p>
+      <label class="label">Description</label>
+      <p class="control">
+        <input
+          class="input"
+          type="text"
+          placeholder="Station Description"
+          v-model="editing.description"
+        />
+      </p>
+      <label class="label">Privacy</label>
+      <p class="control">
+        <span class="select">
+          <select v-model="editing.privacy">
+            <option value="public">Public</option>
+            <option value="unlisted">Unlisted</option>
+            <option value="private">Private</option>
+          </select>
+        </span>
+      </p>
+      <br />
+      <p class="control">
+        <label class="checkbox party-mode-inner">
+          <input type="checkbox" v-model="editing.partyMode" />
+          &nbsp;Party mode
+        </label>
+      </p>
+      <small>With party mode enabled, people can add songs to a queue that plays. With party mode disabled you can play a private playlist on loop.</small>
+      <br />
+      <div v-if="station.partyMode">
+        <br />
+        <br />
+        <label class="label">Queue lock</label>
+        <small
+          v-if="station.partyMode"
+        >With the queue locked, only owners (you) can add songs to the queue.</small>
+        <br />
+        <button
+          class="button is-danger"
+          v-if="!station.locked"
+          v-on:click="$parent.toggleLock()"
+        >Lock the queue</button>
+        <button
+          class="button is-success"
+          v-if="station.locked"
+          v-on:click="$parent.toggleLock()"
+        >Unlock the queue</button>
+      </div>
+    </template>
+    <template v-slot:footer>
+      <button class="button is-success" v-on:click="update()">Update Settings</button>
+      <button
+        class="button is-danger"
+        v-on:click="deleteStation()"
+        v-if="station.type === 'community'"
+      >Delete station</button>
+    </template>
+  </modal>
+</template>
+
+<script>
+import { mapState } from "vuex";
+
+import { Toast } from "vue-roaster";
+import Modal from "../Modals/Modal.vue";
+import io from "../../io";
+import validation from "../../validation";
+
+export default {
+  computed: mapState("admin/stations", {
+    station: state => state.station,
+    editing: state => state.editing
+  }),
+  methods: {
+    update: function() {
+      if (this.station.name !== this.editing.name) this.updateName();
+      if (this.station.displayName !== this.editing.displayName)
+        this.updateDisplayName();
+      if (this.station.description !== this.editing.description)
+        this.updateDescription();
+      if (this.station.privacy !== this.editing.privacy) this.updatePrivacy();
+      if (this.station.partyMode !== this.editing.partyMode)
+        this.updatePartyMode();
+    },
+    updateName: function() {
+      const name = this.editing.name;
+      if (!validation.isLength(name, 2, 16))
+        return Toast.methods.addToast(
+          "Name must have between 2 and 16 characters.",
+          8000
+        );
+      if (!validation.regex.az09_.test(name))
+        return Toast.methods.addToast(
+          "Invalid name format. Allowed characters: a-z, 0-9 and _.",
+          8000
+        );
+
+      this.socket.emit("stations.updateName", this.editing._id, name, res => {
+        if (res.status === "success") {
+          if (this.station) this.station.name = name;
+          else {
+            this.$parent.stations.forEach((station, index) => {
+              if (station._id === this.editing._id)
+                return (this.$parent.stations[index].name = name);
+            });
+          }
+        }
+        Toast.methods.addToast(res.message, 8000);
+      });
+    },
+    updateDisplayName: function() {
+      let _this = this;
+
+      const displayName = this.editing.displayName;
+      if (!validation.isLength(displayName, 2, 32))
+        return Toast.methods.addToast(
+          "Display name must have between 2 and 32 characters.",
+          8000
+        );
+      if (!validation.regex.azAZ09_.test(displayName))
+        return Toast.methods.addToast(
+          "Invalid display name format. Allowed characters: a-z, A-Z, 0-9 and _.",
+          8000
+        );
+
+      this.socket.emit(
+        "stations.updateDisplayName",
+        this.editing._id,
+        displayName,
+        res => {
+          if (res.status === "success") {
+            if (this.station) this.station.displayName = displayName;
+            else {
+              this.$parent.stations.forEach((station, index) => {
+                if (station._id === this.editing._id)
+                  return (this.$parent.stations[
+                    index
+                  ].displayName = displayName);
+              });
+            }
+          }
+          Toast.methods.addToast(res.message, 8000);
+        }
+      );
+    },
+    updateDescription: function() {
+      let _this = this;
+
+      const description = this.editing.description;
+      if (!validation.isLength(description, 2, 200))
+        return Toast.methods.addToast(
+          "Description must have between 2 and 200 characters.",
+          8000
+        );
+      let characters = description.split("");
+      characters = characters.filter(character => {
+        return character.charCodeAt(0) === 21328;
+      });
+      if (characters.length !== 0)
+        return Toast.methods.addToast(
+          "Invalid description format. Swastika's are not allowed.",
+          8000
+        );
+
+      this.socket.emit(
+        "stations.updateDescription",
+        this.editing._id,
+        description,
+        res => {
+          if (res.status === "success") {
+            if (_this.station) _this.station.description = description;
+            else {
+              _this.$parent.stations.forEach((station, index) => {
+                if (station._id === station._id)
+                  return (_this.$parent.stations[
+                    index
+                  ].description = description);
+              });
+            }
+            return Toast.methods.addToast(res.message, 4000);
+          }
+          Toast.methods.addToast(res.message, 8000);
+        }
+      );
+    },
+    updatePrivacy: function() {
+      let _this = this;
+      this.socket.emit(
+        "stations.updatePrivacy",
+        this.editing._id,
+        this.editing.privacy,
+        res => {
+          if (res.status === "success") {
+            if (_this.station) _this.station.privacy = _this.editing.privacy;
+            else {
+              _this.$parent.stations.forEach((station, index) => {
+                if (station._id === station._id)
+                  return (_this.$parent.stations[index].privacy =
+                    _this.editing.privacy);
+              });
+            }
+            return Toast.methods.addToast(res.message, 4000);
+          }
+          Toast.methods.addToast(res.message, 8000);
+        }
+      );
+    },
+    updatePartyMode: function() {
+      let _this = this;
+      this.socket.emit(
+        "stations.updatePartyMode",
+        this.editing._id,
+        this.editing.partyMode,
+        res => {
+          if (res.status === "success") {
+            if (_this.station)
+              _this.station.partyMode = _this.editing.partyMode;
+            else {
+              _this.$parent.stations.forEach((station, index) => {
+                if (station._id === station._id)
+                  return (_this.$parent.stations[index].partyMode =
+                    _this.editing.partyMode);
+              });
+            }
+            return Toast.methods.addToast(res.message, 4000);
+          }
+          Toast.methods.addToast(res.message, 8000);
+        }
+      );
+    },
+    deleteStation: function() {
+      let _this = this;
+      this.socket.emit("stations.remove", this.editing._id, res => {
+        Toast.methods.addToast(res.message, 8000);
+      });
+    }
+  },
+  mounted: function() {
+    let _this = this;
+    io.getSocket(socket => (_this.socket = socket));
+  },
+  components: { Modal }
+};
+</script>
+
+<style lang='scss' scoped>
+.controls {
+  display: flex;
+
+  a {
+    display: flex;
+    align-items: center;
+  }
+}
+
+.table {
+  margin-bottom: 0;
+}
+
+h5 {
+  padding: 20px 0;
+}
+
+.party-mode-inner,
+.party-mode-outer {
+  display: flex;
+  align-items: center;
+}
+
+.select:after {
+  border-color: #029ce3;
+}
+</style>

+ 293 - 219
frontend/components/Admin/News.vue

@@ -1,230 +1,304 @@
 <template>
-	<div class='container'>
-		<table class='table is-striped'>
-			<thead>
-				<tr>
-					<td>Title</td>
-					<td>Description</td>
-					<td>Bugs</td>
-					<td>Features</td>
-					<td>Improvements</td>
-					<td>Upcoming</td>
-					<td>Options</td>
-				</tr>
-			</thead>
-			<tbody>
-				<tr v-for='(index, news) in news' track-by='$index'>
-					<td>
-						<strong>{{ news.title }}</strong>
-					</td>
-					<td>{{ news.description }}</td>
-					<td>{{ news.bugs.join(', ') }}</td>
-					<td>{{ news.features.join(', ') }}</td>
-					<td>{{ news.improvements.join(', ') }}</td>
-					<td>{{ news.upcoming.join(', ') }}</td>
-					<td>
-						<button class='button is-primary' @click='editNews(news)'>Edit</button>
-						<button class='button is-danger' @click='removeNews(news)'>Remove</button>
-					</td>
-				</tr>
-			</tbody>
-		</table>
-
-		<div class='card is-fullwidth'>
-			<header class='card-header'>
-				<p class='card-header-title'>Create News</p>
-			</header>
-			<div class='card-content'>
-				<div class='content'>
-
-					<label class='label'>Title & Description</label>
-					<div class='control is-horizontal'>
-						<div class='control is-grouped'>
-							<p class='control is-expanded'>
-								<input class='input' type='text' placeholder='Title' v-model='creating.title'>
-							</p>
-							<p class='control is-expanded'>
-								<input class='input' type='text' placeholder='Short description' v-model='creating.description'>
-							</p>
-						</div>
-					</div>
-
-					<div class="columns">
-						<div class="column">
-							<label class='label'>Bugs</label>
-							<p class='control has-addons'>
-								<input class='input' id='new-bugs' type='text' placeholder='Bug' v-on:keyup.enter='addChange("bugs")'>
-								<a class='button is-info' href='#' @click='addChange("bugs")'>Add</a>
-							</p>
-							<span class='tag is-info' v-for='(index, bug) in creating.bugs' track-by='$index'>
-								{{ bug }}
-								<button class='delete is-info' @click='removeChange("bugs", index)'></button>
-							</span>
-						</div>
-						<div class="column">
-							<label class='label'>Features</label>
-							<p class='control has-addons'>
-								<input class='input' id='new-features' type='text' placeholder='Feature' v-on:keyup.enter='addChange("features")'>
-								<a class='button is-info' href='#' @click='addChange("features")'>Add</a>
-							</p>
-							<span class='tag is-info' v-for='(index, feature) in creating.features' track-by='$index'>
-								{{ feature }}
-								<button class='delete is-info' @click='removeChange("features", index)'></button>
-							</span>
-						</div>
-					</div>
-
-					<div class="columns">
-						<div class="column">
-							<label class='label'>Improvements</label>
-							<p class='control has-addons'>
-								<input class='input' id='new-improvements' type='text' placeholder='Improvement' v-on:keyup.enter='addChange("improvements")'>
-								<a class='button is-info' href='#' @click='addChange("improvements")'>Add</a>
-							</p>
-							<span class='tag is-info' v-for='(index, improvement) in creating.improvements' track-by='$index'>
-								{{ improvement }}
-								<button class='delete is-info' @click='removeChange("improvements", index)'></button>
-							</span>
-						</div>
-						<div class="column">
-							<label class='label'>Upcoming</label>
-							<p class='control has-addons'>
-								<input class='input' id='new-upcoming' type='text' placeholder='Upcoming' v-on:keyup.enter='addChange("upcoming")'>
-								<a class='button is-info' href='#' @click='addChange("upcoming")'>Add</a>
-							</p>
-							<span class='tag is-info' v-for='(index, upcoming) in creating.upcoming' track-by='$index'>
-								{{ upcoming }}
-								<button class='delete is-info' @click='removeChange("upcoming", index)'></button>
-							</span>
-						</div>
-					</div>
-
-				</div>
-			</div>
-			<footer class='card-footer'>
-				<a class='card-footer-item' @click='createNews()' href='#'>Create</a>
-			</footer>
-		</div>
-	</div>
-
-	<edit-news v-if='modals.editNews'></edit-news>
+  <div>
+    <div class="container">
+      <table class="table is-striped">
+        <thead>
+          <tr>
+            <td>Title</td>
+            <td>Description</td>
+            <td>Bugs</td>
+            <td>Features</td>
+            <td>Improvements</td>
+            <td>Upcoming</td>
+            <td>Options</td>
+          </tr>
+        </thead>
+        <tbody>
+          <tr v-for="(news, index) in news" :key="index">
+            <td>
+              <strong>{{ news.title }}</strong>
+            </td>
+            <td>{{ news.description }}</td>
+            <td>{{ news.bugs.join(', ') }}</td>
+            <td>{{ news.features.join(', ') }}</td>
+            <td>{{ news.improvements.join(', ') }}</td>
+            <td>{{ news.upcoming.join(', ') }}</td>
+            <td>
+              <button class="button is-primary" v-on:click="editNews(news)">Edit</button>
+              <button class="button is-danger" v-on:click="removeNews(news)">Remove</button>
+            </td>
+          </tr>
+        </tbody>
+      </table>
+
+      <div class="card is-fullwidth">
+        <header class="card-header">
+          <p class="card-header-title">Create News</p>
+        </header>
+        <div class="card-content">
+          <div class="content">
+            <label class="label">Title & Description</label>
+            <div class="control is-horizontal">
+              <div class="control is-grouped">
+                <p class="control is-expanded">
+                  <input class="input" type="text" placeholder="Title" v-model="creating.title" />
+                </p>
+                <p class="control is-expanded">
+                  <input
+                    class="input"
+                    type="text"
+                    placeholder="Short description"
+                    v-model="creating.description"
+                  />
+                </p>
+              </div>
+            </div>
+
+            <div class="columns">
+              <div class="column">
+                <label class="label">Bugs</label>
+                <p class="control has-addons">
+                  <input
+                    class="input"
+                    id="new-bugs"
+                    type="text"
+                    placeholder="Bug"
+                    v-on:keyup.enter="addChange('bugs')"
+                  />
+                  <a class="button is-info" href="#" v-on:click="addChange('bugs')">Add</a>
+                </p>
+                <span class="tag is-info" v-for="(bug, index) in creating.bugs" :key="index">
+                  {{ bug }}
+                  <button class="delete is-info" v-on:click="removeChange('bugs', index)"></button>
+                </span>
+              </div>
+              <div class="column">
+                <label class="label">Features</label>
+                <p class="control has-addons">
+                  <input
+                    class="input"
+                    id="new-features"
+                    type="text"
+                    placeholder="Feature"
+                    v-on:keyup.enter="addChange('features')"
+                  />
+                  <a class="button is-info" href="#" v-on:click="addChange('features')">Add</a>
+                </p>
+                <span
+                  class="tag is-info"
+                  v-for="(feature, index) in creating.features"
+                  :key="index"
+                >
+                  {{ feature }}
+                  <button
+                    class="delete is-info"
+                    v-on:click="removeChange('features', index)"
+                  ></button>
+                </span>
+              </div>
+            </div>
+
+            <div class="columns">
+              <div class="column">
+                <label class="label">Improvements</label>
+                <p class="control has-addons">
+                  <input
+                    class="input"
+                    id="new-improvements"
+                    type="text"
+                    placeholder="Improvement"
+                    v-on:keyup.enter="addChange('improvements')"
+                  />
+                  <a class="button is-info" href="#" v-on:click="addChange('improvements')">Add</a>
+                </p>
+                <span
+                  class="tag is-info"
+                  v-for="(improvement, index) in creating.improvements"
+                  :key="index"
+                >
+                  {{ improvement }}
+                  <button
+                    class="delete is-info"
+                    v-on:click="removeChange('improvements', index)"
+                  ></button>
+                </span>
+              </div>
+              <div class="column">
+                <label class="label">Upcoming</label>
+                <p class="control has-addons">
+                  <input
+                    class="input"
+                    id="new-upcoming"
+                    type="text"
+                    placeholder="Upcoming"
+                    v-on:keyup.enter="addChange('upcoming')"
+                  />
+                  <a class="button is-info" href="#" v-on:click="addChange('upcoming')">Add</a>
+                </p>
+                <span
+                  class="tag is-info"
+                  v-for="(upcoming, index) in creating.upcoming"
+                  :key="index"
+                >
+                  {{ upcoming }}
+                  <button
+                    class="delete is-info"
+                    v-on:click="removeChange('upcoming', index)"
+                  ></button>
+                </span>
+              </div>
+            </div>
+          </div>
+        </div>
+        <footer class="card-footer">
+          <a class="card-footer-item" v-on:click="createNews()" href="#">Create</a>
+        </footer>
+      </div>
+    </div>
+
+    <edit-news v-if="modals.editNews"></edit-news>
+  </div>
 </template>
 
 <script>
-	import { Toast } from 'vue-roaster';
-	import io from '../../io';
-
-	import EditNews from '../Modals/EditNews.vue';
-
-	export default {
-		components: { EditNews },
-		data() {
-			return {
-				modals: { editNews: false },
-				news: [],
-				creating: {
-					title: '',
-					description: '',
-					bugs: [],
-					features: [],
-					improvements: [],
-					upcoming: []
-				},
-				editing: {}
-			}
-		},
-		methods: {
-			toggleModal: function () {
-				this.modals.editNews = !this.modals.editNews;
-			},
-			createNews: function () {
-				let _this = this;
-
-				let { creating: { bugs, features, improvements, upcoming } } = this;
-
-				if (this.creating.title === '') return Toast.methods.addToast('Field (Title) cannot be empty', 3000);
-				if (this.creating.description === '') return Toast.methods.addToast('Field (Description) cannot be empty', 3000);
-				if (
-					bugs.length <= 0 && features.length <= 0 &&
-					improvements.length <= 0 && upcoming.length <= 0
-				) return Toast.methods.addToast('You must have at least one News Item', 3000);
-
-				_this.socket.emit('news.create', _this.creating, result => {
-					Toast.methods.addToast(result.message, 4000);
-					if (result.status == 'success') _this.creating = {
-						title: '',
-						description: '',
-						bugs: [],
-						features: [],
-						improvements: [],
-						upcoming: []
-					}
-				});
-			},
-			removeNews: function (news) {
-				this.socket.emit('news.remove', news, res => {
-					Toast.methods.addToast(res.message, 8000);
-				});
-			},
-			editNews: function (news) {
-				this.editing = news;
-				this.toggleModal();
-			},
-			updateNews: function (close) {
-				let _this = this;
-				this.socket.emit('news.update', _this.editing._id, _this.editing, res => {
-					Toast.methods.addToast(res.message, 4000);
-					if (res.status === 'success') {
-						if (close) _this.toggleModal();
-					}
-				});
-			},
-			addChange: function (type) {
-				let change = $(`#new-${type}`).val().trim();
-
-				if (this.creating[type].indexOf(change) !== -1) return Toast.methods.addToast(`Tag already exists`, 3000);
-
-				if (change) {
-					$(`#new-${type}`).val('');
-					this.creating[type].push(change);
-				}
-				else Toast.methods.addToast(`${type} cannot be empty`, 3000);
-			},
-			removeChange: function (type, index) {
-				this.creating[type].splice(index, 1);
-			},
-			init: function () {
-				this.socket.emit('apis.joinAdminRoom', 'news', data => {});
-			}
-		},
-		ready: function () {
-			let _this = this;
-			io.getSocket((socket) => {
-				_this.socket = socket;
-				_this.socket.emit('news.index', result => {
-					_this.news = result.data;
-				});
-				_this.socket.on('event:admin.news.created', news => {
-					_this.news.unshift(news);
-				});
-				_this.socket.on('event:admin.news.removed', news => {
-					_this.news = _this.news.filter(item => item._id !== news._id);
-				});
-				if (_this.socket.connected) _this.init();
-				io.onConnect(() => {
-					_this.init();
-				});
-			});
-		}
-	}
+import { Toast } from "vue-roaster";
+import io from "../../io";
+
+import EditNews from "../Modals/EditNews.vue";
+
+export default {
+  components: { EditNews },
+  data() {
+    return {
+      modals: { editNews: false },
+      news: [],
+      creating: {
+        title: "",
+        description: "",
+        bugs: [],
+        features: [],
+        improvements: [],
+        upcoming: []
+      },
+      editing: {}
+    };
+  },
+  methods: {
+    toggleModal: function() {
+      this.modals.editNews = !this.modals.editNews;
+    },
+    createNews: function() {
+      let _this = this;
+
+      let {
+        creating: { bugs, features, improvements, upcoming }
+      } = this;
+
+      if (this.creating.title === "")
+        return Toast.methods.addToast("Field (Title) cannot be empty", 3000);
+      if (this.creating.description === "")
+        return Toast.methods.addToast(
+          "Field (Description) cannot be empty",
+          3000
+        );
+      if (
+        bugs.length <= 0 &&
+        features.length <= 0 &&
+        improvements.length <= 0 &&
+        upcoming.length <= 0
+      )
+        return Toast.methods.addToast(
+          "You must have at least one News Item",
+          3000
+        );
+
+      _this.socket.emit("news.create", _this.creating, result => {
+        Toast.methods.addToast(result.message, 4000);
+        if (result.status == "success")
+          _this.creating = {
+            title: "",
+            description: "",
+            bugs: [],
+            features: [],
+            improvements: [],
+            upcoming: []
+          };
+      });
+    },
+    removeNews: function(news) {
+      this.socket.emit("news.remove", news, res => {
+        Toast.methods.addToast(res.message, 8000);
+      });
+    },
+    editNews: function(news) {
+      this.editing = news;
+      this.toggleModal();
+    },
+    updateNews: function(close) {
+      let _this = this;
+      this.socket.emit("news.update", _this.editing._id, _this.editing, res => {
+        Toast.methods.addToast(res.message, 4000);
+        if (res.status === "success") {
+          if (close) _this.toggleModal();
+        }
+      });
+    },
+    addChange: function(type) {
+      let change = $(`#new-${type}`)
+        .val()
+        .trim();
+
+      if (this.creating[type].indexOf(change) !== -1)
+        return Toast.methods.addToast(`Tag already exists`, 3000);
+
+      if (change) {
+        $(`#new-${type}`).val("");
+        this.creating[type].push(change);
+      } else Toast.methods.addToast(`${type} cannot be empty`, 3000);
+    },
+    removeChange: function(type, index) {
+      this.creating[type].splice(index, 1);
+    },
+    init: function() {
+      this.socket.emit("apis.joinAdminRoom", "news", data => {});
+    }
+  },
+  mounted: function() {
+    let _this = this;
+    io.getSocket(socket => {
+      _this.socket = socket;
+      _this.socket.emit("news.index", result => {
+        _this.news = result.data;
+      });
+      _this.socket.on("event:admin.news.created", news => {
+        _this.news.unshift(news);
+      });
+      _this.socket.on("event:admin.news.removed", news => {
+        _this.news = _this.news.filter(item => item._id !== news._id);
+      });
+      if (_this.socket.connected) _this.init();
+      io.onConnect(() => {
+        _this.init();
+      });
+    });
+  }
+};
 </script>
 
 <style lang='scss' scoped>
-	.tag:not(:last-child) { margin-right: 5px; }
+.tag:not(:last-child) {
+  margin-right: 5px;
+}
 
-	td { vertical-align: middle; }
+td {
+  vertical-align: middle;
+}
 
-	.is-info:focus { background-color: #0398db; }
+.is-info:focus {
+  background-color: #0398db;
+}
 
-	.card-footer-item { color: #03a9f4; }
+.card-footer-item {
+  color: #03a9f4;
+}
 </style>

+ 133 - 104
frontend/components/Admin/Punishments.vue

@@ -1,114 +1,143 @@
 <template>
-	<div class='container'>
-		<table class='table is-striped'>
-			<thead>
-			<tr>
-				<td>Type</td>
-				<td>Value</td>
-				<td>Reason</td>
-				<td>Status</td>
-				<td>Options</td>
-			</tr>
-			</thead>
-			<tbody>
-			<tr v-for='(index, punishment) in punishments | orderBy "expiresAt" -1' track-by='$index'>
-				<td v-if='punishment.type === "banUserId"'>User ID</td>
-				<td v-else>IP Address</td>
-				<td>{{ punishment.value }}</td>
-				<td>{{ punishment.reason }}</td>
-				<td>{{ (punishment.active && new Date(punishment.expiresAt).getTime() > Date.now()) ? 'Active' : 'Inactive' }}</td>
-				<td>
-					<button class='button is-primary' @click='view(punishment)'>View</button>
-				</td>
-			</tr>
-			</tbody>
-		</table>
-		<div class='card is-fullwidth'>
-			<header class='card-header'>
-				<p class='card-header-title'>Ban an IP</p>
-			</header>
-			<div class='card-content'>
-				<div class='content'>
-					<label class='label'>Expires In</label>
-					<select v-model='ipBan.expiresAt'>
-						<option value='1h'>1 Hour</option>
-						<option value='12h'>12 Hours</option>
-						<option value='1d'>1 Day</option>
-						<option value='1w'>1 Week</option>
-						<option value='1m'>1 Month</option>
-						<option value='3m'>3 Months</option>
-						<option value='6m'>6 Months</option>
-						<option value='1y'>1 Year</option>
-					</select>
-					<label class='label'>IP</label>
-					<p class='control is-expanded'>
-						<input class='input' type='text' placeholder='IP address (xxx.xxx.xxx.xxx)' v-model='ipBan.ip'>
-					</p>
-					<label class='label'>Reason</label>
-					<p class='control is-expanded'>
-						<input class='input' type='text' placeholder='Reason' v-model='ipBan.reason'>
-					</p>
-				</div>
-			</div>
-			<footer class='card-footer'>
-				<a class='card-footer-item' @click='banIP()' href='#'>Ban IP</a>
-			</footer>
-		</div>
-	</div>
-	<view-punishment v-show='modals.viewPunishment'></view-punishment>
+  <div>
+    <div class="container">
+      <table class="table is-striped">
+        <thead>
+          <tr>
+            <td>Type</td>
+            <td>Value</td>
+            <td>Reason</td>
+            <td>Status</td>
+            <td>Options</td>
+          </tr>
+        </thead>
+        <tbody>
+          <tr v-for="(punishment, index) in sortedPunishments" :key="index">
+            <td v-if="punishment.type === 'banUserId'">User ID</td>
+            <td v-else>IP Address</td>
+            <td>{{ punishment.value }}</td>
+            <td>{{ punishment.reason }}</td>
+            <td>{{ (punishment.active && new Date(punishment.expiresAt).getTime() > Date.now()) ? 'Active' : 'Inactive' }}</td>
+            <td>
+              <button class="button is-primary" v-on:click="view(punishment)">View</button>
+            </td>
+          </tr>
+        </tbody>
+      </table>
+      <div class="card is-fullwidth">
+        <header class="card-header">
+          <p class="card-header-title">Ban an IP</p>
+        </header>
+        <div class="card-content">
+          <div class="content">
+            <label class="label">Expires In</label>
+            <select v-model="ipBan.expiresAt">
+              <option value="1h">1 Hour</option>
+              <option value="12h">12 Hours</option>
+              <option value="1d">1 Day</option>
+              <option value="1w">1 Week</option>
+              <option value="1m">1 Month</option>
+              <option value="3m">3 Months</option>
+              <option value="6m">6 Months</option>
+              <option value="1y">1 Year</option>
+            </select>
+            <label class="label">IP</label>
+            <p class="control is-expanded">
+              <input
+                class="input"
+                type="text"
+                placeholder="IP address (xxx.xxx.xxx.xxx)"
+                v-model="ipBan.ip"
+              />
+            </p>
+            <label class="label">Reason</label>
+            <p class="control is-expanded">
+              <input class="input" type="text" placeholder="Reason" v-model="ipBan.reason" />
+            </p>
+          </div>
+        </div>
+        <footer class="card-footer">
+          <a class="card-footer-item" v-on:click="banIP()" href="#">Ban IP</a>
+        </footer>
+      </div>
+    </div>
+    <view-punishment v-if="modals.viewPunishment"></view-punishment>
+  </div>
 </template>
 
 <script>
-	import ViewPunishment from '../Modals/ViewPunishment.vue';
-	import { Toast } from 'vue-roaster';
-	import io from '../../io';
+import { mapState, mapActions } from "vuex";
 
-	export default {
-		components: { ViewPunishment },
-		data() {
-			return {
-				punishments: [],
-				modals: { viewPunishment: false },
-				ipBan: {
-					expiresAt: '1h'
-				}
-			}
-		},
-		methods: {
-			toggleModal: function () {
-				this.modals.viewPunishment = !this.modals.viewPunishment;
-			},
-			view: function (punishment) {
-				this.$broadcast('viewPunishment', punishment);
-			},
-			banIP: function() {
-				let _this = this;
-				_this.socket.emit('punishments.banIP', _this.ipBan.ip, _this.ipBan.reason, _this.ipBan.expiresAt, res => {
-					Toast.methods.addToast(res.message, 6000);
-				});
-			},
-			init: function () {
-				let _this = this;
-				_this.socket.emit('punishments.index', result => {
-					if (result.status === 'success') _this.punishments = result.data;
-				});
-				//_this.socket.emit('apis.joinAdminRoom', 'punishments', () => {});
-			}
-		},
-		ready: function () {
-			let _this = this;
-			io.getSocket(socket => {
-				_this.socket = socket;
-				if (_this.socket.connected) _this.init();
-				io.onConnect(() => _this.init());
-			});
-		}
-	}
+import ViewPunishment from "../Modals/ViewPunishment.vue";
+import { Toast } from "vue-roaster";
+import io from "../../io";
+
+export default {
+  components: { ViewPunishment },
+  data() {
+    return {
+      punishments: [],
+      ipBan: {
+        expiresAt: "1h"
+      }
+    };
+  },
+  computed: {
+    sortedPunishments: function() {
+      //   return _.orderBy(this.punishments, -1);
+      return this.punishments;
+    },
+    ...mapState("modals", {
+      modals: state => state.modals.admin
+    })
+  },
+  methods: {
+    view: function(punishment) {
+      this.viewPunishment(punishment);
+      this.toggleModal({ sector: "admin", modal: "viewPunishment" });
+    },
+    banIP: function() {
+      let _this = this;
+      _this.socket.emit(
+        "punishments.banIP",
+        _this.ipBan.ip,
+        _this.ipBan.reason,
+        _this.ipBan.expiresAt,
+        res => {
+          Toast.methods.addToast(res.message, 6000);
+        }
+      );
+    },
+    init: function() {
+      let _this = this;
+      _this.socket.emit("punishments.index", res => {
+        if (res.status === "success") _this.punishments = res.data;
+      });
+      //_this.socket.emit('apis.joinAdminRoom', 'punishments', () => {});
+    },
+    ...mapActions("modals", ["toggleModal"]),
+    ...mapActions("admin/punishments", ["viewPunishment"])
+  },
+  mounted: function() {
+    let _this = this;
+    io.getSocket(socket => {
+      _this.socket = socket;
+      if (_this.socket.connected) _this.init();
+      io.onConnect(() => _this.init());
+    });
+  }
+};
 </script>
 
 <style lang='scss' scoped>
-	body { font-family: 'Roboto', sans-serif; }
+body {
+  font-family: "Roboto", sans-serif;
+}
 
-	td { vertical-align: middle; }
-	select { margin-bottom: 10px; }
+td {
+  vertical-align: middle;
+}
+select {
+  margin-bottom: 10px;
+}
 </style>

+ 165 - 137
frontend/components/Admin/QueueSongs.vue

@@ -1,149 +1,177 @@
 <template>
-	<div class='container'>
-		<input type='text' class='input' v-model='searchQuery' placeholder='Search for Songs'>
-		<br /><br />
-		<table class='table is-striped'>
-			<thead>
-				<tr>
-					<td>Thumbnail</td>
-					<td>Title</td>
-					<td>YouTube ID</td>
-					<td>Artists</td>
-					<td>Genres</td>
-					<td>Requested By</td>
-					<td>Options</td>
-				</tr>
-			</thead>
-			<tbody>
-				<tr v-for='(index, song) in filteredSongs' track-by='$index'>
-					<td>
-						<img class='song-thumbnail' :src='song.thumbnail' onerror="this.src='/assets/notes-transparent.png'">
-					</td>
-					<td>
-						<strong>{{ song.title }}</strong>
-					</td>
-					<td>{{ song.songId }}</td>
-					<td>{{ song.artists.join(', ') }}</td>
-					<td>{{ song.genres.join(', ') }}</td>
-					<td>{{ song.requestedBy }}</td>
-					<td>
-						<button class='button is-primary' @click='edit(song, index)'>Edit</button>
-						<button class='button is-success' @click='add(song)'>Add</button>
-						<button class='button is-danger' @click='remove(song._id, index)'>Remove</button>
-					</td>
-				</tr>
-			</tbody>
-		</table>
-	</div>
-	<nav class="pagination">
-		<a class="button" href='#' @click='getSet(position - 1)' v-if='position > 1'><i class="material-icons">navigate_before</i></a>
-		<a class="button" href='#' @click='getSet(position + 1)' v-if='maxPosition > position'><i class="material-icons">navigate_next</i></a>
-	</nav>
-	<edit-song v-show='modals.editSong'></edit-song>
+  <div>
+    <div class="container">
+      <input type="text" class="input" v-model="searchQuery" placeholder="Search for Songs" />
+      <br />
+      <br />
+      <table class="table is-striped">
+        <thead>
+          <tr>
+            <td>Thumbnail</td>
+            <td>Title</td>
+            <td>YouTube ID</td>
+            <td>Artists</td>
+            <td>Genres</td>
+            <td>Requested By</td>
+            <td>Options</td>
+          </tr>
+        </thead>
+        <tbody>
+          <tr v-for="(song, index) in filteredSongs" :key="index">
+            <td>
+              <img
+                class="song-thumbnail"
+                :src="song.thumbnail"
+                onerror="this.src='/assets/notes-transparent.png'"
+              />
+            </td>
+            <td>
+              <strong>{{ song.title }}</strong>
+            </td>
+            <td>{{ song.songId }}</td>
+            <td>{{ song.artists.join(', ') }}</td>
+            <td>{{ song.genres.join(', ') }}</td>
+            <td>{{ song.requestedBy }}</td>
+            <td>
+              <button class="button is-primary" v-on:click="edit(song, index)">Edit</button>
+              <button class="button is-success" v-on:click="add(song)">Add</button>
+              <button class="button is-danger" v-on:click="remove(song._id, index)">Remove</button>
+            </td>
+          </tr>
+        </tbody>
+      </table>
+    </div>
+    <nav class="pagination">
+      <a class="button" href="#" v-on:click="getSet(position - 1)" v-if="position > 1">
+        <i class="material-icons">navigate_before</i>
+      </a>
+      <a class="button" href="#" v-on:click="getSet(position + 1)" v-if="maxPosition > position">
+        <i class="material-icons">navigate_next</i>
+      </a>
+    </nav>
+    <edit-song v-if="modals.editSong"></edit-song>
+  </div>
 </template>
 
 <script>
-	import { Toast } from 'vue-roaster';
+import { mapState, mapActions } from "vuex";
 
-	import EditSong from '../Modals/EditSong.vue';
-	import io from '../../io';
+import { Toast } from "vue-roaster";
 
-	export default {
-		components: { EditSong },
-		data() {
-			return {
-				position: 1,
-				maxPosition: 1,
-				searchQuery: '',
-				songs: [],
-				modals: { editSong: false }
-			}
-		},
-		computed: {
-			filteredSongs: function () {
-				return this.$eval('songs | filterBy searchQuery');
-			}
-		},
-		watch: {
-			'modals.editSong': function (value) {
-				if (!value) this.$broadcast('stopVideo');
-			}
-		},
-		methods: {
-			toggleModal: function () {
-				this.modals.editSong = !this.modals.editSong;
-			},
-			getSet: function (position) {
-				let _this = this;
-				this.socket.emit('queueSongs.getSet', position, data => {
-					_this.songs = data;
-					this.position = position;
-				});
-			},
-			edit: function (song, index) {
-				this.$broadcast('editSong', song, index, 'queueSongs');
-			},
-			add: function (song) {
-				this.socket.emit('songs.add', song, res => {
-					if (res.status == 'success') Toast.methods.addToast(res.message, 2000);
-					else Toast.methods.addToast(res.message, 4000);
-				});
-			},
-			remove: function (id, index) {
-				console.log("Removing ", id);
-				this.socket.emit('queueSongs.remove', id, res => {
-					if (res.status == 'success') Toast.methods.addToast(res.message, 2000);
-				else Toast.methods.addToast(res.message, 4000);
-				});
-			},
-			init: function() {
-				let _this = this;
-				_this.socket.emit('queueSongs.index', data => {
-					_this.songs = data.songs;
-					_this.maxPosition = Math.round(data.maxLength / 50);
-				});
-				_this.socket.emit('apis.joinAdminRoom', 'queue', data => {});
-			}
-		},
-		ready: function () {
-			let _this = this;
-			io.getSocket((socket) => {
-				_this.socket = socket;
-				if (_this.socket.connected) {
-					_this.init();
-					_this.socket.on('event:admin.queueSong.added', queueSong => {
-						_this.songs.push(queueSong);
-					});
-					_this.socket.on('event:admin.queueSong.removed', songId => {
-						_this.songs = _this.songs.filter(function(song) {
-							return song._id !== songId;
-						});
-					});
-					_this.socket.on('event:admin.queueSong.updated', updatedSong => {
-						for (let i = 0; i < _this.songs.length; i++) {
-							let song = _this.songs[i];
-							if (song._id === updatedSong._id) {
-								_this.songs.$set(i, updatedSong);
-							}
-						}
-					});
-				}
-				io.onConnect(() => {
-					_this.init();
-				});
-			});
-		}
-	}
+import EditSong from "../Modals/EditSong.vue";
+import io from "../../io";
+
+export default {
+  components: { EditSong },
+  data() {
+    return {
+      position: 1,
+      maxPosition: 1,
+      searchQuery: "",
+      songs: []
+    };
+  },
+  computed: {
+    filteredSongs: function() {
+      return this.songs;
+      // return this.songs.filter(song => song.indexOf(song.searchQuery) !== -1);
+    },
+    ...mapState("modals", {
+      modals: state => state.modals.admin
+    })
+  },
+  // watch: {
+  //   "modals.editSong": function(value) {
+  //     console.log(value);
+  //     if (value === false) this.stopVideo();
+  //   }
+  // },
+  methods: {
+    getSet: function(position) {
+      let _this = this;
+      this.socket.emit("queueSongs.getSet", position, data => {
+        _this.songs = data;
+        this.position = position;
+      });
+    },
+    edit: function(song, index) {
+      console.log(song, index);
+
+      let _this = this;
+
+      let newSong = {};
+      for (let n in song) newSong[n] = song[n];
+
+      this.editSong({ index, song: newSong, type: "queueSongs" });
+      this.toggleModal({ sector: "admin", modal: "editSong" });
+    },
+    add: function(song) {
+      this.socket.emit("songs.add", song, res => {
+        if (res.status == "success") Toast.methods.addToast(res.message, 2000);
+        else Toast.methods.addToast(res.message, 4000);
+      });
+    },
+    remove: function(id, index) {
+      console.log("Removing ", id);
+      this.socket.emit("queueSongs.remove", id, res => {
+        if (res.status == "success") Toast.methods.addToast(res.message, 2000);
+        else Toast.methods.addToast(res.message, 4000);
+      });
+    },
+    init: function() {
+      let _this = this;
+      _this.socket.emit("queueSongs.index", data => {
+        _this.songs = data.songs;
+        _this.maxPosition = Math.round(data.maxLength / 50);
+      });
+      _this.socket.emit("apis.joinAdminRoom", "queue", data => {});
+    },
+    ...mapActions("admin/songs", ["stopVideo", "editSong"]),
+    ...mapActions("modals", ["toggleModal"])
+  },
+  mounted: function() {
+    let _this = this;
+    io.getSocket(socket => {
+      _this.socket = socket;
+      if (_this.socket.connected) {
+        _this.init();
+        _this.socket.on("event:admin.queueSong.added", queueSong => {
+          _this.songs.push(queueSong);
+        });
+        _this.socket.on("event:admin.queueSong.removed", songId => {
+          _this.songs = _this.songs.filter(function(song) {
+            return song._id !== songId;
+          });
+        });
+        _this.socket.on("event:admin.queueSong.updated", updatedSong => {
+          for (let i = 0; i < _this.songs.length; i++) {
+            let song = _this.songs[i];
+            if (song._id === updatedSong._id) {
+              _this.songs.$set(i, updatedSong);
+            }
+          }
+        });
+      }
+      io.onConnect(() => {
+        _this.init();
+      });
+    });
+  }
+};
 </script>
 
 <style lang='scss' scoped>
-	.song-thumbnail {
-		display: block;
-		max-width: 50px;
-		margin: 0 auto;
-	}
+.song-thumbnail {
+  display: block;
+  max-width: 50px;
+  margin: 0 auto;
+}
 
-	td { vertical-align: middle; }
+td {
+  vertical-align: middle;
+}
 
-	.is-primary:focus { background-color: #029ce3 !important; }
+.is-primary:focus {
+  background-color: #029ce3 !important;
+}
 </style>

+ 101 - 97
frontend/components/Admin/Reports.vue

@@ -1,109 +1,113 @@
 <template>
-	<div class='container'>
-		<table class='table is-striped'>
-			<thead>
-				<tr>
-					<td>Song ID</td>
-					<td>Created By</td>
-					<td>Created At</td>
-					<td>Description</td>
-					<td>Options</td>
-				</tr>
-			</thead>
-			<tbody>
-				<tr v-for='(index, report) in reports' track-by='$index'>
-					<td>
-						<span>{{ report.songId }}</span>
-					</td>
-					<td>
-						<span>{{ report.createdBy }}</span>
-					</td>
-					<td>
-						<span>{{ report.createdAt }}</span>
-					</td>
-					<td>
-						<span>{{ report.description }}</span>
-					</td>
-					<td>
-						<a class='button is-warning' href='#' @click='toggleModal(report)'>Issues Modal</a>
-						<a class='button is-primary' href='#' @click='resolve(report._id)'>Resolve</a>
-					</td>
-				</tr>
-			</tbody>
-		</table>
-	</div>
+  <div>
+    <div class="container">
+      <table class="table is-striped">
+        <thead>
+          <tr>
+            <td>Song ID</td>
+            <td>Created By</td>
+            <td>Created At</td>
+            <td>Description</td>
+            <td>Options</td>
+          </tr>
+        </thead>
+        <tbody>
+          <tr v-for="(report, index) in reports" :key="index">
+            <td>
+              <span>{{ report.songId }}</span>
+            </td>
+            <td>
+              <span>{{ report.createdBy }}</span>
+            </td>
+            <td>
+              <span>{{ report.createdAt }}</span>
+            </td>
+            <td>
+              <span>{{ report.description }}</span>
+            </td>
+            <td>
+              <a class="button is-warning" href="#" v-on:click="toggleModal(report)">Issues Modal</a>
+              <a class="button is-primary" href="#" v-on:click="resolve(report._id)">Resolve</a>
+            </td>
+          </tr>
+        </tbody>
+      </table>
+    </div>
 
-	<issues-modal v-if='modals.report'></issues-modal>
+    <issues-modal v-if="modals.report"></issues-modal>
+  </div>
 </template>
 
 <script>
-	import { Toast } from 'vue-roaster';
-	import io from '../../io';
+import { Toast } from "vue-roaster";
+import io from "../../io";
 
-	import IssuesModal from '../Modals/IssuesModal.vue';
+import IssuesModal from "../Modals/IssuesModal.vue";
 
-	export default {
-		data() {
-			return {
-				reports: [],
-				modals: {
-					report: false
-				}
-			}
-		},
-		methods: {
-			init: function() {
-				this.socket.emit('apis.joinAdminRoom', 'reports', data => {});
-			},
-			toggleModal: function (report) {
-				this.modals.report = !this.modals.report;
-				if (this.modals.report) this.editing = report;
-			},
-			resolve: function (reportId) {
-				let _this = this;
-				this.socket.emit('reports.resolve', reportId, res => {
-					Toast.methods.addToast(res.message, 3000);
-					if (res.status === 'success' && this.modals.report) _this.toggleModal();
-				});
-			}
-		},
-		ready: function () {
-			let _this = this;
-			io.getSocket(socket => {
-				_this.socket = socket;
-				if (_this.socket.connected) _this.init();
-				_this.socket.emit('reports.index', res => {
-					_this.reports = res.data;
-				});
-				_this.socket.on('event:admin.report.resolved', reportId => {
-					_this.reports = _this.reports.filter(report => {
-						return report._id !== reportId;
-					});
-				});
-				_this.socket.on('event:admin.report.created', report => {
-					_this.reports.push(report);
-				});
-				io.onConnect(() => {
-					_this.init();
-				});
-			});
-			if (this.$route.query.id) {
-				this.socket.emit('reports.findOne', this.$route.query.id, res => {
-					if (res.status === 'success') _this.toggleModal(res.data);
-					else Toast.methods.addToast('Report with that ID not found', 3000);
-				});
-			}
-		},
-		components: { IssuesModal }
-	}
+export default {
+  data() {
+    return {
+      reports: [],
+      modals: {
+        report: false
+      }
+    };
+  },
+  methods: {
+    init: function() {
+      this.socket.emit("apis.joinAdminRoom", "reports", data => {});
+    },
+    toggleModal: function(report) {
+      this.modals.report = !this.modals.report;
+      if (this.modals.report) this.editing = report;
+    },
+    resolve: function(reportId) {
+      let _this = this;
+      this.socket.emit("reports.resolve", reportId, res => {
+        Toast.methods.addToast(res.message, 3000);
+        if (res.status === "success" && this.modals.report) _this.toggleModal();
+      });
+    }
+  },
+  mounted: function() {
+    let _this = this;
+    io.getSocket(socket => {
+      _this.socket = socket;
+      if (_this.socket.connected) _this.init();
+      _this.socket.emit("reports.index", res => {
+        _this.reports = res.data;
+      });
+      _this.socket.on("event:admin.report.resolved", reportId => {
+        _this.reports = _this.reports.filter(report => {
+          return report._id !== reportId;
+        });
+      });
+      _this.socket.on("event:admin.report.created", report => {
+        _this.reports.push(report);
+      });
+      io.onConnect(() => {
+        _this.init();
+      });
+    });
+    if (this.$route.query.id) {
+      this.socket.emit("reports.findOne", this.$route.query.id, res => {
+        if (res.status === "success") _this.toggleModal(res.data);
+        else Toast.methods.addToast("Report with that ID not found", 3000);
+      });
+    }
+  },
+  components: { IssuesModal }
+};
 </script>
 
 <style lang='scss' scoped>
-	.tag:not(:last-child) { margin-right: 5px; }
+.tag:not(:last-child) {
+  margin-right: 5px;
+}
 
-	td {
-		word-wrap: break-word;
-		max-width: 10vw;
-		vertical-align: middle;
-	}
+td {
+  word-wrap: break-word;
+  max-width: 10vw;
+  vertical-align: middle;
+}
 </style>

+ 151 - 139
frontend/components/Admin/Songs.vue

@@ -1,152 +1,164 @@
 <template>
-	<div class='container'>
-		<input type='text' class='input' v-model='searchQuery' placeholder='Search for Songs'>
-		<br /><br />
-		<table class='table is-striped'>
-			<thead>
-				<tr>
-					<td>Thumbnail</td>
-					<td>Title</td>
-					<td>YouTube ID</td>
-					<td>Artists</td>
-					<td>Genres</td>
-					<td>Requested By</td>
-					<td>Options</td>
-				</tr>
-			</thead>
-			<tbody>
-				<tr v-for='(index, song) in filteredSongs' track-by='$index'>
-					<td>
-						<img class='song-thumbnail' :src='song.thumbnail' onerror="this.src='/assets/notes-transparent.png'">
-					</td>
-					<td>
-						<strong>{{ song.title }}</strong>
-					</td>
-					<td>{{ song.songId }}</td>
-					<td>{{ song.artists.join(', ') }}</td>
-					<td>{{ song.genres.join(', ') }}</td>
-					<td>{{ song.requestedBy }}</td>
-					<td>
-						<button class='button is-primary' @click='edit(song, index)'>Edit</button>
-						<button class='button is-danger' @click='remove(song._id, index)'>Remove</button>
-					</td>
-				</tr>
-			</tbody>
-		</table>
-	</div>
-	<edit-song v-show='modals.editSong'></edit-song>
+  <div>
+    <div class="container">
+      <input type="text" class="input" v-model="searchQuery" placeholder="Search for Songs" />
+      <br />
+      <br />
+      <table class="table is-striped">
+        <thead>
+          <tr>
+            <td>Thumbnail</td>
+            <td>Title</td>
+            <td>YouTube ID</td>
+            <td>Artists</td>
+            <td>Genres</td>
+            <td>Requested By</td>
+            <td>Options</td>
+          </tr>
+        </thead>
+        <tbody>
+          <tr v-for="(song, index) in filteredSongs" :key="index">
+            <td>
+              <img
+                class="song-thumbnail"
+                :src="song.thumbnail"
+                onerror="this.src='/assets/notes-transparent.png'"
+              />
+            </td>
+            <td>
+              <strong>{{ song.title }}</strong>
+            </td>
+            <td>{{ song.songId }}</td>
+            <td>{{ song.artists.join(', ') }}</td>
+            <td>{{ song.genres.join(', ') }}</td>
+            <td>{{ song.requestedBy }}</td>
+            <td>
+              <button class="button is-primary" v-on:click="edit(song, index)">Edit</button>
+              <button class="button is-danger" v-on:click="remove(song._id, index)">Remove</button>
+            </td>
+          </tr>
+        </tbody>
+      </table>
+    </div>
+    <edit-song v-if="modals.editSong"></edit-song>
+  </div>
 </template>
 
 <script>
-	import { Toast } from 'vue-roaster';
+import { mapState, mapActions } from "vuex";
 
-	import EditSong from '../Modals/EditSong.vue';
-	import io from '../../io';
+import { Toast } from "vue-roaster";
 
-	export default {
-		components: { EditSong },
-		data() {
-			return {
-				position: 1,
-				maxPosition: 1,
-				songs: [],
-				searchQuery: '',
-				modals: { editSong: false },
-				editing: {
-					index: 0,
-					song: {}
-				},
-				video: {
-					player: null,
-					paused: false,
-					playerReady: false
-				}
-			}
-		},
-		computed: {
-			filteredSongs: function () {
-				return this.$eval('songs | filterBy searchQuery');
-			}
-		},
-		watch: {
-			'modals.editSong': function (value) {
-				if (!value) this.$broadcast('stopVideo');
-			}
-		},
-		methods: {
-			toggleModal: function () {
-				this.modals.editSong = !this.modals.editSong;
-			},
-			edit: function (song, index) {
-				this.$broadcast('editSong', song, index, 'songs');
-			},
-			remove: function (id) {
-				this.socket.emit('songs.remove', id, res => {
-					if (res.status == 'success') Toast.methods.addToast(res.message, 4000);
-					else Toast.methods.addToast(res.message, 8000);
-				});
-			},
-			getSet: function () {
-				let _this = this;
-				_this.socket.emit('songs.getSet', _this.position, data => {
-					data.forEach(song => {
-						_this.songs.push(song);
-					});
-					_this.position = _this.position + 1;
-					if (_this.maxPosition > _this.position - 1) _this.getSet();
-				});
-			},
-			init: function () {
-				let _this = this;
-				_this.songs = [];
-				_this.socket.emit('songs.length', length => {
-					_this.maxPosition = Math.ceil(length / 15);
-					_this.getSet();
-				});
-				_this.socket.emit('apis.joinAdminRoom', 'songs', () => {});
-			}
-		},
-		ready: function () {
-			let _this = this;
-			io.getSocket((socket) => {
-				_this.socket = socket;
-				if (_this.socket.connected) {
-					_this.init();
-					_this.socket.on('event:admin.song.added', song => {
-						_this.songs.push(song);
-					});
-					_this.socket.on('event:admin.song.removed', songId => {
-						_this.songs = _this.songs.filter(function(song) {
-							return song._id !== songId;
-						});
-					});
-					_this.socket.on('event:admin.song.updated', updatedSong => {
-						for (let i = 0; i < _this.songs.length; i++) {
-							let song = _this.songs[i];
-							if (song._id === updatedSong._id) {
-								_this.songs.$set(i, updatedSong);
-							}
-						}
-					});
-				}
-				io.onConnect(() => {
-					_this.init();
-				});
-			});
-		}
-	}
+import EditSong from "../Modals/EditSong.vue";
+import io from "../../io";
+
+export default {
+  components: { EditSong },
+  data() {
+    return {
+      position: 1,
+      maxPosition: 1,
+      songs: [],
+      searchQuery: "",
+      editing: {
+        index: 0,
+        song: {}
+      }
+    };
+  },
+  computed: {
+    filteredSongs: function() {
+      return this.songs;
+      // return this.songs.filter(song => song.indexOf(song.searchQuery) !== -1);
+    },
+    ...mapState("modals", {
+      modals: state => state.modals.admin
+    })
+  },
+  watch: {
+    "modals.editSong": function(value) {
+      if (!value) this.stopVideo();
+    }
+  },
+  methods: {
+    edit: function(song, index) {
+      this.editSong({ song, index, type: "songs" });
+    },
+    remove: function(id) {
+      this.socket.emit("songs.remove", id, res => {
+        if (res.status == "success") Toast.methods.addToast(res.message, 4000);
+        else Toast.methods.addToast(res.message, 8000);
+      });
+    },
+    getSet: function() {
+      let _this = this;
+      _this.socket.emit("songs.getSet", _this.position, data => {
+        data.forEach(song => {
+          _this.songs.push(song);
+        });
+        _this.position = _this.position + 1;
+        if (_this.maxPosition > _this.position - 1) _this.getSet();
+      });
+    },
+    init: function() {
+      let _this = this;
+      _this.songs = [];
+      _this.socket.emit("songs.length", length => {
+        _this.maxPosition = Math.ceil(length / 15);
+        _this.getSet();
+      });
+      _this.socket.emit("apis.joinAdminRoom", "songs", () => {});
+    },
+    ...mapActions("admin/songs", ["stopVideo", "editSong"]),
+    ...mapActions("modals", ["toggleModal"])
+  },
+  mounted: function() {
+    let _this = this;
+    io.getSocket(socket => {
+      _this.socket = socket;
+      if (_this.socket.connected) {
+        _this.init();
+        _this.socket.on("event:admin.song.added", song => {
+          _this.songs.push(song);
+        });
+        _this.socket.on("event:admin.song.removed", songId => {
+          _this.songs = _this.songs.filter(function(song) {
+            return song._id !== songId;
+          });
+        });
+        _this.socket.on("event:admin.song.updated", updatedSong => {
+          for (let i = 0; i < _this.songs.length; i++) {
+            let song = _this.songs[i];
+            if (song._id === updatedSong._id) {
+              _this.songs.$set(i, updatedSong);
+            }
+          }
+        });
+      }
+      io.onConnect(() => {
+        _this.init();
+      });
+    });
+  }
+};
 </script>
 
 <style lang='scss' scoped>
-	body { font-family: 'Roboto', sans-serif; }
+body {
+  font-family: "Roboto", sans-serif;
+}
 
-	.song-thumbnail {
-		display: block;
-		max-width: 50px;
-		margin: 0 auto;
-	}
+.song-thumbnail {
+  display: block;
+  max-width: 50px;
+  margin: 0 auto;
+}
 
-	td { vertical-align: middle; }
+td {
+  vertical-align: middle;
+}
 
-	.is-primary:focus { background-color: #029ce3 !important; }
+.is-primary:focus {
+  background-color: #029ce3 !important;
+}
 </style>

+ 288 - 208
frontend/components/Admin/Stations.vue

@@ -1,226 +1,306 @@
 <template>
-	<div class='container'>
-		<table class='table is-striped'>
-			<thead>
-				<tr>
-					<td>ID</td>
-					<td>Name</td>
-					<td>Type</td>
-					<td>Display Name</td>
-					<td>Description</td>
-					<td>Options</td>
-				</tr>
-			</thead>
-			<tbody>
-				<tr v-for='(index, station) in stations' track-by='$index'>
-					<td>
-						<span>{{station._id}}</span>
-					</td>
-					<td>
-						<span>{{station.name}}</span>
-					</td>
-					<td>
-						<span>{{station.type}}</span>
-					</td>
-					<td>
-						<span>{{station.displayName}}</span>
-					</td>
-					<td>
-						<span>{{station.description}}</span>
-					</td>
-					<td>
-						<a class='button is-info' @click='editStation(station)'>Edit</a>
-						<a class='button is-danger' @click='removeStation(index)' href='#'>Remove</a>
-					</td>
-				</tr>
-			</tbody>
-		</table>
-	</div>
-	<div class='container'>
-		<div class='card is-fullwidth'>
-			<header class='card-header'>
-				<p class='card-header-title'>Create official station</p>
-			</header>
-			<div class='card-content'>
-				<div class='content'>
-					<div class='control is-horizontal'>
-						<div class='control is-grouped'>
-							<p class='control is-expanded'>
-								<input class='input' type='text' placeholder='Name' v-model='newStation.name'>
-							</p>
-							<p class='control is-expanded'>
-								<input class='input' type='text' placeholder='Display Name' v-model='newStation.displayName'>
-							</p>
-						</div>
-					</div>
-					<label class='label'>Description</label>
-					<p class='control is-expanded'>
-						<input class='input' type='text' placeholder='Short description' v-model='newStation.description'>
-					</p>
-					<div class="control is-grouped genre-wrapper">
-						<div class="sector">
-							<p class='control has-addons'>
-								<input class='input' id='new-genre' type='text' placeholder='Genre' v-on:keyup.enter='addGenre()'>
-								<a class='button is-info' href='#' @click='addGenre()'>Add genre</a>
-							</p>
-							<span class='tag is-info' v-for='(index, genre) in newStation.genres' track-by='$index'>
-								{{ genre }}
-								<button class='delete is-info' @click='removeGenre(index)'></button>
-							</span>
-						</div>
-						<div class="sector">
-							<p class='control has-addons'>
-								<input class='input' id='new-blacklisted-genre' type='text' placeholder='Blacklisted Genre' v-on:keyup.enter='addBlacklistedGenre()'>
-								<a class='button is-info' href='#' @click='addBlacklistedGenre()'>Add blacklisted genre</a>
-							</p>
-							<span class='tag is-info' v-for='(index, genre) in newStation.blacklistedGenres' track-by='$index'>
-								{{ genre }}
-								<button class='delete is-info' @click='removeBlacklistedGenre(index)'></button>
-							</span>
-						</div>
-					</div>
-				</div>
-			</div>
-			<footer class='card-footer'>
-				<a class='card-footer-item' @click='createStation()' href='#'>Create</a>
-			</footer>
-		</div>
-	</div>
+  <div>
+    <div class="container">
+      <table class="table is-striped">
+        <thead>
+          <tr>
+            <td>ID</td>
+            <td>Name</td>
+            <td>Type</td>
+            <td>Display Name</td>
+            <td>Description</td>
+            <td>Options</td>
+          </tr>
+        </thead>
+        <tbody>
+          <tr v-for="(station, index) in stations" :key="index">
+            <td>
+              <span>{{station._id}}</span>
+            </td>
+            <td>
+              <span>{{station.name}}</span>
+            </td>
+            <td>
+              <span>{{station.type}}</span>
+            </td>
+            <td>
+              <span>{{station.displayName}}</span>
+            </td>
+            <td>
+              <span>{{station.description}}</span>
+            </td>
+            <td>
+              <a class="button is-info" v-on:click="edit(station)">Edit</a>
+              <a class="button is-danger" v-on:click="removeStation(index)" href="#">Remove</a>
+            </td>
+          </tr>
+        </tbody>
+      </table>
+    </div>
+    <div class="container">
+      <div class="card is-fullwidth">
+        <header class="card-header">
+          <p class="card-header-title">Create official station</p>
+        </header>
+        <div class="card-content">
+          <div class="content">
+            <div class="control is-horizontal">
+              <div class="control is-grouped">
+                <p class="control is-expanded">
+                  <input class="input" type="text" placeholder="Name" v-model="newStation.name" />
+                </p>
+                <p class="control is-expanded">
+                  <input
+                    class="input"
+                    type="text"
+                    placeholder="Display Name"
+                    v-model="newStation.displayName"
+                  />
+                </p>
+              </div>
+            </div>
+            <label class="label">Description</label>
+            <p class="control is-expanded">
+              <input
+                class="input"
+                type="text"
+                placeholder="Short description"
+                v-model="newStation.description"
+              />
+            </p>
+            <div class="control is-grouped genre-wrapper">
+              <div class="sector">
+                <p class="control has-addons">
+                  <input
+                    class="input"
+                    id="new-genre"
+                    type="text"
+                    placeholder="Genre"
+                    v-on:keyup.enter="addGenre()"
+                  />
+                  <a class="button is-info" href="#" v-on:click="addGenre()">Add genre</a>
+                </p>
+                <span class="tag is-info" v-for="(genre, index) in newStation.genres" :key="index">
+                  {{ genre }}
+                  <button class="delete is-info" v-on:click="removeGenre(index)"></button>
+                </span>
+              </div>
+              <div class="sector">
+                <p class="control has-addons">
+                  <input
+                    class="input"
+                    id="new-blacklisted-genre"
+                    type="text"
+                    placeholder="Blacklisted Genre"
+                    v-on:keyup.enter="addBlacklistedGenre()"
+                  />
+                  <a
+                    class="button is-info"
+                    href="#"
+                    v-on:click="addBlacklistedGenre()"
+                  >Add blacklisted genre</a>
+                </p>
+                <span
+                  class="tag is-info"
+                  v-for="(genre, index) in newStation.blacklistedGenres"
+                  :key="index"
+                >
+                  {{ genre }}
+                  <button
+                    class="delete is-info"
+                    v-on:click="removeBlacklistedGenre(index)"
+                  ></button>
+                </span>
+              </div>
+            </div>
+          </div>
+        </div>
+        <footer class="card-footer">
+          <a class="card-footer-item" v-on:click="createStation()" href="#">Create</a>
+        </footer>
+      </div>
+    </div>
 
-	<edit-station v-show='modals.editStation'></edit-station>
+    <edit-station v-if="modals.editStation"></edit-station>
+  </div>
 </template>
 
 <script>
-	import { Toast } from 'vue-roaster';
-	import io from '../../io';
+import { mapState, mapActions } from "vuex";
 
-	import EditStation from '../Modals/EditStation.vue';
+import { Toast } from "vue-roaster";
+import io from "../../io";
 
-	export default {
-		components: { EditStation },
-		data() {
-			return {
-				stations: [],
-				newStation: {
-					genres: [],
-					blacklistedGenres: []
-				},
-				modals: { editStation: false }
-			}
-		},
-		methods: {
-			toggleModal: function () {
-				this.modals.editStation	= !this.modals.editStation;
-			},
-			createStation: function () {
-				let _this = this;
-				let { newStation: { name, displayName, description, genres, blacklistedGenres } } = this;
+import EditStation from "./EditStation.vue";
 
-				if (name == undefined) return Toast.methods.addToast('Field (Name) cannot be empty', 3000);
-				if (displayName == undefined) return Toast.methods.addToast('Field (Display Name) cannot be empty', 3000);
-				if (description == undefined) return Toast.methods.addToast('Field (Description) cannot be empty', 3000);
+export default {
+  components: { EditStation },
+  data() {
+    return {
+      stations: [],
+      newStation: {
+        genres: [],
+        blacklistedGenres: []
+      }
+    };
+  },
+  computed: {
+    ...mapState("modals", {
+      modals: state => state.modals.station
+    })
+  },
+  methods: {
+    createStation: function() {
+      let _this = this;
+      let {
+        newStation: {
+          name,
+          displayName,
+          description,
+          genres,
+          blacklistedGenres
+        }
+      } = this;
 
-				_this.socket.emit('stations.create', {
-					name,
-					type: 'official',
-					displayName,
-					description,
-					genres,
-					blacklistedGenres,
-				}, result => {
-					Toast.methods.addToast(result.message, 3000);
-					if (result.status == 'success') this.newStation = {
-						genres: [],
-						blacklistedGenres: []
-					}
-				});
-			},
-			removeStation: function (index) {
-				this.socket.emit('stations.remove', this.stations[index]._id, res => {
-					Toast.methods.addToast(res.message, 3000);
-				});
-			},
-			editStation: function (station) {
-				this.$broadcast('editStation', {
-					_id: station._id,
-					name: station.name,
-					type: station.type,
-					partyMode: station.partyMode,
-					description: station.description,
-					privacy: station.privacy,
-					displayName: station.displayName
-				});
-			},
-			addGenre: function () {
-				let genre = $('#new-genre').val().toLowerCase().trim();
-				if (this.newStation.genres.indexOf(genre) !== -1) return Toast.methods.addToast('Genre already exists', 3000);
-				if (genre) {
-					this.newStation.genres.push(genre);
-					$('#new-genre').val('');
-				}
-				else Toast.methods.addToast('Genre cannot be empty', 3000);
-			},
-			removeGenre: function (index) { this.newStation.genres.splice(index, 1); },
-			addBlacklistedGenre: function () {
-				let genre = $('#new-blacklisted-genre').val().toLowerCase().trim();
-				if (this.newStation.blacklistedGenres.indexOf(genre) !== -1) return Toast.methods.addToast('Genre already exists', 3000);
+      if (name == undefined)
+        return Toast.methods.addToast("Field (Name) cannot be empty", 3000);
+      if (displayName == undefined)
+        return Toast.methods.addToast(
+          "Field (Display Name) cannot be empty",
+          3000
+        );
+      if (description == undefined)
+        return Toast.methods.addToast(
+          "Field (Description) cannot be empty",
+          3000
+        );
 
-				if (genre) {
-					this.newStation.blacklistedGenres.push(genre);
-					$('#new-blacklisted-genre').val('');
-				}
-				else Toast.methods.addToast('Genre cannot be empty', 3000);
-			},
-			removeBlacklistedGenre: function (index) { this.newStation.blacklistedGenres.splice(index, 1); },
-			init: function () {
-				let _this = this;
-				_this.socket.emit('stations.index', data => {
-					_this.stations = data.stations;
-				});
-				_this.socket.emit('apis.joinAdminRoom', 'stations', data => {});
-			}
-		},
-		ready: function () {
-			let _this = this;
-			io.getSocket((socket) => {
-				_this.socket = socket;
-				if (_this.socket.connected) _this.init();
-				_this.socket.on('event:admin.station.added', station => {
-					_this.stations.push(station);
-				});
-				_this.socket.on('event:admin.station.removed', stationId => {
-					_this.stations = _this.stations.filter(station => {
-						return station._id !== stationId;
-					});
-				});
-				io.onConnect(() => {
-					_this.init();
-				});
-			});
-		}
-	}
+      _this.socket.emit(
+        "stations.create",
+        {
+          name,
+          type: "official",
+          displayName,
+          description,
+          genres,
+          blacklistedGenres
+        },
+        result => {
+          Toast.methods.addToast(result.message, 3000);
+          if (result.status == "success")
+            this.newStation = {
+              genres: [],
+              blacklistedGenres: []
+            };
+        }
+      );
+    },
+    removeStation: function(index) {
+      this.socket.emit("stations.remove", this.stations[index]._id, res => {
+        Toast.methods.addToast(res.message, 3000);
+      });
+    },
+    edit: function(station) {
+      this.editStation({
+        _id: station._id,
+        name: station.name,
+        type: station.type,
+        partyMode: station.partyMode,
+        description: station.description,
+        privacy: station.privacy,
+        displayName: station.displayName
+      });
+      this.toggleModal({
+        sector: "station",
+        modal: "editStation"
+      });
+    },
+    addGenre: function() {
+      let genre = $("#new-genre")
+        .val()
+        .toLowerCase()
+        .trim();
+      if (this.newStation.genres.indexOf(genre) !== -1)
+        return Toast.methods.addToast("Genre already exists", 3000);
+      if (genre) {
+        this.newStation.genres.push(genre);
+        $("#new-genre").val("");
+      } else Toast.methods.addToast("Genre cannot be empty", 3000);
+    },
+    removeGenre: function(index) {
+      this.newStation.genres.splice(index, 1);
+    },
+    addBlacklistedGenre: function() {
+      let genre = $("#new-blacklisted-genre")
+        .val()
+        .toLowerCase()
+        .trim();
+      if (this.newStation.blacklistedGenres.indexOf(genre) !== -1)
+        return Toast.methods.addToast("Genre already exists", 3000);
+
+      if (genre) {
+        this.newStation.blacklistedGenres.push(genre);
+        $("#new-blacklisted-genre").val("");
+      } else Toast.methods.addToast("Genre cannot be empty", 3000);
+    },
+    removeBlacklistedGenre: function(index) {
+      this.newStation.blacklistedGenres.splice(index, 1);
+    },
+    init: function() {
+      let _this = this;
+      _this.socket.emit("stations.index", data => {
+        _this.stations = data.stations;
+      });
+      _this.socket.emit("apis.joinAdminRoom", "stations", data => {});
+    },
+    ...mapActions("modals", ["toggleModal"]),
+    ...mapActions("admin/stations", ["editStation"])
+  },
+  mounted: function() {
+    let _this = this;
+    io.getSocket(socket => {
+      _this.socket = socket;
+      if (_this.socket.connected) _this.init();
+      _this.socket.on("event:admin.station.added", station => {
+        _this.stations.push(station);
+      });
+      _this.socket.on("event:admin.station.removed", stationId => {
+        _this.stations = _this.stations.filter(station => {
+          return station._id !== stationId;
+        });
+      });
+      io.onConnect(() => {
+        _this.init();
+      });
+    });
+  }
+};
 </script>
 
 <style lang='scss' scoped>
-	.tag {
-		margin-top: 5px;
-		&:not(:last-child) {
-			margin-right: 5px;
-		}
-	}
+.tag {
+  margin-top: 5px;
+  &:not(:last-child) {
+    margin-right: 5px;
+  }
+}
 
-	td {
-		word-wrap: break-word;
-		max-width: 10vw;
-		vertical-align: middle;
-	}
+td {
+  word-wrap: break-word;
+  max-width: 10vw;
+  vertical-align: middle;
+}
 
-	.is-info:focus { background-color: #0398db; }
+.is-info:focus {
+  background-color: #0398db;
+}
 
-	.genre-wrapper {
-		display: flex;
-    	justify-content: space-around;
-	}
+.genre-wrapper {
+  display: flex;
+  justify-content: space-around;
+}
 
-	.card-footer-item { color: #029ce3; }
+.card-footer-item {
+  color: #029ce3;
+}
 </style>

+ 1 - 1
frontend/components/Admin/Statistics.vue

@@ -154,7 +154,7 @@
 				return Math.round(number);
 			}
 		},
-		ready: function () {
+		mounted: function () {
 			let _this = this;
 			var minuteCtx = document.getElementById("minuteChart");
 			var hourCtx = document.getElementById("hourChart");

+ 102 - 88
frontend/components/Admin/Users.vue

@@ -1,100 +1,114 @@
 <template>
-	<div class='container'>
-		<table class='table is-striped'>
-			<thead>
-			<tr>
-				<td>Profile Picture</td>
-				<td>User ID</td>
-				<td>GitHub ID</td>
-				<td>Password</td>
-				<td>Username</td>
-				<td>Role</td>
-				<td>Email Address</td>
-				<td>Email Verified</td>
-				<td>Likes</td>
-				<td>Dislikes</td>
-				<td>Songs Requested</td>
-				<td>Options</td>
-			</tr>
-			</thead>
-			<tbody>
-			<tr v-for='(index, user) in users' track-by='$index'>
-				<td>
-					<img class='user-avatar' src='/assets/notes-transparent.png'>
-				</td>
-				<td>{{ user._id }}</td>
-				<td v-if='user.services.github'>{{ user.services.github.id }}</td>
-				<td v-else>Not Linked</td>
-				<td v-if='user.hasPassword'>Yes</td>
-				<td v-else>Not Linked</td>
-				<td>{{ user.username }}</td>
-				<td>{{ user.role }}</td>
-				<td>{{ user.email.address }}</td>
-				<td>{{ user.email.verified }}</td>
-				<td>{{ user.liked.length }}</td>
-				<td>{{ user.disliked.length }}</td>
-				<td>{{ user.songsRequested }}</td>
-				<td>
-					<button class='button is-primary' @click='edit(user)'>Edit</button>
-				</td>
-			</tr>
-			</tbody>
-		</table>
-	</div>
-	<edit-user v-show='modals.editUser'></edit-user>
+  <div>
+    <div class="container">
+      <table class="table is-striped">
+        <thead>
+          <tr>
+            <td>Profile Picture</td>
+            <td>User ID</td>
+            <td>GitHub ID</td>
+            <td>Password</td>
+            <td>Username</td>
+            <td>Role</td>
+            <td>Email Address</td>
+            <td>Email Verified</td>
+            <td>Likes</td>
+            <td>Dislikes</td>
+            <td>Songs Requested</td>
+            <td>Options</td>
+          </tr>
+        </thead>
+        <tbody>
+          <tr v-for="(user, index) in users" :key="index">
+            <td>
+              <img class="user-avatar" src="/assets/notes-transparent.png" />
+            </td>
+            <td>{{ user._id }}</td>
+            <td v-if="user.services.github">{{ user.services.github.id }}</td>
+            <td v-else>Not Linked</td>
+            <td v-if="user.hasPassword">Yes</td>
+            <td v-else>Not Linked</td>
+            <td>{{ user.username }}</td>
+            <td>{{ user.role }}</td>
+            <td>{{ user.email.address }}</td>
+            <td>{{ user.email.verified }}</td>
+            <td>{{ user.liked.length }}</td>
+            <td>{{ user.disliked.length }}</td>
+            <td>{{ user.songsRequested }}</td>
+            <td>
+              <button class="button is-primary" v-on:click="edit(user)">Edit</button>
+            </td>
+          </tr>
+        </tbody>
+      </table>
+    </div>
+    <edit-user v-if="modals.editUser"></edit-user>
+  </div>
 </template>
 
 <script>
-	import EditUser from '../Modals/EditUser.vue';
-	import io from '../../io';
+import { mapState, mapActions } from "vuex";
 
-	export default {
-		components: { EditUser },
-		data() {
-			return {
-				users: [],
-				modals: { editUser: false }
-			}
-		},
-		methods: {
-			toggleModal: function () {
-				this.modals.editUser = !this.modals.editUser;
-			},
-			edit: function (user) {
-				this.$broadcast('editUser', user);
-			},
-			init: function () {
-				let _this = this;
-				_this.socket.emit('users.index', result => {
-					if (result.status === 'success') _this.users = result.data;
-				});
-				_this.socket.emit('apis.joinAdminRoom', 'users', () => {});
-				_this.socket.on('event:user.username.changed', username => {
-					_this.$parent.$parent.username = username;
-				});
-			}
-		},
-		ready: function () {
-			let _this = this;
-			io.getSocket(socket => {
-				_this.socket = socket;
-				if (_this.socket.connected) _this.init();
-				io.onConnect(() => _this.init());
-			});
-		}
-	}
+import EditUser from "../Modals/EditUser.vue";
+import io from "../../io";
+
+export default {
+  components: { EditUser },
+  data() {
+    return {
+      users: []
+    };
+  },
+  computed: {
+    ...mapState("modals", {
+      modals: state => state.modals.admin
+    })
+  },
+  methods: {
+    edit: function(user) {
+      this.editUser(user);
+      this.toggleModal({ sector: "admin", modal: "editUser" });
+    },
+    init: function() {
+      let _this = this;
+      _this.socket.emit("users.index", result => {
+        if (result.status === "success") _this.users = result.data;
+      });
+      _this.socket.emit("apis.joinAdminRoom", "users", () => {});
+      _this.socket.on("event:user.username.changed", username => {
+        _this.$parent.$parent.username = username;
+      });
+    },
+    ...mapActions("admin/users", ["editUser"]),
+    ...mapActions("modals", ["toggleModal"])
+  },
+  mounted: function() {
+    let _this = this;
+    io.getSocket(socket => {
+      _this.socket = socket;
+      if (_this.socket.connected) _this.init();
+      io.onConnect(() => _this.init());
+    });
+  }
+};
 </script>
 
 <style lang='scss' scoped>
-	body { font-family: 'Roboto', sans-serif; }
+body {
+  font-family: "Roboto", sans-serif;
+}
 
-	.user-avatar {
-		display: block;
-		max-width: 50px;
-		margin: 0 auto;
-	}
+.user-avatar {
+  display: block;
+  max-width: 50px;
+  margin: 0 auto;
+}
 
-	td { vertical-align: middle; }
+td {
+  vertical-align: middle;
+}
 
-	.is-primary:focus { background-color: #029ce3 !important; }
+.is-primary:focus {
+  background-color: #029ce3 !important;
+}
 </style>

+ 152 - 149
frontend/components/MainHeader.vue

@@ -1,157 +1,160 @@
 <template>
-	<nav class="nav is-info">
-		<div class="nav-left">
-			<a class="nav-item is-brand" href="#" v-link="{ path: '/' }">
-				Musare
-			</a>
-		</div>
-
-		<span class="nav-toggle" :class="{ 'is-active': isMobile }" @click="isMobile = !isMobile">
-			<span></span>
-			<span></span>
-			<span></span>
-		</span>
-
-		<div class="nav-right nav-menu" :class="{ 'is-active': isMobile }">
-			<a class="nav-item is-tab admin" href="#" v-link="{ path: '/admin' }" v-if="$parent.$parent.role === 'admin'">
-				<strong>Admin</strong>
-			</a>
-			<!--a class="nav-item is-tab" href="#">
-				About
-			</a-->
-			<a class="nav-item is-tab" href="#" v-link="{ path: '/team' }">
-				Team
-			</a>
-			<a class="nav-item is-tab" href="#" v-link="{ path: '/about' }">
-				About
-			</a>
-			<a class="nav-item is-tab" href="#" v-link="{ path: '/news' }">
-				News
-			</a>
-			<span class="grouped" v-if="$parent.$parent.loggedIn">
-				<a class="nav-item is-tab" href="#" v-link="{ path: '/u/' + $parent.$parent.username }">
-					Profile
-				</a>
-				<a class="nav-item is-tab" href="#" v-link="{ path: '/settings' }">
-					Settings
-				</a>
-				<a class="nav-item is-tab" href="#" @click="$parent.$parent.logout()">
-					Logout
-				</a>
-			</span>
-			<span class="grouped" v-else>
-				<a class="nav-item" href="#" @click="toggleModal('login')">
-					Login
-				</a>
-				<a class="nav-item" href="#" @click="toggleModal('register')">
-					Register
-				</a>
-			</span>
-		</div>
-	</nav>
+  <nav class="nav is-info">
+    <div class="nav-left">
+      <router-link class="nav-item is-brand" to="/">Musare</router-link>
+    </div>
+
+    <span class="nav-toggle" :class="{ 'is-active': isMobile }" v-on:click="isMobile = !isMobile">
+      <span></span>
+      <span></span>
+      <span></span>
+    </span>
+
+    <div class="nav-right nav-menu" :class="{ 'is-active': isMobile }">
+      <router-link
+        class="nav-item is-tab admin"
+        to="/admin"
+        v-if="$parent.$parent.role === 'admin'"
+      >
+        <strong>Admin</strong>
+      </router-link>
+      <router-link class="nav-item is-tab admin" to="/team">Team</router-link>
+      <router-link class="nav-item is-tab admin" to="/about">About</router-link>
+      <router-link class="nav-item is-tab admin" to="/news">News</router-link>
+      <span class="grouped" v-if="$parent.$parent.loggedIn">
+        <router-link
+          class="nav-item is-tab admin"
+          :to="{ name: 'profile', params: { username: $parent.$parent.username } }"
+        >Profile</router-link>
+        <router-link class="nav-item is-tab admin" to="/settings">Settings</router-link>
+        <a class="nav-item is-tab" href="#" v-on:click="$parent.$parent.logout()">Logout</a>
+      </span>
+      <span class="grouped" v-else>
+        <a
+          class="nav-item"
+          href="#"
+          v-on:click="toggleModal({
+            sector: 'header',
+            modal: 'login'
+          })"
+        >Login</a>
+        <a
+          class="nav-item"
+          href="#"
+          v-on:click="toggleModal({
+            sector: 'header',
+            modal: 'register'
+          })"
+        >Register</a>
+      </span>
+    </div>
+  </nav>
 </template>
 
 <script>
-	export default {
-		data() {
-			return {
-				isMobile: false
-			}
-		},
-		methods: {
-			toggleModal: function (type) {
-				this.$dispatch('toggleModal', type);
-			}
-		}
-	}
+import { mapState, mapActions } from "vuex";
+
+export default {
+  data() {
+    return {
+      isMobile: false
+    };
+  },
+  computed: mapState("modals", {
+    modals: state => state.modals.header
+  }),
+  methods: {
+    ...mapActions("modals", ["toggleModal"])
+  }
+};
 </script>
 
 <style lang="scss" scoped>
-	.nav {
-		background-color: #03a9f4;
-		height: 64px;
-
-		.nav-menu.is-active {
-			.nav-item {
-				color: #333;
-
-				&:hover {
-					color: #333;
-				}
-			}
-		}
-
-		.nav-toggle {
-			height: 64px;
-
-			&.is-active span {
-				background-color: #333;
-			}
-		}
-
-		.is-brand {
-			font-size: 2.1rem !important;
-			line-height: 64px !important;
-			padding: 0 20px;
-		}
-
-		.nav-item {
-			font-size: 15px;
-			color: hsl(0, 0%, 100%);
-
-			&:hover {
-				color: hsl(0, 0%, 100%);
-			}
-		}
-		.admin {
-			color: #424242;
-		}
-	}
-	.grouped {
-		margin: 0;
-		display: flex;
-		text-decoration: none;
-	}
-	.nightMode {
-		.nav {
-			background-color: #012332;
-			height: 64px;
-
-			.nav-menu.is-active {
-				.nav-item {
-					color: #333;
-
-					&:hover {
-						color: #333;
-					}
-				}
-			}
-
-			.nav-toggle {
-				height: 64px;
-
-				&.is-active span {
-					background-color: #333;
-				}
-			}
-
-			.is-brand {
-				font-size: 2.1rem !important;
-				line-height: 64px !important;
-				padding: 0 20px;
-			}
-
-			.nav-item {
-				font-size: 15px;
-				color: hsl(0, 0%, 100%);
-
-				&:hover {
-					color: hsl(0, 0%, 100%);
-				}
-			}
-			.admin strong {
-				color: #03a9f4;
-			}
-		}
-	}
+.nav {
+  background-color: #03a9f4;
+  height: 64px;
+
+  .nav-menu.is-active {
+    .nav-item {
+      color: #333;
+
+      &:hover {
+        color: #333;
+      }
+    }
+  }
+
+  .nav-toggle {
+    height: 64px;
+
+    &.is-active span {
+      background-color: #333;
+    }
+  }
+
+  .is-brand {
+    font-size: 2.1rem !important;
+    line-height: 64px !important;
+    padding: 0 20px;
+  }
+
+  .nav-item {
+    font-size: 15px;
+    color: hsl(0, 0%, 100%);
+
+    &:hover {
+      color: hsl(0, 0%, 100%);
+    }
+  }
+  .admin {
+    color: #424242;
+  }
+}
+.grouped {
+  margin: 0;
+  display: flex;
+  text-decoration: none;
+}
+.nightMode {
+  .nav {
+    background-color: #012332;
+    height: 64px;
+
+    .nav-menu.is-active {
+      .nav-item {
+        color: #333;
+
+        &:hover {
+          color: #333;
+        }
+      }
+    }
+
+    .nav-toggle {
+      height: 64px;
+
+      &.is-active span {
+        background-color: #333;
+      }
+    }
+
+    .is-brand {
+      font-size: 2.1rem !important;
+      line-height: 64px !important;
+      padding: 0 20px;
+    }
+
+    .nav-item {
+      font-size: 15px;
+      color: hsl(0, 0%, 100%);
+
+      &:hover {
+        color: hsl(0, 0%, 100%);
+      }
+    }
+    .admin strong {
+      color: #03a9f4;
+    }
+  }
+}
 </style>

+ 124 - 116
frontend/components/Modals/AddSongToPlaylist.vue

@@ -1,124 +1,132 @@
 <template>
-	<modal title='Add Song To Playlist'>
-		<div slot='body'>
-			<h4 class="songTitle">{{ $parent.currentSong.title }}</h4>
-			<h5 class="songArtist">{{ $parent.currentSong.artists }}</h5>
-			<aside class="menu">
-				<p class="menu-label">
-					Playlists
-				</p>
-				<ul class="menu-list">
-					<li v-for='playlist in playlistsArr'>
-						<div class='playlist'>
-							<span class='icon is-small' @click='removeSongFromPlaylist(playlist._id)' v-if='playlists[playlist._id].hasSong'>
-								<i class="material-icons">playlist_add_check</i>
-							</span>
-							<span class='icon' @click='addSongToPlaylist(playlist._id)' v-else>
-								<i class="material-icons">playlist_add</i>
-							</span>
-							{{ playlist.displayName }}
-						</div>
-					</li>
-				</ul>
-				</aside>
-		</div>
-	</modal>
+  <modal title="Add Song To Playlist">
+    <template v-slot:body>
+      <h4 class="songTitle">{{ $parent.currentSong.title }}</h4>
+      <h5 class="songArtist">{{ $parent.currentSong.artists }}</h5>
+      <aside class="menu">
+        <p class="menu-label">Playlists</p>
+        <ul class="menu-list">
+          <li v-for="(playlist, index) in playlistsArr" :key="index">
+            <div class="playlist">
+              <span
+                class="icon is-small"
+                v-on:click="removeSongFromPlaylist(playlist._id)"
+                v-if="playlists[playlist._id].hasSong"
+              >
+                <i class="material-icons">playlist_add_check</i>
+              </span>
+              <span class="icon" v-on:click="addSongToPlaylist(playlist._id)" v-else>
+                <i class="material-icons">playlist_add</i>
+              </span>
+              {{ playlist.displayName }}
+            </div>
+          </li>
+        </ul>
+      </aside>
+    </template>
+  </modal>
 </template>
 
 <script>
-	import { Toast } from 'vue-roaster';
-	import Modal from './Modal.vue';
-	import io from '../../io';
-	import auth from '../../auth';
+import { Toast } from "vue-roaster";
+import Modal from "./Modal.vue";
+import io from "../../io";
+import auth from "../../auth";
 
-	export default {
-		data() {
-			return {
-				playlists: {},
-				playlistsArr: [],
-				songId: null,
-				song: null
-			}
-		},
-		methods: {
-			addSongToPlaylist: function (playlistId) {
-				let _this = this;
-				this.socket.emit('playlists.addSongToPlaylist', this.$parent.currentSong.songId, playlistId, res => {
-					Toast.methods.addToast(res.message, 4000);
-					if (res.status === 'success') {
-						_this.playlists[playlistId].songs.push(_this.song);
-					}
-					_this.recalculatePlaylists();
-					//this.$parent.modals.addSongToPlaylist = false;
-				});
-			},
-			removeSongFromPlaylist: function (playlistId) {
-				let _this = this;
-				this.socket.emit('playlists.removeSongFromPlaylist', _this.songId, playlistId, res => {
-					Toast.methods.addToast(res.message, 4000);
-					if (res.status === 'success') {
-						_this.playlists[playlistId].songs.forEach((song, index) => {
-							if (song.songId === _this.songId) _this.playlists[playlistId].songs.splice(index, 1);
-						});
-					}
-					_this.recalculatePlaylists();
-					//this.$parent.modals.addSongToPlaylist = false;
-				});
-			},
-			recalculatePlaylists: function() {
-				let _this = this;
-				_this.playlistsArr = Object.values(_this.playlists).map((playlist) => {
-					let hasSong = false;
-					for (let i = 0; i < playlist.songs.length; i++) {
-						if (playlist.songs[i].songId === _this.songId) {
-							hasSong = true;
-						}
-					}
-					playlist.hasSong = hasSong;
-					_this.playlists[playlist._id] = playlist;
-					return playlist;
-				});
-			}
-		},
-		ready: function () {
-			let _this = this;
-			this.songId = this.$parent.currentSong.songId;
-			this.song = this.$parent.currentSong;
-			io.getSocket((socket) => {
-				_this.socket = socket;
-				_this.socket.emit('playlists.indexForUser', res => {
-					if (res.status === 'success') {
-						res.data.forEach((playlist) => {
-							_this.playlists[playlist._id] = playlist;
-						});
-						_this.recalculatePlaylists();
-					}
-				});
-			});
-		},
-		events: {
-			closeModal: function () {
-				this.$parent.modals.addSongToPlaylist = !this.$parent.modals.addSongToPlaylist;
-			}
-		},
-		components: { Modal }
-	}
+export default {
+  data() {
+    return {
+      playlists: {},
+      playlistsArr: [],
+      songId: null,
+      song: null
+    };
+  },
+  methods: {
+    addSongToPlaylist: function(playlistId) {
+      let _this = this;
+      this.socket.emit(
+        "playlists.addSongToPlaylist",
+        this.$parent.currentSong.songId,
+        playlistId,
+        res => {
+          Toast.methods.addToast(res.message, 4000);
+          if (res.status === "success") {
+            _this.playlists[playlistId].songs.push(_this.song);
+          }
+          _this.recalculatePlaylists();
+          //this.$parent.modals.addSongToPlaylist = false;
+        }
+      );
+    },
+    removeSongFromPlaylist: function(playlistId) {
+      let _this = this;
+      this.socket.emit(
+        "playlists.removeSongFromPlaylist",
+        _this.songId,
+        playlistId,
+        res => {
+          Toast.methods.addToast(res.message, 4000);
+          if (res.status === "success") {
+            _this.playlists[playlistId].songs.forEach((song, index) => {
+              if (song.songId === _this.songId)
+                _this.playlists[playlistId].songs.splice(index, 1);
+            });
+          }
+          _this.recalculatePlaylists();
+          //this.$parent.modals.addSongToPlaylist = false;
+        }
+      );
+    },
+    recalculatePlaylists: function() {
+      let _this = this;
+      _this.playlistsArr = Object.values(_this.playlists).map(playlist => {
+        let hasSong = false;
+        for (let i = 0; i < playlist.songs.length; i++) {
+          if (playlist.songs[i].songId === _this.songId) {
+            hasSong = true;
+          }
+        }
+        playlist.hasSong = hasSong;
+        _this.playlists[playlist._id] = playlist;
+        return playlist;
+      });
+    }
+  },
+  mounted: function() {
+    let _this = this;
+    this.songId = this.$parent.currentSong.songId;
+    this.song = this.$parent.currentSong;
+    io.getSocket(socket => {
+      _this.socket = socket;
+      _this.socket.emit("playlists.indexForUser", res => {
+        if (res.status === "success") {
+          res.data.forEach(playlist => {
+            _this.playlists[playlist._id] = playlist;
+          });
+          _this.recalculatePlaylists();
+        }
+      });
+    });
+  },
+  components: { Modal }
+};
 </script>
 
-<style type='scss' scoped>
-	.icon.is-small {
-		margin-right: 10px !important;
-	}
-	.songTitle {
-		font-size: 22px;
-		padding: 0 10px;
-	}
-	.songArtist {
-		font-size: 19px;
-		font-weight: 200;
-		padding: 0 10px;
-	}
-	.menu-label {
-		font-size: 16px;
-	}
+<style lang='scss' scoped>
+.icon.is-small {
+  margin-right: 10px !important;
+}
+.songTitle {
+  font-size: 22px;
+  padding: 0 10px;
+}
+.songArtist {
+  font-size: 19px;
+  font-weight: 200;
+  padding: 0 10px;
+}
+.menu-label {
+  font-size: 16px;
+}
 </style>

+ 163 - 136
frontend/components/Modals/AddSongToQueue.vue

@@ -1,145 +1,172 @@
 <template>
-	<modal title='Add Song To Queue'>
-		<div slot='body'>
-			<aside class='menu' v-if='$parent.$parent.loggedIn && $parent.type === "community"'>
-				<ul class='menu-list'>
-					<li v-for='playlist in playlists' track-by='$index'>
-						<a href='#' target='_blank' @click='$parent.editPlaylist(playlist._id)'>{{ playlist.displayName }}</a>
-						<div class='controls'>
-							<a href='#' @click='selectPlaylist(playlist._id)' v-if="!isPlaylistSelected(playlist._id)"><i class='material-icons'>panorama_fish_eye</i></a>
-							<a href='#' @click='unSelectPlaylist()' v-if="isPlaylistSelected(playlist._id)"><i class='material-icons'>lens</i></a>
-						</div>
-					</li>
-				</ul>
-				<br />
-			</aside>
-			<div class="control is-grouped">
-				<p class="control is-expanded">
-					<input class="input" type="text" placeholder="YouTube Query" v-model='querySearch' autofocus @keyup.enter='submitQuery()'>
-				</p>
-				<p class="control">
-					<a class="button is-info" @click="submitQuery()" href='#'>
-						Search
-					</a>
-				</p>
-			</div>
-			<table class="table">
-				<tbody>
-				<tr v-for="result in queryResults">
-					<td>
-						<img :src="result.thumbnail" />
-					</td>
-					<td>{{ result.title }}</td>
-					<td>
-						<a class="button is-success" @click="addSongToQueue(result.id)" href='#'>
-							Add
-						</a>
-					</td>
-				</tr>
-				</tbody>
-			</table>
-		</div>
-	</modal>
+  <modal title="Add Song To Queue">
+    <div slot="body">
+      <aside class="menu" v-if="$parent.$parent.loggedIn && $parent.type === 'community'">
+        <ul class="menu-list">
+          <li v-for="(playlist, index) in playlists" :key="index">
+            <a
+              href="#"
+              target="_blank"
+              v-on:click="$parent.editPlaylist(playlist._id)"
+            >{{ playlist.displayName }}</a>
+            <div class="controls">
+              <a
+                href="#"
+                v-on:click="selectPlaylist(playlist._id)"
+                v-if="!isPlaylistSelected(playlist._id)"
+              >
+                <i class="material-icons">panorama_fish_eye</i>
+              </a>
+              <a href="#" v-on:click="unSelectPlaylist()" v-if="isPlaylistSelected(playlist._id)">
+                <i class="material-icons">lens</i>
+              </a>
+            </div>
+          </li>
+        </ul>
+        <br />
+      </aside>
+      <div class="control is-grouped">
+        <p class="control is-expanded">
+          <input
+            class="input"
+            type="text"
+            placeholder="YouTube Query"
+            v-model="querySearch"
+            autofocus
+            @keyup.enter="submitQuery()"
+          />
+        </p>
+        <p class="control">
+          <a class="button is-info" v-on:click="submitQuery()" href="#">Search</a>
+        </p>
+      </div>
+      <table class="table">
+        <tbody>
+          <tr v-for="(result, index) in queryResults" :key="index">
+            <td>
+              <img :src="result.thumbnail" />
+            </td>
+            <td>{{ result.title }}</td>
+            <td>
+              <a class="button is-success" v-on:click="addSongToQueue(result.id)" href="#">Add</a>
+            </td>
+          </tr>
+        </tbody>
+      </table>
+    </div>
+  </modal>
 </template>
 
 <script>
-	import { Toast } from 'vue-roaster';
-	import Modal from './Modal.vue';
-	import io from '../../io';
-	import auth from '../../auth';
+import { Toast } from "vue-roaster";
+import Modal from "./Modal.vue";
+import io from "../../io";
+import auth from "../../auth";
 
-	export default {
-		data() {
-			return {
-				querySearch: '',
-				queryResults: [],
-				playlists: [],
-				privatePlaylistQueueSelected: null
-			}
-		},
-		methods: {
-			isPlaylistSelected: function(playlistId) {
-				return this.privatePlaylistQueueSelected === playlistId;
-			},
-			selectPlaylist: function (playlistId) {
-				let _this = this;
-				if (_this.$parent.type === 'community') {
-					_this.privatePlaylistQueueSelected = playlistId;
-					_this.$parent.privatePlaylistQueueSelected = playlistId;
-					_this.$parent.addFirstPrivatePlaylistSongToQueue();
-				}
-			},
-			unSelectPlaylist: function () {
-				let _this = this;
-				if (_this.$parent.type === 'community') {
-					_this.privatePlaylistQueueSelected = null;
-					_this.$parent.privatePlaylistQueueSelected = null;
-				}
-			},
-			addSongToQueue: function (songId) {
-				let _this = this;
-				if (_this.$parent.type === 'community') {
-					_this.socket.emit('stations.addToQueue', _this.$parent.station._id, songId, data => {
-						if (data.status !== 'success') Toast.methods.addToast(`Error: ${data.message}`, 8000);
-						else Toast.methods.addToast(`${data.message}`, 4000);
-					});
-				} else {
-					_this.socket.emit('queueSongs.add', songId, data => {
-						if (data.status !== 'success') Toast.methods.addToast(`Error: ${data.message}`, 8000);
-						else Toast.methods.addToast(`${data.message}`, 4000);
-					});
-				}
-			},
-			submitQuery: function () {
-				let _this = this;
-				let query = _this.querySearch;
-				if (query.indexOf('&index=') !== -1) {
-					query = query.split('&index=');
-					query.pop();
-					query = query.join('');
-				}
-				if (query.indexOf('&list=') !== -1) {
-					query = query.split('&list=');
-					query.pop();
-					query = query.join('');
-				}
-				_this.socket.emit('apis.searchYoutube', query, results => {
-					results = results.data;
-					_this.queryResults = [];
-					for (let i = 0; i < results.items.length; i++) {
-						_this.queryResults.push({
-							id: results.items[i].id.videoId,
-							url: `https://www.youtube.com/watch?v=${this.id}`,
-							title: results.items[i].snippet.title,
-							thumbnail: results.items[i].snippet.thumbnails.default.url
-						});
-					}
-				});
-			}
-		},
-		ready: function () {
-			let _this = this;
-			io.getSocket((socket) => {
-				_this.socket = socket;
-				_this.socket.emit('playlists.indexForUser', res => {
-					if (res.status === 'success') _this.playlists = res.data;
-				});
-				_this.privatePlaylistQueueSelected = _this.$parent.privatePlaylistQueueSelected;
-			});
-		},
-		events: {
-			closeModal: function () {
-				this.$parent.modals.addSongToQueue = !this.$parent.modals.addSongToQueue;
-			}
-		},
-		components: { Modal }
-	}
+export default {
+  data() {
+    return {
+      querySearch: "",
+      queryResults: [],
+      playlists: [],
+      privatePlaylistQueueSelected: null
+    };
+  },
+  methods: {
+    isPlaylistSelected: function(playlistId) {
+      return this.privatePlaylistQueueSelected === playlistId;
+    },
+    selectPlaylist: function(playlistId) {
+      let _this = this;
+      if (_this.$parent.type === "community") {
+        _this.privatePlaylistQueueSelected = playlistId;
+        _this.$parent.privatePlaylistQueueSelected = playlistId;
+        _this.$parent.addFirstPrivatePlaylistSongToQueue();
+      }
+    },
+    unSelectPlaylist: function() {
+      let _this = this;
+      if (_this.$parent.type === "community") {
+        _this.privatePlaylistQueueSelected = null;
+        _this.$parent.privatePlaylistQueueSelected = null;
+      }
+    },
+    addSongToQueue: function(songId) {
+      let _this = this;
+      if (_this.$parent.type === "community") {
+        _this.socket.emit(
+          "stations.addToQueue",
+          _this.$parent.station._id,
+          songId,
+          data => {
+            if (data.status !== "success")
+              Toast.methods.addToast(`Error: ${data.message}`, 8000);
+            else Toast.methods.addToast(`${data.message}`, 4000);
+          }
+        );
+      } else {
+        _this.socket.emit("queueSongs.add", songId, data => {
+          if (data.status !== "success")
+            Toast.methods.addToast(`Error: ${data.message}`, 8000);
+          else Toast.methods.addToast(`${data.message}`, 4000);
+        });
+      }
+    },
+    submitQuery: function() {
+      console.log("submit query");
+      let _this = this;
+      let query = _this.querySearch;
+      if (query.indexOf("&index=") !== -1) {
+        query = query.split("&index=");
+        query.pop();
+        query = query.join("");
+      }
+      if (query.indexOf("&list=") !== -1) {
+        query = query.split("&list=");
+        query.pop();
+        query = query.join("");
+      }
+      _this.socket.emit("apis.searchYoutube", query, results => {
+        // check for error
+        results = results.data;
+        _this.queryResults = [];
+        for (let i = 0; i < results.items.length; i++) {
+          _this.queryResults.push({
+            id: results.items[i].id.videoId,
+            url: `https://www.youtube.com/watch?v=${this.id}`,
+            title: results.items[i].snippet.title,
+            thumbnail: results.items[i].snippet.thumbnails.default.url
+          });
+        }
+      });
+    }
+  },
+  mounted: function() {
+    let _this = this;
+    io.getSocket(socket => {
+      _this.socket = socket;
+      _this.socket.emit("playlists.indexForUser", res => {
+        if (res.status === "success") _this.playlists = res.data;
+      });
+      _this.privatePlaylistQueueSelected =
+        _this.$parent.privatePlaylistQueueSelected;
+    });
+  },
+  events: {
+    closeModal: function() {
+      this.$parent.modals.addSongToQueue = !this.$parent.modals.addSongToQueue;
+    }
+  },
+  components: { Modal }
+};
 </script>
 
-<style type='scss' scoped>
-	tr td {
-		vertical-align: middle;
+<style lang='scss' scoped>
+tr td {
+  vertical-align: middle;
 
-		img { width: 55px; }
-	}
+  img {
+    width: 55px;
+  }
+}
 </style>

+ 120 - 81
frontend/components/Modals/CreateCommunityStation.vue

@@ -1,91 +1,130 @@
 <template>
-	<modal title='Create Community Station'>
-		<div slot='body'>
-			<!-- validation to check if exists http://bulma.io/documentation/elements/form/ -->
-			<label class='label'>Name (unique lowercase station id)</label>
-			<p class='control'>
-				<input class='input' type='text' placeholder='Name...' v-model='newCommunity.name' autofocus>
-			</p>
-			<label class='label'>Display Name</label>
-			<p class='control'>
-				<input class='input' type='text' placeholder='Display name...' v-model='newCommunity.displayName'>
-			</p>
-			<label class='label'>Description</label>
-			<p class='control'>
-				<input class='input' type='text' placeholder='Description...' v-model='newCommunity.description' @keyup.enter="submitModal()">
-			</p>
-		</div>
-		<div slot='footer'>
-			<a class='button is-primary' @click='submitModal()'>Create</a>
-		</div>
-	</modal>
+  <modal title="Create Community Station">
+    <template v-slot:body>
+      <!-- validation to check if exists http://bulma.io/documentation/elements/form/ -->
+      <label class="label">Name (unique lowercase station id)</label>
+      <p class="control">
+        <input
+          class="input"
+          type="text"
+          placeholder="Name..."
+          v-model="newCommunity.name"
+          autofocus
+        />
+      </p>
+      <label class="label">Display Name</label>
+      <p class="control">
+        <input
+          class="input"
+          type="text"
+          placeholder="Display name..."
+          v-model="newCommunity.displayName"
+        />
+      </p>
+      <label class="label">Description</label>
+      <p class="control">
+        <input
+          class="input"
+          type="text"
+          placeholder="Description..."
+          v-model="newCommunity.description"
+          @keyup.enter="submitModal()"
+        />
+      </p>
+    </template>
+    <template v-slot:footer>
+      <a class="button is-primary" v-on:click="submitModal()">Create</a>
+    </template>
+  </modal>
 </template>
 
 <script>
-	import { Toast } from 'vue-roaster';
-	import Modal from './Modal.vue';
-	import io from '../../io';
-	import validation from '../../validation';
+import { Toast } from "vue-roaster";
+import Modal from "./Modal.vue";
+import io from "../../io";
+import validation from "../../validation";
 
-	export default {
-		components: { Modal },
-		data() {
-			return {
-				newCommunity: {
-					name: '',
-					displayName: '',
-					description: ''
-				}
-			}
-		},
-		ready: function () {
-			let _this = this;
-			io.getSocket((socket) => {
-				_this.socket = socket;
-			});
-		},
-		methods: {
-			toggleModal: function () {
-				this.$parent.modals.createCommunityStation = !this.$parent.modals.createCommunityStation;
-			},
-			submitModal: function () {
-				const name = this.newCommunity.name;
-				const displayName = this.newCommunity.displayName;
-				const description = this.newCommunity.description;
-				if (!name || !displayName || !description) return Toast.methods.addToast('Please fill in all fields', 8000);
+export default {
+  components: { Modal },
+  data() {
+    return {
+      newCommunity: {
+        name: "",
+        displayName: "",
+        description: ""
+      }
+    };
+  },
+  mounted: function() {
+    let _this = this;
+    io.getSocket(socket => {
+      _this.socket = socket;
+    });
+  },
+  methods: {
+    submitModal: function() {
+      const name = this.newCommunity.name;
+      const displayName = this.newCommunity.displayName;
+      const description = this.newCommunity.description;
+      if (!name || !displayName || !description)
+        return Toast.methods.addToast("Please fill in all fields", 8000);
 
-				if (!validation.isLength(name, 2, 16)) return Toast.methods.addToast('Name must have between 2 and 16 characters.', 8000);
-				if (!validation.regex.az09_.test(name)) return Toast.methods.addToast('Invalid name format. Allowed characters: a-z, 0-9 and _.', 8000);
+      if (!validation.isLength(name, 2, 16))
+        return Toast.methods.addToast(
+          "Name must have between 2 and 16 characters.",
+          8000
+        );
+      if (!validation.regex.az09_.test(name))
+        return Toast.methods.addToast(
+          "Invalid name format. Allowed characters: a-z, 0-9 and _.",
+          8000
+        );
 
+      if (!validation.isLength(displayName, 2, 32))
+        return Toast.methods.addToast(
+          "Display name must have between 2 and 32 characters.",
+          8000
+        );
+      if (!validation.regex.azAZ09_.test(displayName))
+        return Toast.methods.addToast(
+          "Invalid display name format. Allowed characters: a-z, A-Z, 0-9 and _.",
+          8000
+        );
 
-				if (!validation.isLength(displayName, 2, 32)) return Toast.methods.addToast('Display name must have between 2 and 32 characters.', 8000);
-				if (!validation.regex.azAZ09_.test(displayName)) return Toast.methods.addToast('Invalid display name format. Allowed characters: a-z, A-Z, 0-9 and _.', 8000);
+      if (!validation.isLength(description, 2, 200))
+        return Toast.methods.addToast(
+          "Description must have between 2 and 200 characters.",
+          8000
+        );
+      let characters = description.split("");
+      characters = characters.filter(function(character) {
+        return character.charCodeAt(0) === 21328;
+      });
+      if (characters.length !== 0)
+        return Toast.methods.addToast(
+          "Invalid description format. Swastika's are not allowed.",
+          8000
+        );
 
-
-				if (!validation.isLength(description, 2, 200)) return Toast.methods.addToast('Description must have between 2 and 200 characters.', 8000);
-				let characters = description.split("");
-				characters = characters.filter(function(character) {
-					return character.charCodeAt(0) === 21328;
-				});
-				if (characters.length !== 0) return Toast.methods.addToast('Invalid description format. Swastika\'s are not allowed.', 8000);
-
-
-				this.socket.emit('stations.create', {
-					name: name,
-					type: 'community',
-					displayName: displayName,
-					description: description
-				}, res => {
-					if (res.status === 'success') Toast.methods.addToast(`You have added the station successfully`, 4000);
-					else Toast.methods.addToast(res.message, 4000);
-				});
-				this.toggleModal();
-			}
-		},
-		events: {
-			closeModal: function() {
-				this.$parent.modals.createCommunityStation = !this.$parent.modals.createCommunityStation;
-			}
-		}
-	}
+      this.socket.emit(
+        "stations.create",
+        {
+          name: name,
+          type: "community",
+          displayName: displayName,
+          description: description
+        },
+        res => {
+          if (res.status === "success")
+            Toast.methods.addToast(
+              `You have added the station successfully`,
+              4000
+            );
+          else Toast.methods.addToast(res.message, 4000);
+        }
+      );
+      //   this.toggleModal();
+    }
+  }
+};
 </script>

+ 12 - 12
frontend/components/Modals/EditNews.vue

@@ -14,22 +14,22 @@
 					<label class='label'>Bugs</label>
 					<p class='control has-addons'>
 						<input class='input' id='edit-bugs' type='text' placeholder='Bug' v-on:keyup.enter='addChange("bugs")'>
-						<a class='button is-info' href='#' @click='addChange("bugs")'>Add</a>
+						<a class='button is-info' href='#' v-on:click='addChange("bugs")'>Add</a>
 					</p>
 					<span class='tag is-info' v-for='(index, bug) in $parent.editing.bugs' track-by='$index'>
 						{{ bug }}
-						<button class='delete is-info' @click='removeChange("bugs", index)'></button>
+						<button class='delete is-info' v-on:click='removeChange("bugs", index)'></button>
 					</span>
 				</div>
 				<div class="column">
 					<label class='label'>Features</label>
 					<p class='control has-addons'>
 						<input class='input' id='edit-features' type='text' placeholder='Feature' v-on:keyup.enter='addChange("features")'>
-						<a class='button is-info' href='#' @click='addChange("features")'>Add</a>
+						<a class='button is-info' href='#' v-on:click='addChange("features")'>Add</a>
 					</p>
 					<span class='tag is-info' v-for='(index, feature) in $parent.editing.features' track-by='$index'>
 						{{ feature }}
-						<button class='delete is-info' @click='removeChange("features", index)'></button>
+						<button class='delete is-info' v-on:click='removeChange("features", index)'></button>
 					</span>
 				</div>
 			</div>
@@ -39,36 +39,36 @@
 					<label class='label'>Improvements</label>
 					<p class='control has-addons'>
 						<input class='input' id='edit-improvements' type='text' placeholder='Improvement' v-on:keyup.enter='addChange("improvements")'>
-						<a class='button is-info' href='#' @click='addChange("improvements")'>Add</a>
+						<a class='button is-info' href='#' v-on:click='addChange("improvements")'>Add</a>
 					</p>
 					<span class='tag is-info' v-for='(index, improvement) in $parent.editing.improvements' track-by='$index'>
 						{{ improvement }}
-						<button class='delete is-info' @click='removeChange("improvements", index)'></button>
+						<button class='delete is-info' v-on:click='removeChange("improvements", index)'></button>
 					</span>
 				</div>
 				<div class="column">
 					<label class='label'>Upcoming</label>
 					<p class='control has-addons'>
 						<input class='input' id='edit-upcoming' type='text' placeholder='Upcoming' v-on:keyup.enter='addChange("upcoming")'>
-						<a class='button is-info' href='#' @click='addChange("upcoming")'>Add</a>
+						<a class='button is-info' href='#' v-on:click='addChange("upcoming")'>Add</a>
 					</p>
 					<span class='tag is-info' v-for='(index, upcoming) in $parent.editing.upcoming' track-by='$index'>
 						{{ upcoming }}
-						<button class='delete is-info' @click='removeChange("upcoming", index)'></button>
+						<button class='delete is-info' v-on:click='removeChange("upcoming", index)'></button>
 					</span>
 				</div>
 			</div>
 		</div>
 		<div slot='footer'>
-			<button class='button is-success' @click='$parent.updateNews(false)'>
+			<button class='button is-success' v-on:click='$parent.updateNews(false)'>
 				<i class='material-icons save-changes'>done</i>
 				<span>&nbsp;Save</span>
 			</button>
-			<button class='button is-success' @click='$parent.updateNews(true)'>
+			<button class='button is-success' v-on:click='$parent.updateNews(true)'>
 				<i class='material-icons save-changes'>done</i>
 				<span>&nbsp;Save and close</span>
 			</button>
-			<button class='button is-danger' @click='$parent.toggleModal()'>
+			<button class='button is-danger' v-on:click='$parent.toggleModal()'>
 				<span>&nbsp;Close</span>
 			</button>
 		</div>
@@ -103,7 +103,7 @@
 	}
 </script>
 
-<style type='scss' scoped>
+<style lang='scss' scoped>
 	input[type=range] {
 		-webkit-appearance: none;
 		width: 100%;

+ 603 - 524
frontend/components/Modals/EditSong.vue

@@ -1,531 +1,610 @@
 <template>
-	<div>
-		<modal title='Edit Song'>
-			<div slot='body'>
-				<h5 class='has-text-centered'>Video Preview</h5>
-				<div class='video-container'>
-					<div id='player'></div>
-					<div class="controls">
-						<form action="#">
-							<p style="margin-top: 0; position: relative;">
-								<input type="range" id="volumeSlider" min="0" max="100" class="active" v-on:change="changeVolume()" v-on:input="changeVolume()">
-							</p>
-						</form>
-						<p class='control has-addons'>
-							<button class='button' @click='settings("pause")' v-if='!video.paused'>
-								<i class='material-icons'>pause</i>
-							</button>
-							<button class='button' @click='settings("play")' v-if='video.paused'>
-								<i class='material-icons'>play_arrow</i>
-							</button>
-							<button class='button' @click='settings("stop")'>
-								<i class='material-icons'>stop</i>
-							</button>
-							<button class='button' @click='settings("skipToLast10Secs")'>
-								<i class='material-icons'>fast_forward</i>
-							</button>
-						</p>
-					</div>
-				</div>
-				<h5 class='has-text-centered'>Thumbnail Preview</h5>
-				<img class='thumbnail-preview' :src='editing.song.thumbnail' onerror="this.src='/assets/notes-transparent.png'">
-
-				<div class="control is-horizontal">
-					<div class="control-label">
-						<label class="label">Thumbnail URL</label>
-					</div>
-					<div class="control">
-						<input class='input' type='text' v-model='editing.song.thumbnail'>
-					</div>
-				</div>
-
-				<h5 class='has-text-centered'>Edit Information</h5>
-
-				<p class='control'>
-					<label class='checkbox'>
-						<input type='checkbox' v-model='editing.song.explicit'>
-						Explicit
-					</label>
-				</p>
-				<label class='label'>Song ID & Title</label>
-				<div class="control is-horizontal">
-					<div class="control is-grouped">
-						<p class='control is-expanded'>
-							<input class='input' type='text' v-model='editing.song.songId'>
-						</p>
-						<p class='control is-expanded'>
-							<input class='input' type='text' v-model='editing.song.title' autofocus>
-						</p>
-					</div>
-				</div>
-				<label class='label'>Artists & Genres</label>
-				<div class='control is-horizontal'>
-					<div class='control is-grouped artist-genres'>
-						<div>
-							<p class='control has-addons'>
-								<input class='input' id='new-artist' type='text' placeholder='Artist'>
-								<button class='button is-info' @click='addTag("artists")'>Add Artist</button>
-							</p>
-							<span class='tag is-info' v-for='(index, artist) in editing.song.artists' track-by='$index'>
-								{{ artist }}
-								<button class='delete is-info' @click='removeTag("artists", index)'></button>
-							</span>
-						</div>
-						<div>
-							<p class='control has-addons'>
-								<input class='input' id='new-genre' type='text' placeholder='Genre'>
-								<button class='button is-info' @click='addTag("genres")'>Add Genre</button>
-							</p>
-							<span class='tag is-info' v-for='(index, genre) in editing.song.genres' track-by='$index'>
-								{{ genre }}
-								<button class='delete is-info' @click='removeTag("genres", index)'></button>
-							</span>
-						</div>
-					</div>
-				</div>
-				<label class='label'>Song Duration</label>
-				<p class='control'>
-					<input class='input' type='text' v-model='editing.song.duration'>
-				</p>
-				<label class='label'>Skip Duration</label>
-				<p class='control'>
-					<input class='input' type='text' v-model='editing.song.skipDuration'>
-				</p>
-				<article class="message" v-if="editing.type === 'songs'">
-					<div class="message-body">
-						<span class="reports-length">
-							{{ reports.length }}
-							<span v-if="reports.length > 1 || reports.length <= 0">&nbsp;Reports</span>
-							<span v-else>&nbsp;Report</span>
-						</span>
-						<div v-for='report in reports'>
-							<a :href='`/admin/reports?id=${report}`' class='report-link'>Report - {{ report }}</a>
-						</div>
-					</div>
-				</article>
-				<hr />
-				<h5 class='has-text-centered'>Spotify Information</h5>
-				<label class='label'>Song title</label>
-				<p class='control'>
-					<input class='input' type='text' v-model='spotify.title'>
-				</p>
-				<label class='label'>Song artist (1 artist full name)</label>
-				<p class='control'>
-					<input class='input' type='text' v-model='spotify.artist'>
-				</p>
-				<button class='button is-success' @click='getSpotifySongs()'>
-					Get Spotify songs
-				</button>
-				<hr />
-				<article class="media" v-for='song in spotify.songs'>
-					<figure class="media-left">
-						<p class="image is-64x64">
-							<img :src="song.thumbnail" onerror="this.src='/assets/notes-transparent.png'">
-						</p>
-					</figure>
-					<div class="media-content">
-						<div class="content">
-							<p>
-								<strong>{{song.title}}</strong>
-								<br />
-								<small>Artists: {{song.artists}}</small>, <small>Duration: {{song.duration}}</small>, <small>Explicit: {{song.explicit}}</small>
-								<br />
-								<small>Thumbnail: {{song.thumbnail}}</small>
-							</p>
-						</div>
-					</div>
-				</article>
-			</div>
-			<div slot='footer'>
-				<button class='button is-success' @click='save(editing.song, false)'>
-					<i class='material-icons save-changes'>done</i>
-					<span>&nbsp;Save</span>
-				</button>
-				<button class='button is-success' @click='save(editing.song, true)'>
-					<i class='material-icons save-changes'>done</i>
-					<span>&nbsp;Save and close</span>
-				</button>
-				<button class='button is-danger' @click='$parent.toggleModal()'>
-					<span>&nbsp;Close</span>
-				</button>
-			</div>
-		</modal>
-	</div>
+  <div>
+    <modal title="Edit Song">
+      <div slot="body">
+        <h5 class="has-text-centered">Video Preview</h5>
+        <div class="video-container">
+          <div id="player"></div>
+          <div class="controls">
+            <form action="#">
+              <p style="margin-top: 0; position: relative;">
+                <input
+                  type="range"
+                  id="volumeSlider"
+                  min="0"
+                  max="100"
+                  class="active"
+                  v-on:change="changeVolume()"
+                  v-on:input="changeVolume()"
+                />
+              </p>
+            </form>
+            <p class="control has-addons">
+              <button class="button" v-on:click="settings('pause')" v-if="!video.paused">
+                <i class="material-icons">pause</i>
+              </button>
+              <button class="button" v-on:click="settings('play')" v-if="video.paused">
+                <i class="material-icons">play_arrow</i>
+              </button>
+              <button class="button" v-on:click="settings('stop')">
+                <i class="material-icons">stop</i>
+              </button>
+              <button class="button" v-on:click="settings('skipToLast10Secs')">
+                <i class="material-icons">fast_forward</i>
+              </button>
+            </p>
+          </div>
+        </div>
+        <h5 class="has-text-centered">Thumbnail Preview</h5>
+        <img
+          class="thumbnail-preview"
+          :src="editing.song.thumbnail"
+          onerror="this.src='/assets/notes-transparent.png'"
+        />
+
+        <div class="control is-horizontal">
+          <div class="control-label">
+            <label class="label">Thumbnail URL</label>
+          </div>
+          <div class="control">
+            <input class="input" type="text" v-model="editing.song.thumbnail" />
+          </div>
+        </div>
+
+        <h5 class="has-text-centered">Edit Information</h5>
+
+        <p class="control">
+          <label class="checkbox">
+            <input type="checkbox" v-model="editing.song.explicit" />
+            Explicit
+          </label>
+        </p>
+        <label class="label">Song ID & Title</label>
+        <div class="control is-horizontal">
+          <div class="control is-grouped">
+            <p class="control is-expanded">
+              <input class="input" type="text" v-model="editing.song.songId" />
+            </p>
+            <p class="control is-expanded">
+              <input class="input" type="text" v-model="editing.song.title" autofocus />
+            </p>
+          </div>
+        </div>
+        <label class="label">Artists & Genres</label>
+        <div class="control is-horizontal">
+          <div class="control is-grouped artist-genres">
+            <div>
+              <p class="control has-addons">
+                <input class="input" id="new-artist" type="text" placeholder="Artist" />
+                <button class="button is-info" v-on:click="addTag('artists')">Add Artist</button>
+              </p>
+              <span
+                class="tag is-info"
+                v-for="(artist, index) in editing.song.artists"
+                :key="index"
+              >
+                {{ artist }}
+                <button class="delete is-info" v-on:click="removeTag('artists', index)"></button>
+              </span>
+            </div>
+            <div>
+              <p class="control has-addons">
+                <input class="input" id="new-genre" type="text" placeholder="Genre" />
+                <button class="button is-info" v-on:click="addTag('genres')">Add Genre</button>
+              </p>
+              <span class="tag is-info" v-for="(genre, index) in editing.song.genres" :key="index">
+                {{ genre }}
+                <button class="delete is-info" v-on:click="removeTag('genres', index)"></button>
+              </span>
+            </div>
+          </div>
+        </div>
+        <label class="label">Song Duration</label>
+        <p class="control">
+          <input class="input" type="text" v-model="editing.song.duration" />
+        </p>
+        <label class="label">Skip Duration</label>
+        <p class="control">
+          <input class="input" type="text" v-model="editing.song.skipDuration" />
+        </p>
+        <article class="message" v-if="editing.type === 'songs'">
+          <div class="message-body">
+            <span class="reports-length">
+              {{ reports.length }}
+              <span
+                v-if="reports.length > 1 || reports.length <= 0"
+              >&nbsp;Reports</span>
+              <span v-else>&nbsp;Report</span>
+            </span>
+            <div v-for="(report, index) in reports" :key="index">
+              <a :href="`/admin/reports?id=${report}`" class="report-link">Report - {{ report }}</a>
+            </div>
+          </div>
+        </article>
+        <hr />
+        <h5 class="has-text-centered">Spotify Information</h5>
+        <label class="label">Song title</label>
+        <p class="control">
+          <input class="input" type="text" v-model="spotify.title" />
+        </p>
+        <label class="label">Song artist (1 artist full name)</label>
+        <p class="control">
+          <input class="input" type="text" v-model="spotify.artist" />
+        </p>
+        <button class="button is-success" v-on:click="getSpotifySongs()">Get Spotify songs</button>
+        <hr />
+        <article class="media" v-for="(song, index) in spotify.songs" :key="index">
+          <figure class="media-left">
+            <p class="image is-64x64">
+              <img :src="song.thumbnail" onerror="this.src='/assets/notes-transparent.png'" />
+            </p>
+          </figure>
+          <div class="media-content">
+            <div class="content">
+              <p>
+                <strong>{{song.title}}</strong>
+                <br />
+                <small>Artists: {{song.artists}}</small>,
+                <small>Duration: {{song.duration}}</small>,
+                <small>Explicit: {{song.explicit}}</small>
+                <br />
+                <small>Thumbnail: {{song.thumbnail}}</small>
+              </p>
+            </div>
+          </div>
+        </article>
+      </div>
+      <div slot="footer">
+        <button class="button is-success" v-on:click="save(editing.song, false)">
+          <i class="material-icons save-changes">done</i>
+          <span>&nbsp;Save</span>
+        </button>
+        <button class="button is-success" v-on:click="save(editing.song, true)">
+          <i class="material-icons save-changes">done</i>
+          <span>&nbsp;Save and close</span>
+        </button>
+        <button
+          class="button is-danger"
+          v-on:click="toggleModal({ sector: 'admin', modal: 'editSong' })"
+        >
+          <span>&nbsp;Close</span>
+        </button>
+      </div>
+    </modal>
+  </div>
 </template>
 
 <script>
-	import io from '../../io';
-	import validation from '../../validation';
-	import { Toast } from 'vue-roaster';
-	import Modal from './Modal.vue';
-
-	export default {
-		components: { Modal },
-		data() {
-			return {
-				editing: {
-					index: 0,
-					song: {},
-					type: ''
-				},
-				reports: 0,
-				video: {
-					player: null,
-					paused: true,
-					playerReady: false,
-					autoPlayed: false
-				},
-				spotify: {
-					title: '',
-					artist: '',
-					songs: []
-				}
-			}
-		},
-		methods: {
-			save: function (song, close) {
-				let _this = this;
-
-				if (!song.title) return Toast.methods.addToast('Please fill in all fields', 8000);
-				if (!song.thumbnail) return Toast.methods.addToast('Please fill in all fields', 8000);
-
-
-				// Title
-				if (!validation.isLength(song.title, 1, 64)) return Toast.methods.addToast('Title must have between 1 and 64 characters.', 8000);
-				if (!validation.regex.ascii.test(song.title)) return Toast.methods.addToast('Invalid title format. Only ascii characters are allowed.', 8000);
-
-
-				// Artists
-				if (song.artists.length < 1 || song.artists.length > 10) return Toast.methods.addToast('Invalid artists. You must have at least 1 artist and a maximum of 10 artists.', 8000);
-				let error;
-				song.artists.forEach((artist) => {
-					if (!validation.isLength(artist, 1, 32)) return error = 'Artist must have between 1 and 32 characters.';
-					if (!validation.regex.ascii.test(artist)) return error = 'Invalid artist format. Only ascii characters are allowed.';
-					if (artist === 'NONE') return error = 'Invalid artist format. Artists are not allowed to be named "NONE".';
-				});
-				if (error) return Toast.methods.addToast(error, 8000);
-
-
-				// Genres
-				error = undefined;
-				song.genres.forEach((genre) => {
-					if (!validation.isLength(genre, 1, 16)) return error = 'Genre must have between 1 and 16 characters.';
-					if (!validation.regex.az09_.test(genre)) return error = 'Invalid genre format. Only ascii characters are allowed.';
-				});
-				if (error) return Toast.methods.addToast(error, 8000);
-
-
-				// Thumbnail
-				if (!validation.isLength(song.thumbnail, 8, 256)) return Toast.methods.addToast('Thumbnail must have between 8 and 256 characters.', 8000);
-				if (song.thumbnail.indexOf('https://') !== 0) return Toast.methods.addToast('Thumbnail must start with "https://".', 8000);
-
-
-				this.socket.emit(`${_this.editing.type}.update`, song._id, song, res => {
-					Toast.methods.addToast(res.message, 4000);
-					if (res.status === 'success') {
-						_this.$parent.songs.forEach(lSong => {
-							if (song._id === lSong._id) {
-								for (let n in song) {
-									lSong[n] = song[n];
-								}
-							}
-						});
-					}
-					if (close) _this.$parent.toggleModal();
-				});
-			},
-			settings: function (type) {
-				let _this = this;
-				switch(type) {
-					case 'stop':
-						_this.video.player.stopVideo();
-						_this.video.paused = true;
-						break;
-					case 'pause':
-						_this.video.player.pauseVideo();
-						_this.video.paused = true;
-						break;
-					case 'play':
-						_this.video.player.playVideo();
-						_this.video.paused = false;
-						break;
-					case 'skipToLast10Secs':
-						_this.video.player.seekTo((_this.editing.song.duration - 10) + _this.editing.song.skipDuration);
-						break;
-				}
-			},
-			changeVolume: function () {
-				let local = this;
-				let volume = $("#volumeSlider").val();
-				localStorage.setItem("volume", volume);
-				local.video.player.setVolume(volume);
-				if (volume > 0) local.video.player.unMute();
-			},
-			addTag: function (type) {
-				if (type == 'genres') {
-					let genre = $('#new-genre').val().toLowerCase().trim();
-					if (this.editing.song.genres.indexOf(genre) !== -1) return Toast.methods.addToast('Genre already exists', 3000);
-					if (genre) {
-						this.editing.song.genres.push(genre);
-						$('#new-genre').val('');
-					} else Toast.methods.addToast('Genre cannot be empty', 3000);
-				} else if (type == 'artists') {
-					let artist = $('#new-artist').val();
-					if (this.editing.song.artists.indexOf(artist) !== -1) return Toast.methods.addToast('Artist already exists', 3000);
-					if ($('#new-artist').val() !== '') {
-						this.editing.song.artists.push(artist);
-						$('#new-artist').val('');
-					} else Toast.methods.addToast('Artist cannot be empty', 3000);
-				}
-			},
-			removeTag: function (type, index) {
-				if (type == 'genres') this.editing.song.genres.splice(index, 1);
-				else if (type == 'artists') this.editing.song.artists.splice(index, 1);
-			},
-			getSpotifySongs: function() {
-				this.socket.emit('apis.getSpotifySongs', this.spotify.title, this.spotify.artist, (res) => {
-					if (res.status === 'success') {
-						Toast.methods.addToast(`Succesfully got ${res.songs.length} song${(res.songs.length !== 1) ? 's' : ''}.`, 3000);
-						this.spotify.songs = res.songs;
-					} else Toast.methods.addToast(`Failed to get songs. ${res.message}`, 3000);
-				});
-			}
-		},
-		ready: function () {
-
-			let _this = this;
-
-			io.getSocket(socket => {
-				_this.socket = socket;
-			});
-
-			setInterval(() => {
-				if (_this.video.paused === false && _this.playerReady && _this.video.player.getCurrentTime() - _this.editing.song.skipDuration > _this.editing.song.duration) {
-					_this.video.paused = false;
-					_this.video.player.stopVideo();
-				}
-			}, 200);
-
-			this.video.player = new YT.Player('player', {
-				height: 315,
-				width: 560,
-				videoId: this.editing.song.songId,
-				playerVars: { controls: 0, iv_load_policy: 3, rel: 0, showinfo: 0, autoplay: 1 },
-				startSeconds: _this.editing.song.skipDuration,
-				events: {
-					'onReady': () => {
-						let volume = parseInt(localStorage.getItem("volume"));
-						volume = (typeof volume === "number") ? volume : 20;
-						_this.video.player.seekTo(_this.editing.song.skipDuration);
-						_this.video.player.setVolume(volume);
-						if (volume > 0) _this.video.player.unMute();
-						_this.playerReady = true;
-					},
-					'onStateChange': event => {
-						if (event.data === 1) {
-							if (!_this.video.autoPlayed) {
-								_this.video.autoPlayed = true;
-								return _this.video.player.stopVideo();
-							}
-
-							_this.video.paused = false;
-							let youtubeDuration = _this.video.player.getDuration();
-							youtubeDuration -= _this.editing.song.skipDuration;
-							if (_this.editing.song.duration > youtubeDuration) {
-								this.video.player.stopVideo();
-								_this.video.paused = true;
-								Toast.methods.addToast("Video can't play. Specified duration is bigger than the YouTube song duration.", 4000);
-							} else if (_this.editing.song.duration <= 0) {
-								this.video.player.stopVideo();
-								_this.video.paused = true;
-								Toast.methods.addToast("Video can't play. Specified duration has to be more than 0 seconds.", 4000);
-							}
-
-							if (_this.video.player.getCurrentTime() < _this.editing.song.skipDuration) {
-								_this.video.player.seekTo(10);
-							}
-						} else if (event.data === 2) {
-							this.video.paused = true;
-						}
-					}
-				}
-			});
-
-			let volume = parseInt(localStorage.getItem("volume"));
-			volume = (typeof volume === "number") ? volume : 20;
-			$("#volumeSlider").val(volume);
-
-		},
-		events: {
-			closeModal: function () {
-				this.$parent.modals.editSong = false;
-				this.video.player.stopVideo();
-			},
-			editSong: function (song, index, type) {
-				let _this = this;
-				this.video.player.loadVideoById(song.songId, this.editing.song.skipDuration);
-				let newSong = {};
-				for (let n in song) {
-					newSong[n] = song[n];
-				}
-				this.editing = {
-					index,
-					song: newSong,
-					type
-				};
-				if (type === 'songs') {
-					_this.socket.emit('reports.getReportsForSong', song.songId, res => {
-						if (res.status === 'success') _this.reports = res.data;
-					});
-				}
-				this.$parent.toggleModal();
-			},
-			stopVideo: function () {
-				this.video.player.stopVideo();
-			}
-		}
-	}
+import { mapState, mapActions } from "vuex";
+
+import io from "../../io";
+import validation from "../../validation";
+import { Toast } from "vue-roaster";
+import Modal from "./Modal.vue";
+
+export default {
+  components: { Modal },
+  data() {
+    return {
+      reports: 0,
+      spotify: {
+        title: "",
+        artist: "",
+        songs: []
+      }
+    };
+  },
+  computed: {
+    ...mapState("admin/songs", {
+      video: state => state.video,
+      editing: state => state.editing
+    }),
+    ...mapState("modals", {
+      modals: state => state.modals.admin
+    })
+  },
+  methods: {
+    save: function(song, close) {
+      let _this = this;
+
+      if (!song.title)
+        return Toast.methods.addToast("Please fill in all fields", 8000);
+      if (!song.thumbnail)
+        return Toast.methods.addToast("Please fill in all fields", 8000);
+
+      // Title
+      if (!validation.isLength(song.title, 1, 64))
+        return Toast.methods.addToast(
+          "Title must have between 1 and 64 characters.",
+          8000
+        );
+      if (!validation.regex.ascii.test(song.title))
+        return Toast.methods.addToast(
+          "Invalid title format. Only ascii characters are allowed.",
+          8000
+        );
+
+      // Artists
+      if (song.artists.length < 1 || song.artists.length > 10)
+        return Toast.methods.addToast(
+          "Invalid artists. You must have at least 1 artist and a maximum of 10 artists.",
+          8000
+        );
+      let error;
+      song.artists.forEach(artist => {
+        if (!validation.isLength(artist, 1, 32))
+          return (error = "Artist must have between 1 and 32 characters.");
+        if (!validation.regex.ascii.test(artist))
+          return (error =
+            "Invalid artist format. Only ascii characters are allowed.");
+        if (artist === "NONE")
+          return (error =
+            'Invalid artist format. Artists are not allowed to be named "NONE".');
+      });
+      if (error) return Toast.methods.addToast(error, 8000);
+
+      // Genres
+      error = undefined;
+      song.genres.forEach(genre => {
+        if (!validation.isLength(genre, 1, 16))
+          return (error = "Genre must have between 1 and 16 characters.");
+        if (!validation.regex.az09_.test(genre))
+          return (error =
+            "Invalid genre format. Only ascii characters are allowed.");
+      });
+      if (error) return Toast.methods.addToast(error, 8000);
+
+      // Thumbnail
+      if (!validation.isLength(song.thumbnail, 8, 256))
+        return Toast.methods.addToast(
+          "Thumbnail must have between 8 and 256 characters.",
+          8000
+        );
+      if (song.thumbnail.indexOf("https://") !== 0)
+        return Toast.methods.addToast(
+          'Thumbnail must start with "https://".',
+          8000
+        );
+
+      this.socket.emit(`${_this.editing.type}.update`, song._id, song, res => {
+        Toast.methods.addToast(res.message, 4000);
+        if (res.status === "success") {
+          _this.$parent.songs.forEach(lSong => {
+            if (song._id === lSong._id) {
+              for (let n in song) {
+                lSong[n] = song[n];
+              }
+            }
+          });
+        }
+        if (close) _this.closeCurrentModal();
+      });
+    },
+    settings: function(type) {
+      let _this = this;
+      switch (type) {
+        case "stop":
+          _this.stopVideo();
+          _this.pauseVideo(true);
+          break;
+        case "pause":
+          _this.pauseVideo(true);
+          break;
+        case "play":
+          _this.pauseVideo(false);
+          break;
+        case "skipToLast10Secs":
+          _this.video.player.seekTo(
+            _this.editing.song.duration - 10 + _this.editing.song.skipDuration
+          );
+          break;
+      }
+    },
+    changeVolume: function() {
+      let local = this;
+      let volume = $("#volumeSlider").val();
+      localStorage.setItem("volume", volume);
+      local.video.player.setVolume(volume);
+      if (volume > 0) local.video.player.unMute();
+    },
+    addTag: function(type) {
+      if (type == "genres") {
+        let genre = $("#new-genre")
+          .val()
+          .toLowerCase()
+          .trim();
+        if (this.editing.song.genres.indexOf(genre) !== -1)
+          return Toast.methods.addToast("Genre already exists", 3000);
+        if (genre) {
+          this.editing.song.genres.push(genre);
+          $("#new-genre").val("");
+        } else Toast.methods.addToast("Genre cannot be empty", 3000);
+      } else if (type == "artists") {
+        let artist = $("#new-artist").val();
+        if (this.editing.song.artists.indexOf(artist) !== -1)
+          return Toast.methods.addToast("Artist already exists", 3000);
+        if ($("#new-artist").val() !== "") {
+          this.editing.song.artists.push(artist);
+          $("#new-artist").val("");
+        } else Toast.methods.addToast("Artist cannot be empty", 3000);
+      }
+    },
+    removeTag: function(type, index) {
+      if (type == "genres") this.editing.song.genres.splice(index, 1);
+      else if (type == "artists") this.editing.song.artists.splice(index, 1);
+    },
+    getSpotifySongs: function() {
+      this.socket.emit(
+        "apis.getSpotifySongs",
+        this.spotify.title,
+        this.spotify.artist,
+        res => {
+          if (res.status === "success") {
+            Toast.methods.addToast(
+              `Succesfully got ${res.songs.length} song${
+                res.songs.length !== 1 ? "s" : ""
+              }.`,
+              3000
+            );
+            this.spotify.songs = res.songs;
+          } else
+            Toast.methods.addToast(`Failed to get songs. ${res.message}`, 3000);
+        }
+      );
+    },
+    ...mapActions("admin/songs", [
+      "stopVideo",
+      "loadVideoById",
+      "pauseVideo",
+      "editSong"
+    ]),
+    ...mapActions("modals", ["toggleModal"])
+  },
+  mounted: function() {
+    let _this = this;
+
+    // if (this.modals.editSong = false) this.video.player.stopVideo();
+
+    // this.loadVideoById(
+    //   this.editing.song.songId,
+    //   this.editing.song.skipDuration
+    // );
+
+    io.getSocket(socket => (_this.socket = socket));
+
+    setInterval(() => {
+      if (
+        _this.video.paused === false &&
+        _this.playerReady &&
+        _this.video.player.getCurrentTime() - _this.editing.song.skipDuration >
+          _this.editing.song.duration
+      ) {
+        _this.video.paused = false;
+        _this.video.player.stopVideo();
+      }
+    }, 200);
+
+    this.video.player = new YT.Player("player", {
+      height: 315,
+      width: 560,
+      videoId: this.editing.song.songId,
+      playerVars: {
+        controls: 0,
+        iv_load_policy: 3,
+        rel: 0,
+        showinfo: 0,
+        autoplay: 1
+      },
+      startSeconds: _this.editing.song.skipDuration,
+      events: {
+        onReady: () => {
+          let volume = parseInt(localStorage.getItem("volume"));
+          volume = typeof volume === "number" ? volume : 20;
+          _this.video.player.seekTo(_this.editing.song.skipDuration);
+          _this.video.player.setVolume(volume);
+          if (volume > 0) _this.video.player.unMute();
+          _this.playerReady = true;
+        },
+        onStateChange: event => {
+          if (event.data === 1) {
+            if (!_this.video.autoPlayed) {
+              _this.video.autoPlayed = true;
+              return _this.video.player.stopVideo();
+            }
+
+            _this.video.paused = false;
+            let youtubeDuration = _this.video.player.getDuration();
+            youtubeDuration -= _this.editing.song.skipDuration;
+            if (_this.editing.song.duration > youtubeDuration) {
+              this.video.player.stopVideo();
+              _this.video.paused = true;
+              Toast.methods.addToast(
+                "Video can't play. Specified duration is bigger than the YouTube song duration.",
+                4000
+              );
+            } else if (_this.editing.song.duration <= 0) {
+              this.video.player.stopVideo();
+              _this.video.paused = true;
+              Toast.methods.addToast(
+                "Video can't play. Specified duration has to be more than 0 seconds.",
+                4000
+              );
+            }
+
+            if (
+              _this.video.player.getCurrentTime() <
+              _this.editing.song.skipDuration
+            ) {
+              _this.video.player.seekTo(10);
+            }
+          } else if (event.data === 2) {
+            this.video.paused = true;
+          }
+        }
+      }
+    });
+
+    let volume = parseInt(localStorage.getItem("volume"));
+    volume = typeof volume === "number" ? volume : 20;
+    $("#volumeSlider").val(volume);
+  }
+};
 </script>
 
-<style type='scss' scoped>
-	input[type=range] {
-		-webkit-appearance: none;
-		width: 100%;
-		margin: 7.3px 0;
-	}
-
-	input[type=range]:focus {
-		outline: none;
-	}
-
-	input[type=range]::-webkit-slider-runnable-track {
-		width: 100%;
-		height: 5.2px;
-		cursor: pointer;
-		box-shadow: 0;
-		background: #c2c0c2;
-		border-radius: 0;
-		border: 0;
-	}
-
-	input[type=range]::-webkit-slider-thumb {
-		box-shadow: 0;
-		border: 0;
-		height: 19px;
-		width: 19px;
-		border-radius: 15px;
-		background: #03a9f4;
-		cursor: pointer;
-		-webkit-appearance: none;
-		margin-top: -6.5px;
-	}
-
-	input[type=range]::-moz-range-track {
-		width: 100%;
-		height: 5.2px;
-		cursor: pointer;
-		box-shadow: 0;
-		background: #c2c0c2;
-		border-radius: 0;
-		border: 0;
-	}
-
-	input[type=range]::-moz-range-thumb {
-		box-shadow: 0;
-		border: 0;
-		height: 19px;
-		width: 19px;
-		border-radius: 15px;
-		background: #03a9f4;
-		cursor: pointer;
-		-webkit-appearance: none;
-		margin-top: -6.5px;
-	}
-
-	input[type=range]::-ms-track {
-		width: 100%;
-		height: 5.2px;
-		cursor: pointer;
-		box-shadow: 0;
-		background: #c2c0c2;
-		border-radius: 1.3px;
-	}
-
-	input[type=range]::-ms-fill-lower {
-		background: #c2c0c2;
-		border: 0;
-		border-radius: 0;
-		box-shadow: 0;
-	}
-
-	input[type=range]::-ms-fill-upper {
-		background: #c2c0c2;
-		border: 0;
-		border-radius: 0;
-		box-shadow: 0;
-	}
-
-	input[type=range]::-ms-thumb {
-		box-shadow: 0;
-		border: 0;
-		height: 15px;
-		width: 15px;
-		border-radius: 15px;
-		background: #03a9f4;
-		cursor: pointer;
-		-webkit-appearance: none;
-		margin-top: 1.5px;
-	}
-
-	.controls {
-		display: flex;
-		flex-direction: column;
-		align-items: center;
-	}
-
-	.artist-genres {
-		display: flex;
-    	justify-content: space-between;
-	}
-
-	#volumeSlider { margin-bottom: 15px; }
-
-	.has-text-centered { padding: 10px; }
-
-	.thumbnail-preview {
-		display: flex;
-		margin: 0 auto 25px auto;
-		max-width: 200px;
-		width: 100%;
-	}
-
-	.modal-card-body, .modal-card-foot { border-top: 0; }
-
-	.label, .checkbox, h5 {
-		font-weight: normal;
-	}
-
-	.video-container {
-		display: flex;
-		flex-direction: column;
-		align-items: center;
-		padding: 10px;
-
-		iframe { pointer-events: none; }
-	}
-
-	.save-changes { color: #fff; }
-
-	.tag:not(:last-child) { margin-right: 5px; }
-
-	.reports-length {
-		color: #ff4545;
-		font-weight: bold;
-		display: flex;
-		justify-content: center;
-	}
-
-	.report-link {
-		color: #000;
-	}
+<style lang='scss' scoped>
+input[type="range"] {
+  -webkit-appearance: none;
+  width: 100%;
+  margin: 7.3px 0;
+}
+
+input[type="range"]:focus {
+  outline: none;
+}
+
+input[type="range"]::-webkit-slider-runnable-track {
+  width: 100%;
+  height: 5.2px;
+  cursor: pointer;
+  box-shadow: 0;
+  background: #c2c0c2;
+  border-radius: 0;
+  border: 0;
+}
+
+input[type="range"]::-webkit-slider-thumb {
+  box-shadow: 0;
+  border: 0;
+  height: 19px;
+  width: 19px;
+  border-radius: 15px;
+  background: #03a9f4;
+  cursor: pointer;
+  -webkit-appearance: none;
+  margin-top: -6.5px;
+}
+
+input[type="range"]::-moz-range-track {
+  width: 100%;
+  height: 5.2px;
+  cursor: pointer;
+  box-shadow: 0;
+  background: #c2c0c2;
+  border-radius: 0;
+  border: 0;
+}
+
+input[type="range"]::-moz-range-thumb {
+  box-shadow: 0;
+  border: 0;
+  height: 19px;
+  width: 19px;
+  border-radius: 15px;
+  background: #03a9f4;
+  cursor: pointer;
+  -webkit-appearance: none;
+  margin-top: -6.5px;
+}
+
+input[type="range"]::-ms-track {
+  width: 100%;
+  height: 5.2px;
+  cursor: pointer;
+  box-shadow: 0;
+  background: #c2c0c2;
+  border-radius: 1.3px;
+}
+
+input[type="range"]::-ms-fill-lower {
+  background: #c2c0c2;
+  border: 0;
+  border-radius: 0;
+  box-shadow: 0;
+}
+
+input[type="range"]::-ms-fill-upper {
+  background: #c2c0c2;
+  border: 0;
+  border-radius: 0;
+  box-shadow: 0;
+}
+
+input[type="range"]::-ms-thumb {
+  box-shadow: 0;
+  border: 0;
+  height: 15px;
+  width: 15px;
+  border-radius: 15px;
+  background: #03a9f4;
+  cursor: pointer;
+  -webkit-appearance: none;
+  margin-top: 1.5px;
+}
+
+.controls {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+}
+
+.artist-genres {
+  display: flex;
+  justify-content: space-between;
+}
+
+#volumeSlider {
+  margin-bottom: 15px;
+}
+
+.has-text-centered {
+  padding: 10px;
+}
+
+.thumbnail-preview {
+  display: flex;
+  margin: 0 auto 25px auto;
+  max-width: 200px;
+  width: 100%;
+}
+
+.modal-card-body,
+.modal-card-foot {
+  border-top: 0;
+}
+
+.label,
+.checkbox,
+h5 {
+  font-weight: normal;
+}
+
+.video-container {
+  display: flex;
+  flex-direction: column;
+  align-items: center;
+  padding: 10px;
+
+  iframe {
+    pointer-events: none;
+  }
+}
+
+.save-changes {
+  color: #fff;
+}
+
+.tag:not(:last-child) {
+  margin-right: 5px;
+}
+
+.reports-length {
+  color: #ff4545;
+  font-weight: bold;
+  display: flex;
+  justify-content: center;
+}
+
+.report-link {
+  color: #000;
+}
 </style>

+ 269 - 198
frontend/components/Modals/EditStation.vue

@@ -1,217 +1,288 @@
 <template>
-	<div>
-		<modal title='Edit Station'>
-			<div slot='body'>
-				<label class='label'>Name</label>
-				<p class='control'>
-					<input class='input' type='text' placeholder='Station Name' v-model='editing.name'>
-				</p>
-				<label class='label'>Display name</label>
-				<p class='control'>
-					<input class='input' type='text' placeholder='Station Display Name' v-model='editing.displayName'>
-				</p>
-				<label class='label'>Description</label>
-				<p class='control'>
-					<input class='input' type='text' placeholder='Station Display Name' v-model='editing.description'>
-				</p>
-				<label class='label'>Privacy</label>
-				<p class='control'>
-					<span class='select'>
-						<select v-model='editing.privacy'>
-							<option :value='"public"'>Public</option>
-							<option :value='"unlisted"'>Unlisted</option>
-							<option :value='"private"'>Private</option>
-						</select>
-					</span>
-				</p>
-				<br><br>
-				<p class='control'>
-					<label class="checkbox party-mode-inner">
-						<input type="checkbox" v-model="editing.partyMode">
-						&nbsp;Party mode
-					</label>
-				</p>
-				<small>With party mode enabled, people can add songs to a queue that plays. With party mode disabled you can play a private playlist on loop.</small><br>
-				<div v-if="$parent.station.partyMode">
-					<br>
-					<br>
-					<label class='label'>Queue lock</label>
-					<small v-if="$parent.station.partyMode">With the queue locked, only owners (you) can add songs to the queue.</small><br>
-					<button class='button is-danger' v-if='!$parent.station.locked' @click="$parent.toggleLock()">Lock the queue</button>
-					<button class='button is-success' v-if='$parent.station.locked' @click="$parent.toggleLock()">Unlock the queue</button>
-				</div>
-			</div>
-			<div slot='footer'>
-				<button class='button is-success' @click='update()'>Update Settings</button>
-				<button class='button is-danger' @click='deleteStation()' v-if="$parent.type === 'community'">Delete station</button>
-			</div>
-		</modal>
-	</div>
+  <modal title="Edit Station">
+    <template v-slot:body>
+      <label class="label">Name</label>
+      <p class="control">
+        <input class="input" type="text" placeholder="Station Name" v-model="editing.name" />
+      </p>
+      <label class="label">Display name</label>
+      <p class="control">
+        <input
+          class="input"
+          type="text"
+          placeholder="Station Display Name"
+          v-model="editing.displayName"
+        />
+      </p>
+      <label class="label">Description</label>
+      <p class="control">
+        <input
+          class="input"
+          type="text"
+          placeholder="Station Description"
+          v-model="editing.description"
+        />
+      </p>
+      <label class="label">Privacy</label>
+      <p class="control">
+        <span class="select">
+          <select v-model="editing.privacy">
+            <option value="public">Public</option>
+            <option value="unlisted">Unlisted</option>
+            <option value="private">Private</option>
+          </select>
+        </span>
+      </p>
+      <br />
+      <p class="control">
+        <label class="checkbox party-mode-inner">
+          <input type="checkbox" v-model="editing.partyMode" />
+          &nbsp;Party mode
+        </label>
+      </p>
+      <small>With party mode enabled, people can add songs to a queue that plays. With party mode disabled you can play a private playlist on loop.</small>
+      <br />
+      <div v-if="station.partyMode">
+        <br />
+        <br />
+        <label class="label">Queue lock</label>
+        <small
+          v-if="station.partyMode"
+        >With the queue locked, only owners (you) can add songs to the queue.</small>
+        <br />
+        <button
+          class="button is-danger"
+          v-if="!station.locked"
+          v-on:click="$parent.toggleLock()"
+        >Lock the queue</button>
+        <button
+          class="button is-success"
+          v-if="station.locked"
+          v-on:click="$parent.toggleLock()"
+        >Unlock the queue</button>
+      </div>
+    </template>
+    <template v-slot:footer>
+      <button class="button is-success" v-on:click="update()">Update Settings</button>
+      <button
+        class="button is-danger"
+        v-on:click="deleteStation()"
+        v-if="station.type === 'community'"
+      >Delete station</button>
+    </template>
+  </modal>
 </template>
 
 <script>
-	import { Toast } from 'vue-roaster';
-	import Modal from './Modal.vue';
-	import io from '../../io';
-	import validation from '../../validation';
+import { mapState } from "vuex";
 
-	export default {
-		data: function() {
-			return {
-				editing: {
-					_id: '',
-					name: '',
-					type: '',
-					displayName: '',
-					description: '',
-					privacy: 'private',
-					partyMode: false
-				}
-			}
-		},
-		methods: {
-			update: function () {
-				if (this.$parent.station.name !== this.editing.name) this.updateName();
-				if (this.$parent.station.displayName !== this.editing.displayName) this.updateDisplayName();
-				if (this.$parent.station.description !== this.editing.description) this.updateDescription();
-				if (this.$parent.station.privacy !== this.editing.privacy) this.updatePrivacy();
-				if (this.$parent.station.partyMode !== this.editing.partyMode) this.updatePartyMode();
-			},
-			updateName: function () {
-				const name = this.editing.name;
-				if (!validation.isLength(name, 2, 16)) return Toast.methods.addToast('Name must have between 2 and 16 characters.', 8000);
-				if (!validation.regex.az09_.test(name)) return Toast.methods.addToast('Invalid name format. Allowed characters: a-z, 0-9 and _.', 8000);
+import { Toast } from "vue-roaster";
+import Modal from "./Modal.vue";
+import io from "../../io";
+import validation from "../../validation";
 
+export default {
+  computed: mapState("station", {
+    station: state => state.station,
+    editing: state => state.editing
+  }),
+  methods: {
+    update: function() {
+      if (this.station.name !== this.editing.name) this.updateName();
+      if (this.station.displayName !== this.editing.displayName)
+        this.updateDisplayName();
+      if (this.station.description !== this.editing.description)
+        this.updateDescription();
+      if (this.station.privacy !== this.editing.privacy) this.updatePrivacy();
+      if (this.station.partyMode !== this.editing.partyMode)
+        this.updatePartyMode();
+    },
+    updateName: function() {
+      const name = this.editing.name;
+      if (!validation.isLength(name, 2, 16))
+        return Toast.methods.addToast(
+          "Name must have between 2 and 16 characters.",
+          8000
+        );
+      if (!validation.regex.az09_.test(name))
+        return Toast.methods.addToast(
+          "Invalid name format. Allowed characters: a-z, 0-9 and _.",
+          8000
+        );
 
-				this.socket.emit('stations.updateName', this.editing._id, name, res => {
-					if (res.status === 'success') {
-						if (this.$parent.station) _this.$parent.station.name = name;
-						else {
-							this.$parent.stations.forEach((station, index) => {
-								if (station._id === this.editing._id) return this.$parent.stations[index].name = name;
-							});
-						}
-					}
-					Toast.methods.addToast(res.message, 8000);
-				});
-			},
-			updateDisplayName: function () {
-				const displayName = this.editing.displayName;
-				if (!validation.isLength(displayName, 2, 32)) return Toast.methods.addToast('Display name must have between 2 and 32 characters.', 8000);
-				if (!validation.regex.azAZ09_.test(displayName)) return Toast.methods.addToast('Invalid display name format. Allowed characters: a-z, A-Z, 0-9 and _.', 8000);
+      this.socket.emit("stations.updateName", this.editing._id, name, res => {
+        if (res.status === "success") {
+          if (this.station) this.station.name = name;
+          else {
+            this.$parent.stations.forEach((station, index) => {
+              if (station._id === this.editing._id)
+                return (this.$parent.stations[index].name = name);
+            });
+          }
+        }
+        Toast.methods.addToast(res.message, 8000);
+      });
+    },
+    updateDisplayName: function() {
+      let _this = this;
 
+      const displayName = this.editing.displayName;
+      if (!validation.isLength(displayName, 2, 32))
+        return Toast.methods.addToast(
+          "Display name must have between 2 and 32 characters.",
+          8000
+        );
+      if (!validation.regex.azAZ09_.test(displayName))
+        return Toast.methods.addToast(
+          "Invalid display name format. Allowed characters: a-z, A-Z, 0-9 and _.",
+          8000
+        );
 
-				this.socket.emit('stations.updateDisplayName', this.editing._id, displayName, res => {
-					if (res.status === 'success') {
-						if (this.$parent.station) _this.$parent.station.displayName = displayName;
-						else {
-							this.$parent.stations.forEach((station, index) => {
-								if (station._id === this.editing._id) return this.$parent.stations[index].displayName = displayName;
-							});
-						}
-					}
-					Toast.methods.addToast(res.message, 8000);
-				});
-			},
-			updateDescription: function () {
-				const description = this.editing.description;
-				if (!validation.isLength(description, 2, 200)) return Toast.methods.addToast('Description must have between 2 and 200 characters.', 8000);
-				let characters = description.split("");
-				characters = characters.filter(function(character) {
-					return character.charCodeAt(0) === 21328;
-				});
-				if (characters.length !== 0) return Toast.methods.addToast('Invalid description format. Swastika\'s are not allowed.', 8000);
+      this.socket.emit(
+        "stations.updateDisplayName",
+        this.editing._id,
+        displayName,
+        res => {
+          if (res.status === "success") {
+            if (this.station) this.station.displayName = displayName;
+            else {
+              this.$parent.stations.forEach((station, index) => {
+                if (station._id === this.editing._id)
+                  return (this.$parent.stations[
+                    index
+                  ].displayName = displayName);
+              });
+            }
+          }
+          Toast.methods.addToast(res.message, 8000);
+        }
+      );
+    },
+    updateDescription: function() {
+      let _this = this;
 
+      const description = this.editing.description;
+      if (!validation.isLength(description, 2, 200))
+        return Toast.methods.addToast(
+          "Description must have between 2 and 200 characters.",
+          8000
+        );
+      let characters = description.split("");
+      characters = characters.filter(character => {
+        return character.charCodeAt(0) === 21328;
+      });
+      if (characters.length !== 0)
+        return Toast.methods.addToast(
+          "Invalid description format. Swastika's are not allowed.",
+          8000
+        );
 
-				this.socket.emit('stations.updateDescription', this.editing._id, description, res => {
-					if (res.status === 'success') {
-						if (_this.$parent.station) _this.$parent.station.description = description;
-						else {
-							_this.$parent.stations.forEach((station, index) => {
-								if (station._id === station._id) return _this.$parent.stations[index].description = description;
-							});
-						}
-						return Toast.methods.addToast(res.message, 4000);
-					}
-					Toast.methods.addToast(res.message, 8000);
-				});
-			},
-			updatePrivacy: function () {
-				let _this = this;
-				this.socket.emit('stations.updatePrivacy', this.editing._id, this.editing.privacy, res => {
-					if (res.status === 'success') {
-						if (_this.$parent.station) _this.$parent.station.privacy = _this.editing.privacy;
-						else {
-							_this.$parent.stations.forEach((station, index) => {
-								if (station._id === station._id) return _this.$parent.stations[index].privacy = _this.editing.privacy;
-							});
-						}
-						return Toast.methods.addToast(res.message, 4000);
-					}
-					Toast.methods.addToast(res.message, 8000);
-				});
-			},
-			updatePartyMode: function () {
-				let _this = this;
-				this.socket.emit('stations.updatePartyMode', this.editing._id, this.editing.partyMode, res => {
-					if (res.status === 'success') {
-						if (_this.$parent.station) _this.$parent.station.partyMode = _this.editing.partyMode;
-						else {
-							_this.$parent.stations.forEach((station, index) => {
-								if (station._id === station._id) return _this.$parent.stations[index].partyMode = _this.editing.partyMode;
-							});
-						}
-						return Toast.methods.addToast(res.message, 4000);
-					}
-					Toast.methods.addToast(res.message, 8000);
-				});
-			},
-			deleteStation: function() {
-				let _this = this;
-				this.socket.emit('stations.remove', this.editing._id, res => {
-					Toast.methods.addToast(res.message, 8000);
-				});
-			}
-		},
-		ready: function () {
-			let _this = this;
-			io.getSocket(socket => {
-				_this.socket = socket;
-			});
-		},
-		events: {
-			closeModal: function() {
-				this.$parent.modals.editStation = false;
-			},
-			editStation: function(station) {
-				for (let prop in station) {
-					this.editing[prop] = station[prop];
-				}
-				this.$parent.modals.editStation = true;
-			}
-		},
-		components: { Modal }
-	}
+      this.socket.emit(
+        "stations.updateDescription",
+        this.editing._id,
+        description,
+        res => {
+          if (res.status === "success") {
+            if (_this.station) _this.station.description = description;
+            else {
+              _this.$parent.stations.forEach((station, index) => {
+                if (station._id === station._id)
+                  return (_this.$parent.stations[
+                    index
+                  ].description = description);
+              });
+            }
+            return Toast.methods.addToast(res.message, 4000);
+          }
+          Toast.methods.addToast(res.message, 8000);
+        }
+      );
+    },
+    updatePrivacy: function() {
+      let _this = this;
+      this.socket.emit(
+        "stations.updatePrivacy",
+        this.editing._id,
+        this.editing.privacy,
+        res => {
+          if (res.status === "success") {
+            if (_this.station) _this.station.privacy = _this.editing.privacy;
+            else {
+              _this.$parent.stations.forEach((station, index) => {
+                if (station._id === station._id)
+                  return (_this.$parent.stations[index].privacy =
+                    _this.editing.privacy);
+              });
+            }
+            return Toast.methods.addToast(res.message, 4000);
+          }
+          Toast.methods.addToast(res.message, 8000);
+        }
+      );
+    },
+    updatePartyMode: function() {
+      let _this = this;
+      this.socket.emit(
+        "stations.updatePartyMode",
+        this.editing._id,
+        this.editing.partyMode,
+        res => {
+          if (res.status === "success") {
+            if (_this.station)
+              _this.station.partyMode = _this.editing.partyMode;
+            else {
+              _this.$parent.stations.forEach((station, index) => {
+                if (station._id === station._id)
+                  return (_this.$parent.stations[index].partyMode =
+                    _this.editing.partyMode);
+              });
+            }
+            return Toast.methods.addToast(res.message, 4000);
+          }
+          Toast.methods.addToast(res.message, 8000);
+        }
+      );
+    },
+    deleteStation: function() {
+      let _this = this;
+      this.socket.emit("stations.remove", this.editing._id, res => {
+        Toast.methods.addToast(res.message, 8000);
+      });
+    }
+  },
+  mounted: function() {
+    let _this = this;
+    io.getSocket(socket => (_this.socket = socket));
+  },
+  components: { Modal }
+};
 </script>
 
-<style type='scss' scoped>
-	.controls {
-		display: flex;
+<style lang='scss' scoped>
+.controls {
+  display: flex;
 
-		a {
-			display: flex;
-    		align-items: center;
-		}
-	}
+  a {
+    display: flex;
+    align-items: center;
+  }
+}
 
-	.table { margin-bottom: 0; }
+.table {
+  margin-bottom: 0;
+}
 
-	h5 { padding: 20px 0; }
+h5 {
+  padding: 20px 0;
+}
 
-	.party-mode-inner, .party-mode-outer {
-		display: flex;
-		align-items: center;
-	}
+.party-mode-inner,
+.party-mode-outer {
+  display: flex;
+  align-items: center;
+}
 
-	.select:after { border-color: #029ce3; }
+.select:after {
+  border-color: #029ce3;
+}
 </style>

+ 185 - 129
frontend/components/Modals/EditUser.vue

@@ -1,147 +1,203 @@
 <template>
-	<div>
-		<modal title='Edit User'>
-			<div slot='body'>
-				<p class="control has-addons">
-					<input class='input is-expanded' type='text' placeholder='Username' v-model='editing.username' autofocus>
-					<a class="button is-info" @click='updateUsername()'>Update Username</a>
-				</p>
-				<p class="control has-addons">
-					<input class='input is-expanded' type='text' placeholder='Username' v-model='editing.email' autofocus>
-					<a class="button is-info" @click='updateEmail()'>Update Email Address</a>
-				</p>
-				<p class="control has-addons">
-					<span class="select">
-						<select v-model="editing.role">
-							<option>default</option>
-							<option>admin</option>
-						</select>
-					</span>
-					<a class="button is-info" @click='updateRole()'>Update Role</a>
-				</p>
-				<hr>
-				<p class="control has-addons">
-					<span class="select">
-						<select v-model='ban.expiresAt'>
-							<option value='1h'>1 Hour</option>
-							<option value='12h'>12 Hours</option>
-							<option value='1d'>1 Day</option>
-							<option value='1w'>1 Week</option>
-							<option value='1m'>1 Month</option>
-							<option value='3m'>3 Months</option>
-							<option value='6m'>6 Months</option>
-							<option value='1y'>1 Year</option>
-						</select>
-					</span>
-					<input class='input is-expanded' type='text' placeholder='Ban reason' v-model='ban.reason' autofocus>
-					<a class="button is-error" @click='banUser()'>Ban user</a>
-				</p>
-			</div>
-			<div slot='footer'>
-				<!--button class='button is-warning'>
+  <div>
+    <modal title="Edit User">
+      <div slot="body">
+        <p class="control has-addons">
+          <input
+            class="input is-expanded"
+            type="text"
+            placeholder="Username"
+            v-model="editing.username"
+            autofocus
+          />
+          <a class="button is-info" v-on:click="updateUsername()">Update Username</a>
+        </p>
+        <p class="control has-addons">
+          <input
+            class="input is-expanded"
+            type="text"
+            placeholder="Email Address"
+            v-model="editing.email.address"
+            autofocus
+          />
+          <a class="button is-info" v-on:click="updateEmail()">Update Email Address</a>
+        </p>
+        <p class="control has-addons">
+          <span class="select">
+            <select v-model="editing.role">
+              <option>default</option>
+              <option>admin</option>
+            </select>
+          </span>
+          <a class="button is-info" v-on:click="updateRole()">Update Role</a>
+        </p>
+        <hr />
+        <p class="control has-addons">
+          <span class="select">
+            <select v-model="ban.expiresAt">
+              <option value="1h">1 Hour</option>
+              <option value="12h">12 Hours</option>
+              <option value="1d">1 Day</option>
+              <option value="1w">1 Week</option>
+              <option value="1m">1 Month</option>
+              <option value="3m">3 Months</option>
+              <option value="6m">6 Months</option>
+              <option value="1y">1 Year</option>
+            </select>
+          </span>
+          <input
+            class="input is-expanded"
+            type="text"
+            placeholder="Ban reason"
+            v-model="ban.reason"
+            autofocus
+          />
+          <a class="button is-error" v-on:click="banUser()">Ban user</a>
+        </p>
+      </div>
+      <div slot="footer">
+        <!--button class='button is-warning'>
 					<span>&nbsp;Send Verification Email</span>
 				</button>
 				<button class='button is-warning'>
 					<span>&nbsp;Send Password Reset Email</span>
-				</button-->
-				<button class='button is-warning' @click='removeSessions()'>
-					<span>&nbsp;Remove all sessions</span>
-				</button>
-				<button class='button is-danger' @click='$parent.toggleModal()'>
-					<span>&nbsp;Close</span>
-				</button>
-			</div>
-		</modal>
-	</div>
+        </button-->
+        <button class="button is-warning" v-on:click="removeSessions()">
+          <span>&nbsp;Remove all sessions</span>
+        </button>
+        <button class="button is-danger" v-on:click="closeCurrentModal()">
+          <span>&nbsp;Close</span>
+        </button>
+      </div>
+    </modal>
+  </div>
 </template>
 
 <script>
-	import io from '../../io';
-	import { Toast } from 'vue-roaster';
-	import Modal from './Modal.vue';
-	import validation from '../../validation';
-
-	export default {
-		components: { Modal },
-		data() {
-			return {
-				editing: {},
-				ban: {
-					expiresAt: '1h'
-				}
-			}
-		},
-		methods: {
-			updateUsername: function () {
-				const username = this.editing.username;
-				if (!validation.isLength(username, 2, 32)) return Toast.methods.addToast('Username must have between 2 and 32 characters.', 8000);
-				if (!validation.regex.azAZ09_.test(username)) return Toast.methods.addToast('Invalid username format. Allowed characters: a-z, A-Z, 0-9 and _.', 8000);
+import { mapState, mapActions } from "vuex";
 
+import io from "../../io";
+import { Toast } from "vue-roaster";
+import Modal from "./Modal.vue";
+import validation from "../../validation";
 
-				this.socket.emit(`users.updateUsername`, this.editing._id, username, res => {
-					Toast.methods.addToast(res.message, 4000);
-				});
-			},
-			updateEmail: function () {
-				const email = this.editing.email;
-				if (!validation.isLength(email, 3, 254)) return Toast.methods.addToast('Email must have between 3 and 254 characters.', 8000);
-				if (email.indexOf('@') !== email.lastIndexOf('@') || !validation.regex.emailSimple.test(email)) return Toast.methods.addToast('Invalid email format.', 8000);
+export default {
+  components: { Modal },
+  data() {
+    return {
+      ban: {
+        expiresAt: "1h"
+      }
+    };
+  },
+  computed: {
+    ...mapState("admin/users", {
+      editing: state => state.editing
+    })
+  },
+  methods: {
+    updateUsername: function() {
+      const username = this.editing.username;
+      if (!validation.isLength(username, 2, 32))
+        return Toast.methods.addToast(
+          "Username must have between 2 and 32 characters.",
+          8000
+        );
+      if (!validation.regex.azAZ09_.test(username))
+        return Toast.methods.addToast(
+          "Invalid username format. Allowed characters: a-z, A-Z, 0-9 and _.",
+          8000
+        );
 
+      this.socket.emit(
+        `users.updateUsername`,
+        this.editing._id,
+        username,
+        res => {
+          Toast.methods.addToast(res.message, 4000);
+        }
+      );
+    },
+    updateEmail: function() {
+      const email = this.editing.email;
+      if (!validation.isLength(email, 3, 254))
+        return Toast.methods.addToast(
+          "Email must have between 3 and 254 characters.",
+          8000
+        );
+      if (
+        email.indexOf("@") !== email.lastIndexOf("@") ||
+        !validation.regex.emailSimple.test(email)
+      )
+        return Toast.methods.addToast("Invalid email format.", 8000);
 
-				this.socket.emit(`users.updateEmail`, this.editing._id, email, res => {
-					Toast.methods.addToast(res.message, 4000);
-				});
-			},
-			updateRole: function () {
-				this.socket.emit(`users.updateRole`, this.editing._id, this.editing.role, res => {
-					Toast.methods.addToast(res.message, 4000);
-					if (
-							res.status === 'success' &&
-							this.editing.role === 'default' &&
-							this.editing._id === this.$parent.$parent.$parent.userId
-					) location.reload();
-				});
-			},
-			banUser: function () {
-				const reason = this.ban.reason;
-				if (!validation.isLength(reason, 1, 64)) return Toast.methods.addToast('Reason must have between 1 and 64 characters.', 8000);
-				if (!validation.regex.ascii.test(reason)) return Toast.methods.addToast('Invalid reason format. Only ascii characters are allowed.', 8000);
+      this.socket.emit(`users.updateEmail`, this.editing._id, email, res => {
+        Toast.methods.addToast(res.message, 4000);
+      });
+    },
+    updateRole: function() {
+      this.socket.emit(
+        `users.updateRole`,
+        this.editing._id,
+        this.editing.role,
+        res => {
+          Toast.methods.addToast(res.message, 4000);
+          if (
+            res.status === "success" &&
+            this.editing.role === "default" &&
+            this.editing._id === this.$parent.$parent.$parent.userId
+          )
+            location.reload();
+        }
+      );
+    },
+    banUser: function() {
+      const reason = this.ban.reason;
+      if (!validation.isLength(reason, 1, 64))
+        return Toast.methods.addToast(
+          "Reason must have between 1 and 64 characters.",
+          8000
+        );
+      if (!validation.regex.ascii.test(reason))
+        return Toast.methods.addToast(
+          "Invalid reason format. Only ascii characters are allowed.",
+          8000
+        );
 
-				this.socket.emit(`users.banUserById`, this.editing._id, this.ban.reason, this.ban.expiresAt, res => {
-					Toast.methods.addToast(res.message, 4000);
-				});
-			},
-			removeSessions: function () {
-				this.socket.emit(`users.removeSessions`, this.editing._id, res => {
-					Toast.methods.addToast(res.message, 4000);
-				});
-			}
-		},
-		ready: function () {
-			let _this = this;
-			io.getSocket(socket => _this.socket = socket );
-		},
-		events: {
-			closeModal: function () {
-				this.$parent.modals.editUser = false;
-			},
-			editUser: function (user) {
-				this.editing = {
-					_id: user._id,
-					username: user.username,
-					email: user.email.address,
-					role: user.role
-				};
-				this.$parent.toggleModal();
-			}
-		}
-	}
+      this.socket.emit(
+        `users.banUserById`,
+        this.editing._id,
+        this.ban.reason,
+        this.ban.expiresAt,
+        res => {
+          Toast.methods.addToast(res.message, 4000);
+        }
+      );
+    },
+    removeSessions: function() {
+      this.socket.emit(`users.removeSessions`, this.editing._id, res => {
+        Toast.methods.addToast(res.message, 4000);
+      });
+    },
+    ...mapActions("modals", ["closeCurrentModal"])
+  },
+  mounted: function() {
+    let _this = this;
+    io.getSocket(socket => (_this.socket = socket));
+  }
+};
 </script>
 
-<style type='scss' scoped>
-	.save-changes { color: #fff; }
+<style lang='scss' scoped>
+.save-changes {
+  color: #fff;
+}
 
-	.tag:not(:last-child) { margin-right: 5px; }
+.tag:not(:last-child) {
+  margin-right: 5px;
+}
 
-	.select:after { border-color: #029ce3; }
+.select:after {
+  border-color: #029ce3;
+}
 </style>

+ 56 - 47
frontend/components/Modals/IssuesModal.vue

@@ -1,53 +1,62 @@
 <template>
-	<modal title='Report'>
-		<div slot='body'>
-			<article class="message">
-				<div class="message-body">
-					<strong>Song ID: </strong>{{ $parent.editing.songId }}<br/>
-					<strong>Created By: </strong>{{ $parent.editing.createdBy }}<br/>
-					<strong>Created At: </strong>{{ $parent.editing.createdAt }}<br/>
-					<span v-if='$parent.editing.description'><strong>Description: </strong>{{ $parent.editing.description }}</span>
-				</div>
-			</article>
-			<table class='table is-narrow' v-if='$parent.editing.issues.length > 0'>
-				<thead>
-					<tr>
-						<td>Issue</td>
-						<td>Reasons</td>
-					</tr>
-				</thead>
-				<tbody>
-					<tr v-for='(index, issue) in $parent.editing.issues' track-by='$index'>
-						<td>
-							<span>{{ issue.name }}</span>
-						</td>
-						<td>
-							<span>{{ issue.reasons }}</span>
-						</td>
-					</tr>
-				</tbody>
-			</table>
-		</div>
-		<div slot='footer'>
-			<a class='button is-primary' @click='$parent.resolve($parent.editing._id)' href='#'>
-				<span>Resolve</span>
-			</a>
-			<a class='button is-danger' @click='$parent.toggleModal()' href='#'>
-				<span>Cancel</span>
-			</a>
-		</div>
-	</modal>
+  <modal title="Report">
+    <div slot="body">
+      <article class="message">
+        <div class="message-body">
+          <strong>Song ID:</strong>
+          {{ $parent.editing.songId }}
+          <br />
+          <strong>Created By:</strong>
+          {{ $parent.editing.createdBy }}
+          <br />
+          <strong>Created At:</strong>
+          {{ $parent.editing.createdAt }}
+          <br />
+          <span v-if="$parent.editing.description">
+            <strong>Description:</strong>
+            {{ $parent.editing.description }}
+          </span>
+        </div>
+      </article>
+      <table class="table is-narrow" v-if="$parent.editing.issues.length > 0">
+        <thead>
+          <tr>
+            <td>Issue</td>
+            <td>Reasons</td>
+          </tr>
+        </thead>
+        <tbody>
+          <tr v-for="(issue, index) in $parent.editing.issues" :key="index">
+            <td>
+              <span>{{ issue.name }}</span>
+            </td>
+            <td>
+              <span>{{ issue.reasons }}</span>
+            </td>
+          </tr>
+        </tbody>
+      </table>
+    </div>
+    <div slot="footer">
+      <a class="button is-primary" v-on:click="$parent.resolve($parent.editing._id)" href="#">
+        <span>Resolve</span>
+      </a>
+      <a class="button is-danger" v-on:click="$parent.toggleModal()" href="#">
+        <span>Cancel</span>
+      </a>
+    </div>
+  </modal>
 </template>
 
 <script>
-	import Modal from './Modal.vue';
+import Modal from "./Modal.vue";
 
-	export default {
-		components: { Modal },
-		events: {
-			closeModal: function () {
-				this.$parent.modals.report = false;
-			}
-		}
-	}
+export default {
+  components: { Modal },
+  events: {
+    closeModal: function() {
+      this.$parent.modals.report = false;
+    }
+  }
+};
 </script>

+ 79 - 64
frontend/components/Modals/Login.vue

@@ -1,74 +1,89 @@
 <template>
-	<div class='modal is-active'>
-		<div class='modal-background'></div>
-		<div class='modal-card'>
-			<header class='modal-card-head'>
-				<p class='modal-card-title'>Login</p>
-				<button class='delete' @click='toggleModal()'></button>
-			</header>
-			<section class='modal-card-body'>
-				<!-- validation to check if exists http://bulma.io/documentation/elements/form/ -->
-				<label class='label'>Email</label>
-				<p class='control'>
-					<input class='input' type='text' placeholder='Email...' v-model='$parent.login.email'>
-				</p>
-				<label class='label'>Password</label>
-				<p class='control'>
-					<input class='input' type='password' placeholder='Password...' v-model='$parent.login.password' v-on:keypress='$parent.submitOnEnter(submitModal, $event)'>
-				</p>
-				<p>By logging in/registering you agree to our <a href="/terms" v-link="{ path: '/terms' }">Terms of Service</a> and <a href="/privacy" v-link="{ path: '/privacy' }">Privacy Policy</a>.</p>
-			</section>
-			<footer class='modal-card-foot'>
-				<a class='button is-primary' href='#' @click='submitModal("login")'>Submit</a>
-				<a class='button is-github' :href='$parent.serverDomain + "/auth/github/authorize"' @click="githubRedirect()">
-					<div class='icon'>
-						<img class='invert' src='/assets/social/github.svg'/>
-					</div>
-					&nbsp;&nbsp;Login with GitHub
-				</a>
-				<a href='/reset_password' @click='resetPassword()'>Forgot password?</a>
-			</footer>
-		</div>
-	</div>
+  <div class="modal is-active">
+    <div class="modal-background"></div>
+    <div class="modal-card">
+      <header class="modal-card-head">
+        <p class="modal-card-title">Login</p>
+        <button class="delete" v-on:click="closeCurrentModal()"></button>
+      </header>
+      <section class="modal-card-body">
+        <!-- validation to check if exists http://bulma.io/documentation/elements/form/ -->
+        <label class="label">Email</label>
+        <p class="control">
+          <input class="input" type="text" placeholder="Email..." v-model="$parent.login.email" />
+        </p>
+        <label class="label">Password</label>
+        <p class="control">
+          <input
+            class="input"
+            type="password"
+            placeholder="Password..."
+            v-model="$parent.login.password"
+            v-on:keypress="$parent.submitOnEnter(submitModal, $event)"
+          />
+        </p>
+        <p>
+          By logging in/registering you agree to our
+          <router-link to="/terms">Terms of Service</router-link>and&nbsp;
+          <router-link to="/privacy">Privacy Policy</router-link>.
+        </p>
+      </section>
+      <footer class="modal-card-foot">
+        <a class="button is-primary" href="#" v-on:click="submitModal('login')">Submit</a>
+        <a
+          class="button is-github"
+          :href="$parent.serverDomain + '/auth/github/authorize'"
+          v-on:click="githubRedirect()"
+        >
+          <div class="icon">
+            <img class="invert" src="/assets/social/github.svg" />
+          </div>&nbsp;&nbsp;Login with GitHub
+        </a>
+        <a href="/reset_password" v-on:click="resetPassword()">Forgot password?</a>
+      </footer>
+    </div>
+  </div>
 </template>
 
 <script>
-	export default {
-		methods: {
-			toggleModal: function () {
-				if (this.$router._currentRoute.path === '/login') location.href = '/';
-				else this.$dispatch('toggleModal', 'login');
-			},
-			submitModal: function () {
-				this.$dispatch('login');
-				this.toggleModal();
-			},
-			resetPassword: function () {
-				this.toggleModal();
-				this.$router.go('/reset_password');
-			},
-			githubRedirect: function() {
-			    localStorage.setItem('github_redirect', this.$route.path)
-			}
-		},
-		events: {
-			closeModal: function() {
-				this.$dispatch('toggleModal', 'login');
-			}
-		}
-	}
+import { mapActions } from "vuex";
+
+export default {
+  methods: {
+    submitModal: function() {
+      // this.$dispatch('login');
+      //this.toggleModal();
+    },
+    resetPassword: function() {
+      this.$router.go("/reset_password");
+      //this.toggleModal();
+    },
+    githubRedirect: function() {
+      localStorage.setItem("github_redirect", this.$route.path);
+    },
+    ...mapActions("modals", ["toggleModal", "closeCurrentModal"])
+  }
+};
 </script>
 
-<style type='scss' scoped>
-	.button.is-github {
-		background-color: #333;
-		color: #fff !important;
-	}
+<style lang='scss' scoped>
+.button.is-github {
+  background-color: #333;
+  color: #fff !important;
+}
 
-	.is-github:focus { background-color: #1a1a1a; }
-	.is-primary:focus { background-color: #029ce3 !important; }
+.is-github:focus {
+  background-color: #1a1a1a;
+}
+.is-primary:focus {
+  background-color: #029ce3 !important;
+}
 
-	.invert { filter: brightness(5); }
+.invert {
+  filter: brightness(5);
+}
 
-	a { color: #029ce3; }
+a {
+  color: #029ce3;
+}
 </style>

+ 2 - 2
frontend/components/Modals/MobileAlert.vue

@@ -3,7 +3,7 @@
 		<div class='modal-background'></div>
 		<div class='modal-card'>
 			<header class='modal-card-head'>
-				<button class='delete' @click='toggleModal()'></button>
+				<button class='delete' v-on:click='toggleModal()'></button>
 			</header>
 			<section class='modal-card-body'>
 				<h5>Musare doesn't work very well on mobile right now, we are working on this!</h5>
@@ -21,7 +21,7 @@
 				isModalActive: false
 			}
 		},
-		ready: function () {
+		mounted: function () {
 			let _this = this;
 			if (!localStorage.getItem('mobileOptimization')) {
 				this.toggleModal();

+ 39 - 32
frontend/components/Modals/Modal.vue

@@ -1,37 +1,44 @@
 <template>
-	<div class='modal is-active'>
-		<div class='modal-background'></div>
-		<div class='modal-card'>
-			<header class='modal-card-head'>
-				<p class='modal-card-title'>{{ title }}</p>
-				<button class='delete' @click='$parent.$parent.modals[this.type] = !$parent.$parent.modals[this.type]'></button>
-			</header>
-			<section class='modal-card-body'>
-				<slot name='body'></slot>
-			</section>
-			<footer class='modal-card-foot' v-if='_slotContents["footer"] != null'>
-				<slot name='footer'></slot>
-			</footer>
-		</div>
-	</div>
+  <div class="modal is-active">
+    <div class="modal-background"></div>
+    <div class="modal-card">
+      <header class="modal-card-head">
+        <p class="modal-card-title">{{ title }}</p>
+        <button class="delete" v-on:click="closeCurrentModal()"></button>
+      </header>
+      <section class="modal-card-body">
+        <slot name="body"></slot>
+      </section>
+      <!-- v-if="_slotContents['footer'] != null" -->
+      <footer class="modal-card-foot">
+        <slot name="footer"></slot>
+      </footer>
+    </div>
+  </div>
 </template>
 
 <script>
-	export default {
-		props: {
-			title: { type: String }
-		},
-		methods: {
-			toCamelCase: str => {
-				return str.toLowerCase()
-					.replace(/[-_]+/g, ' ')
-					.replace(/[^\w\s]/g, '')
-					.replace(/ (.)/g, function($1) { return $1.toUpperCase(); })
-					.replace(/ /g, '');
-			}
-		},
-		ready: function () {
-			this.type = this.toCamelCase(this.title);
-		}
-	}
+import { mapActions } from "vuex";
+
+export default {
+  props: {
+    title: { type: String }
+  },
+  methods: {
+    toCamelCase: str => {
+      return str
+        .toLowerCase()
+        .replace(/[-_]+/g, " ")
+        .replace(/[^\w\s]/g, "")
+        .replace(/ (.)/g, function($1) {
+          return $1.toUpperCase();
+        })
+        .replace(/ /g, "");
+    },
+    ...mapActions("modals", ["closeCurrentModal"])
+  },
+  mounted: function() {
+    this.type = this.toCamelCase(this.title);
+  }
+};
 </script>

+ 87 - 72
frontend/components/Modals/Playlists/Create.vue

@@ -1,88 +1,103 @@
 <template>
-	<modal title='Create Playlist'>
-		<div slot='body'>
-			<p class='control is-expanded'>
-				<input class='input' type='text' placeholder='Playlist Display Name' v-model='playlist.displayName' autofocus @keyup.enter='createPlaylist()'>
-			</p>
-		</div>
-		<div slot='footer'>
-			<a class='button is-info' @click='createPlaylist()'>Create Playlist</a>
-		</div>
-	</modal>
+  <modal title="Create Playlist">
+    <template v-slot:body>
+      <p class="control is-expanded">
+        <input
+          class="input"
+          type="text"
+          placeholder="Playlist Display Name"
+          v-model="playlist.displayName"
+          autofocus
+          @keyup.enter="createPlaylist()"
+        />
+      </p>
+    </template>
+    <template v-slot:footer>
+      <a class="button is-info" v-on:click="createPlaylist()">Create Playlist</a>
+    </template>
+  </modal>
 </template>
 
 <script>
-	import { Toast } from 'vue-roaster';
-	import Modal from '../Modal.vue';
-	import io from '../../../io';
-	import validation from '../../../validation';
+import { Toast } from "vue-roaster";
+import Modal from "../Modal.vue";
+import io from "../../../io";
+import validation from "../../../validation";
 
-	export default {
-		components: { Modal },
-		data() {
-			return {
-				playlist: {
-					displayName: null,
-					songs: [],
-					createdBy: this.$parent.$parent.username,
-					createdAt: Date.now()
-				}
-			}
-		},
-		methods: {
-			createPlaylist: function () {
-				const displayName = this.playlist.displayName;
-				if (!validation.isLength(displayName, 2, 32)) return Toast.methods.addToast('Display name must have between 2 and 32 characters.', 8000);
-				if (!validation.regex.azAZ09_.test(displayName)) return Toast.methods.addToast('Invalid display name format. Allowed characters: a-z, A-Z, 0-9 and _.', 8000);
+export default {
+  components: { Modal },
+  data() {
+    return {
+      playlist: {
+        displayName: null,
+        songs: [],
+        createdBy: this.$parent.$parent.username,
+        createdAt: Date.now()
+      }
+    };
+  },
+  methods: {
+    createPlaylist: function() {
+      const displayName = this.playlist.displayName;
+      if (!validation.isLength(displayName, 2, 32))
+        return Toast.methods.addToast(
+          "Display name must have between 2 and 32 characters.",
+          8000
+        );
+      if (!validation.regex.azAZ09_.test(displayName))
+        return Toast.methods.addToast(
+          "Invalid display name format. Allowed characters: a-z, A-Z, 0-9 and _.",
+          8000
+        );
 
-
-				this.socket.emit('playlists.create', this.playlist, res => {
-					Toast.methods.addToast(res.message, 3000);
-				});
-				this.$parent.modals.createPlaylist = !this.$parent.modals.createPlaylist;
-			}
-		},
-		ready: function () {
-			let _this = this;
-			io.getSocket((socket) => {
-				_this.socket = socket;
-			});
-		},
-		events: {
-			closeModal: function() {
-				this.$parent.modals.createPlaylist = !this.$parent.modals.createPlaylist;
-			}
-		}
-	}
+      this.socket.emit("playlists.create", this.playlist, res => {
+        Toast.methods.addToast(res.message, 3000);
+      });
+      this.$parent.modals.createPlaylist = !this.$parent.modals.createPlaylist;
+    }
+  },
+  mounted: function() {
+    let _this = this;
+    io.getSocket(socket => {
+      _this.socket = socket;
+    });
+  }
+};
 </script>
 
-<style type='scss' scoped>
-	.menu { padding: 0 20px; }
+<style lang='scss' scoped>
+.menu {
+  padding: 0 20px;
+}
 
-	.menu-list li {
-		display: flex;
-		justify-content: space-between;
-	}
+.menu-list li {
+  display: flex;
+  justify-content: space-between;
+}
 
-	.menu-list a:hover { color: #000 !important; }
+.menu-list a:hover {
+  color: #000 !important;
+}
 
-	li a {
-		display: flex;
-    	align-items: center;
-	}
+li a {
+  display: flex;
+  align-items: center;
+}
 
-	.controls {
-		display: flex;
+.controls {
+  display: flex;
 
-		a {
-			display: flex;
-    		align-items: center;
-		}
-	}
+  a {
+    display: flex;
+    align-items: center;
+  }
+}
 
-	.table {
-		margin-bottom: 0;
-	}
+.table {
+  margin-bottom: 0;
+}
 
-	h5 { padding: 20px 0; }
+h5 {
+  padding: 20px 0;
+}
 </style>

+ 349 - 250
frontend/components/Modals/Playlists/Edit.vue

@@ -1,267 +1,366 @@
 <template>
-	<modal title='Edit Playlist'>
-		<div slot='body'>
-			<nav class="level">
-				<div class="level-item has-text-centered">
-					<div>
-						<p class="heading">Total Length</p>
-						<p class="title">{{ totalLength() }}</p>
-					</div>
-				</div>
-			</nav>
-			<hr />
-			<aside class='menu' v-if='playlist.songs && playlist.songs.length > 0'>
-				<ul class='menu-list'>
-					<li v-for='song in playlist.songs' track-by='$index'>
-						<a :href='' target='_blank'>{{ song.title }}</a>
-						<div class='controls'>
-							<a href='#' @click='promoteSong(song.songId)'>
-								<i class='material-icons' v-if='$index > 0'>keyboard_arrow_up</i>
-								<i class='material-icons' style='opacity: 0' v-else>error</i>
-							</a>
-							<a href='#' @click='demoteSong(song.songId)'>
-								<i class='material-icons' v-if='playlist.songs.length - 1 !== $index'>keyboard_arrow_down</i>
-								<i class='material-icons' style='opacity: 0' v-else>error</i>
-							</a>
-							<a href='#' @click='removeSongFromPlaylist(song.songId)'><i class='material-icons'>delete</i></a>
-						</div>
-					</li>
-				</ul>
-				<br />
-			</aside>
-			<div class='control is-grouped'>
-				<p class='control is-expanded'>
-					<input class='input' type='text' placeholder='Search for Song to add' v-model='songQuery' autofocus @keyup.enter='searchForSongs()'>
-				</p>
-				<p class='control'>
-					<a class='button is-info' @click='searchForSongs()' href="#">Search</a>
-				</p>
-			</div>
-			<table class='table' v-if='songQueryResults.length > 0'>
-				<tbody>
-				<tr v-for='result in songQueryResults'>
-					<td>
-						<img :src='result.thumbnail' />
-					</td>
-					<td>{{ result.title }}</td>
-					<td>
-						<a class='button is-success' @click='addSongToPlaylist(result.id)' href='#'>
-							Add
-						</a>
-					</td>
-				</tr>
-				</tbody>
-			</table>
-			<div class='control is-grouped'>
-				<p class='control is-expanded'>
-					<input class='input' type='text' placeholder='YouTube Playlist URL' v-model='importQuery' @keyup.enter="importPlaylist()">
-				</p>
-				<p class='control'>
-					<a class='button is-info' @click='importPlaylist()' href="#">Import</a>
-				</p>
-			</div>
-			<h5>Edit playlist details:</h5>
-			<div class='control is-grouped'>
-				<p class='control is-expanded'>
-					<input class='input' type='text' placeholder='Playlist Display Name' v-model='playlist.displayName' @keyup.enter="renamePlaylist()">
-				</p>
-				<p class='control'>
-					<a class='button is-info' @click='renamePlaylist()' href="#">Rename</a>
-				</p>
-			</div>
-		</div>
-		<div slot='footer'>
-			<a class='button is-danger' @click='removePlaylist()' href="#">Remove Playlist</a>
-		</div>
-	</modal>
+  <modal title="Edit Playlist">
+    <div slot="body">
+      <nav class="level">
+        <div class="level-item has-text-centered">
+          <div>
+            <p class="heading">Total Length</p>
+            <p class="title">{{ totalLength() }}</p>
+          </div>
+        </div>
+      </nav>
+      <hr />
+      <aside class="menu" v-if="playlist.songs && playlist.songs.length > 0">
+        <ul class="menu-list">
+          <li v-for="(song, index) in playlist.songs" :key="index">
+            <a href="#" target="_blank">{{ song.title }}</a>
+            <div class="controls">
+              <a href="#" v-on:click="promoteSong(song.songId)">
+                <i class="material-icons" v-if="$index > 0">keyboard_arrow_up</i>
+                <i class="material-icons" style="opacity: 0" v-else>error</i>
+              </a>
+              <a href="#" v-on:click="demoteSong(song.songId)">
+                <i
+                  class="material-icons"
+                  v-if="playlist.songs.length - 1 !== $index"
+                >keyboard_arrow_down</i>
+                <i class="material-icons" style="opacity: 0" v-else>error</i>
+              </a>
+              <a href="#" v-on:click="removeSongFromPlaylist(song.songId)">
+                <i class="material-icons">delete</i>
+              </a>
+            </div>
+          </li>
+        </ul>
+        <br />
+      </aside>
+      <div class="control is-grouped">
+        <p class="control is-expanded">
+          <input
+            class="input"
+            type="text"
+            placeholder="Search for Song to add"
+            v-model="songQuery"
+            autofocus
+            @keyup.enter="searchForSongs()"
+          />
+        </p>
+        <p class="control">
+          <a class="button is-info" v-on:click="searchForSongs()" href="#">Search</a>
+        </p>
+      </div>
+      <table class="table" v-if="songQueryResults.length > 0">
+        <tbody>
+          <tr v-for="(result, index) in songQueryResults" :key="index">
+            <td>
+              <img :src="result.thumbnail" />
+            </td>
+            <td>{{ result.title }}</td>
+            <td>
+              <a class="button is-success" v-on:click="addSongToPlaylist(result.id)" href="#">Add</a>
+            </td>
+          </tr>
+        </tbody>
+      </table>
+      <div class="control is-grouped">
+        <p class="control is-expanded">
+          <input
+            class="input"
+            type="text"
+            placeholder="YouTube Playlist URL"
+            v-model="importQuery"
+            @keyup.enter="importPlaylist()"
+          />
+        </p>
+        <p class="control">
+          <a class="button is-info" v-on:click="importPlaylist()" href="#">Import</a>
+        </p>
+      </div>
+      <h5>Edit playlist details:</h5>
+      <div class="control is-grouped">
+        <p class="control is-expanded">
+          <input
+            class="input"
+            type="text"
+            placeholder="Playlist Display Name"
+            v-model="playlist.displayName"
+            @keyup.enter="renamePlaylist()"
+          />
+        </p>
+        <p class="control">
+          <a class="button is-info" v-on:click="renamePlaylist()" href="#">Rename</a>
+        </p>
+      </div>
+    </div>
+    <div slot="footer">
+      <a class="button is-danger" v-on:click="removePlaylist()" href="#">Remove Playlist</a>
+    </div>
+  </modal>
 </template>
 
 <script>
-	import { Toast } from 'vue-roaster';
-	import Modal from '../Modal.vue';
-	import io from '../../../io';
-	import validation from '../../../validation';
+import { mapState } from "vuex";
 
-	export default {
-		components: { Modal },
-		data() {
-			return {
-				playlist: {songs: []},
-				songQueryResults: [],
-				songQuery: '',
-				importQuery: ''
-			}
-		},
-		methods: {
-			formatTime: function (length) {
-				let duration = moment.duration(length, 'seconds');
-				function getHours() {return Math.floor(duration.asHours());}
-				if (length <= 0) return '0 seconds';
-				else return ((getHours() > 0 ? (getHours() > 1 ? (getHours() < 10 ? ('0' + getHours() + ' hours ') : (getHours() + ' hours ')) : ('0' + getHours() + ' hour ')) : '') + (duration.minutes() > 0 ? (duration.minutes() > 1 ? (duration.minutes() < 10 ? ('0' + duration.minutes() + ' minutes ') : (duration.minutes() + ' minutes ')) : ('0' + duration.minutes() + ' minute ')) : '') + (duration.seconds() > 0 ? (duration.seconds() > 1 ? (duration.seconds() < 10 ? ('0' + duration.seconds() + ' seconds ') : (duration.seconds() + ' seconds ')) : ('0' + duration.seconds() + ' second ')) : ''));
-			},
-			totalLength: function() {
-			    let length = 0;
-			    this.playlist.songs.forEach((song) => {
-			        length += song.duration;
-				});
-			    return this.formatTime(length);
-			},
-			searchForSongs: function () {
-				let _this = this;
-				let query = _this.songQuery;
-				if (query.indexOf('&index=') !== -1) {
-					query = query.split('&index=');
-					query.pop();
-					query = query.join('');
-				}
-				if (query.indexOf('&list=') !== -1) {
-					query = query.split('&list=');
-					query.pop();
-					query = query.join('');
-				}
-				_this.socket.emit('apis.searchYoutube', query, res => {
-					if (res.status == 'success') {
-						_this.songQueryResults = [];
-						for (let i = 0; i < res.data.items.length; i++) {
-							_this.songQueryResults.push({
-								id: res.data.items[i].id.videoId,
-								url: `https://www.youtube.com/watch?v=${this.id}`,
-								title: res.data.items[i].snippet.title,
-								thumbnail: res.data.items[i].snippet.thumbnails.default.url
-							});
-						}
-					} else if (res.status === 'error') Toast.methods.addToast(res.message, 3000);
-				});
-			},
-			addSongToPlaylist: function (id) {
-				let _this = this;
-				_this.socket.emit('playlists.addSongToPlaylist', id, _this.playlist._id, res => {
-					Toast.methods.addToast(res.message, 4000);
-				});
-			},
-			importPlaylist: function () {
-				let _this = this;
-				Toast.methods.addToast('Starting to import your playlist. This can take some time to do.', 4000);
-				this.socket.emit('playlists.addSetToPlaylist', _this.importQuery, _this.playlist._id, res => {
-					if (res.status === 'success') _this.playlist.songs = res.data;
-					Toast.methods.addToast(res.message, 4000);
-				});
-			},
-			removeSongFromPlaylist: function (id) {
-				let _this = this;
-				this.socket.emit('playlists.removeSongFromPlaylist', id, _this.playlist._id, res => {
-					Toast.methods.addToast(res.message, 4000);
-				});
-			},
-			renamePlaylist: function () {
-				const displayName = this.playlist.displayName;
-				if (!validation.isLength(displayName, 2, 32)) return Toast.methods.addToast('Display name must have between 2 and 32 characters.', 8000);
-				if (!validation.regex.azAZ09_.test(displayName)) return Toast.methods.addToast('Invalid display name format. Allowed characters: a-z, A-Z, 0-9 and _.', 8000);
+import { Toast } from "vue-roaster";
+import Modal from "../Modal.vue";
+import io from "../../../io";
+import validation from "../../../validation";
 
+export default {
+  components: { Modal },
+  data() {
+    return {
+      playlist: { songs: [] },
+      songQueryResults: [],
+      songQuery: "",
+      importQuery: ""
+    };
+  },
+  computed: mapState("user/playlists", {
+    editing: state => state.editing
+  }),
+  methods: {
+    formatTime: function(length) {
+      let duration = moment.duration(length, "seconds");
+      function getHours() {
+        return Math.floor(duration.asHours());
+      }
+      if (length <= 0) return "0 seconds";
+      else
+        return (
+          (getHours() > 0
+            ? getHours() > 1
+              ? getHours() < 10
+                ? "0" + getHours() + " hours "
+                : getHours() + " hours "
+              : "0" + getHours() + " hour "
+            : "") +
+          (duration.minutes() > 0
+            ? duration.minutes() > 1
+              ? duration.minutes() < 10
+                ? "0" + duration.minutes() + " minutes "
+                : duration.minutes() + " minutes "
+              : "0" + duration.minutes() + " minute "
+            : "") +
+          (duration.seconds() > 0
+            ? duration.seconds() > 1
+              ? duration.seconds() < 10
+                ? "0" + duration.seconds() + " seconds "
+                : duration.seconds() + " seconds "
+              : "0" + duration.seconds() + " second "
+            : "")
+        );
+    },
+    totalLength: function() {
+      let length = 0;
+      this.playlist.songs.forEach(song => {
+        length += song.duration;
+      });
+      return this.formatTime(length);
+    },
+    searchForSongs: function() {
+      let _this = this;
+      let query = _this.songQuery;
+      if (query.indexOf("&index=") !== -1) {
+        query = query.split("&index=");
+        query.pop();
+        query = query.join("");
+      }
+      if (query.indexOf("&list=") !== -1) {
+        query = query.split("&list=");
+        query.pop();
+        query = query.join("");
+      }
+      _this.socket.emit("apis.searchYoutube", query, res => {
+        if (res.status == "success") {
+          _this.songQueryResults = [];
+          for (let i = 0; i < res.data.items.length; i++) {
+            _this.songQueryResults.push({
+              id: res.data.items[i].id.videoId,
+              url: `https://www.youtube.com/watch?v=${this.id}`,
+              title: res.data.items[i].snippet.title,
+              thumbnail: res.data.items[i].snippet.thumbnails.default.url
+            });
+          }
+        } else if (res.status === "error")
+          Toast.methods.addToast(res.message, 3000);
+      });
+    },
+    addSongToPlaylist: function(id) {
+      let _this = this;
+      _this.socket.emit(
+        "playlists.addSongToPlaylist",
+        id,
+        _this.playlist._id,
+        res => {
+          Toast.methods.addToast(res.message, 4000);
+        }
+      );
+    },
+    importPlaylist: function() {
+      let _this = this;
+      Toast.methods.addToast(
+        "Starting to import your playlist. This can take some time to do.",
+        4000
+      );
+      this.socket.emit(
+        "playlists.addSetToPlaylist",
+        _this.importQuery,
+        _this.playlist._id,
+        res => {
+          if (res.status === "success") _this.playlist.songs = res.data;
+          Toast.methods.addToast(res.message, 4000);
+        }
+      );
+    },
+    removeSongFromPlaylist: function(id) {
+      let _this = this;
+      this.socket.emit(
+        "playlists.removeSongFromPlaylist",
+        id,
+        _this.playlist._id,
+        res => {
+          Toast.methods.addToast(res.message, 4000);
+        }
+      );
+    },
+    renamePlaylist: function() {
+      const displayName = this.playlist.displayName;
+      if (!validation.isLength(displayName, 2, 32))
+        return Toast.methods.addToast(
+          "Display name must have between 2 and 32 characters.",
+          8000
+        );
+      if (!validation.regex.azAZ09_.test(displayName))
+        return Toast.methods.addToast(
+          "Invalid display name format. Allowed characters: a-z, A-Z, 0-9 and _.",
+          8000
+        );
 
-				this.socket.emit('playlists.updateDisplayName', this.playlist._id, this.playlist.displayName, res => {
-					Toast.methods.addToast(res.message, 4000);
-				});
-			},
-			removePlaylist: function () {
-				let _this = this;
-				_this.socket.emit('playlists.remove', _this.playlist._id, res => {
-					Toast.methods.addToast(res.message, 3000);
-					if (res.status === 'success') {
-						_this.$parent.modals.editPlaylist = !_this.$parent.modals.editPlaylist;
-					}
-				});
-			},
-			promoteSong: function (songId) {
-				let _this = this;
-				_this.socket.emit('playlists.moveSongToTop', _this.playlist._id, songId, res => {
-					Toast.methods.addToast(res.message, 4000);
-				});
-			},
-			demoteSong: function (songId) {
-				let _this = this;
-				_this.socket.emit('playlists.moveSongToBottom', _this.playlist._id, songId, res => {
-					Toast.methods.addToast(res.message, 4000);
-				});
-			}
-		},
-		ready: function () {
-			let _this = this;
-			io.getSocket((socket) => {
-				_this.socket = socket;
-				_this.socket.emit('playlists.getPlaylist', _this.$parent.playlistBeingEdited, res => {
-					if (res.status === 'success') _this.playlist = res.data; _this.playlist.oldId = res.data._id;
-				});
-				_this.socket.on('event:playlist.addSong', data => {
-					if (_this.playlist._id === data.playlistId) _this.playlist.songs.push(data.song);
-				});
-				_this.socket.on('event:playlist.removeSong', data => {
-					if (_this.playlist._id === data.playlistId) {
-						_this.playlist.songs.forEach((song, index) => {
-							if (song.songId === data.songId) _this.playlist.songs.splice(index, 1);
-						});
-					}
-				});
-				_this.socket.on('event:playlist.updateDisplayName', data => {
-					if (_this.playlist._id === data.playlistId) _this.playlist.displayName = data.displayName;
-				});
-				_this.socket.on('event:playlist.moveSongToBottom', data => {
-					if (_this.playlist._id === data.playlistId) {
-						let songIndex;
-						_this.playlist.songs.forEach((song, index) => {
-							if (song.songId === data.songId) songIndex = index;
-						});
-						let song = _this.playlist.songs.splice(songIndex, 1)[0];
-						_this.playlist.songs.push(song);
-					}
-				});
-				_this.socket.on('event:playlist.moveSongToTop', (data) => {
-					if (_this.playlist._id === data.playlistId) {
-						let songIndex;
-						_this.playlist.songs.forEach((song, index) => {
-							if (song.songId === data.songId) songIndex = index;
-						});
-						let song = _this.playlist.songs.splice(songIndex, 1)[0];
-						_this.playlist.songs.unshift(song);
-					}
-				});
-			});
-		},
-		events: {
-			closeModal: function() {
-				this.$parent.modals.editPlaylist = !this.$parent.modals.editPlaylist;
-			}
-		}
-	}
+      this.socket.emit(
+        "playlists.updateDisplayName",
+        this.playlist._id,
+        this.playlist.displayName,
+        res => {
+          Toast.methods.addToast(res.message, 4000);
+        }
+      );
+    },
+    removePlaylist: function() {
+      let _this = this;
+      _this.socket.emit("playlists.remove", _this.playlist._id, res => {
+        Toast.methods.addToast(res.message, 3000);
+        if (res.status === "success") {
+          _this.$parent.modals.editPlaylist = !_this.$parent.modals
+            .editPlaylist;
+        }
+      });
+    },
+    promoteSong: function(songId) {
+      let _this = this;
+      _this.socket.emit(
+        "playlists.moveSongToTop",
+        _this.playlist._id,
+        songId,
+        res => {
+          Toast.methods.addToast(res.message, 4000);
+        }
+      );
+    },
+    demoteSong: function(songId) {
+      let _this = this;
+      _this.socket.emit(
+        "playlists.moveSongToBottom",
+        _this.playlist._id,
+        songId,
+        res => {
+          Toast.methods.addToast(res.message, 4000);
+        }
+      );
+    }
+  },
+  mounted: function() {
+    let _this = this;
+    io.getSocket(socket => {
+      _this.socket = socket;
+      _this.socket.emit("playlists.getPlaylist", _this.editing, res => {
+        if (res.status === "success") _this.playlist = res.data;
+        _this.playlist.oldId = res.data._id;
+      });
+      _this.socket.on("event:playlist.addSong", data => {
+        if (_this.playlist._id === data.playlistId)
+          _this.playlist.songs.push(data.song);
+      });
+      _this.socket.on("event:playlist.removeSong", data => {
+        if (_this.playlist._id === data.playlistId) {
+          _this.playlist.songs.forEach((song, index) => {
+            if (song.songId === data.songId)
+              _this.playlist.songs.splice(index, 1);
+          });
+        }
+      });
+      _this.socket.on("event:playlist.updateDisplayName", data => {
+        if (_this.playlist._id === data.playlistId)
+          _this.playlist.displayName = data.displayName;
+      });
+      _this.socket.on("event:playlist.moveSongToBottom", data => {
+        if (_this.playlist._id === data.playlistId) {
+          let songIndex;
+          _this.playlist.songs.forEach((song, index) => {
+            if (song.songId === data.songId) songIndex = index;
+          });
+          let song = _this.playlist.songs.splice(songIndex, 1)[0];
+          _this.playlist.songs.push(song);
+        }
+      });
+      _this.socket.on("event:playlist.moveSongToTop", data => {
+        if (_this.playlist._id === data.playlistId) {
+          let songIndex;
+          _this.playlist.songs.forEach((song, index) => {
+            if (song.songId === data.songId) songIndex = index;
+          });
+          let song = _this.playlist.songs.splice(songIndex, 1)[0];
+          _this.playlist.songs.unshift(song);
+        }
+      });
+    });
+  }
+};
 </script>
 
-<style type='scss' scoped>
-	.menu { padding: 0 20px; }
+<style lang='scss' scoped>
+.menu {
+  padding: 0 20px;
+}
 
-	.menu-list li {
-		display: flex;
-		justify-content: space-between;
-	}
+.menu-list li {
+  display: flex;
+  justify-content: space-between;
+}
 
-	.menu-list a:hover { color: #000 !important; }
+.menu-list a:hover {
+  color: #000 !important;
+}
 
-	li a {
-		display: flex;
-    	align-items: center;
-	}
+li a {
+  display: flex;
+  align-items: center;
+}
 
-	.controls {
-		display: flex;
+.controls {
+  display: flex;
 
-		a {
-			display: flex;
-    		align-items: center;
-		}
-	}
+  a {
+    display: flex;
+    align-items: center;
+  }
+}
 
-	.table {
-		margin-bottom: 0;
-	}
+.table {
+  margin-bottom: 0;
+}
 
-	h5 { padding: 20px 0; }
+h5 {
+  padding: 20px 0;
+}
 </style>

+ 109 - 81
frontend/components/Modals/Register.vue

@@ -1,92 +1,120 @@
 <template>
-	<div class='modal is-active'>
-		<div class='modal-background'></div>
-		<div class='modal-card'>
-			<header class='modal-card-head'>
-				<p class='modal-card-title'>Register</p>
-				<button class='delete' @click='toggleModal()'></button>
-			</header>
-			<section class='modal-card-body'>
-				<!-- validation to check if exists http://bulma.io/documentation/elements/form/ -->
-				<label class='label'>Email</label>
-				<p class='control'>
-					<input class='input' type='text' placeholder='Email...' v-model='$parent.register.email' autofocus>
-				</p>
-				<label class='label'>Username</label>
-				<p class='control'>
-					<input class='input' type='text' placeholder='Username...' v-model='$parent.register.username'>
-				</p>
-				<label class='label'>Password</label>
-				<p class='control'>
-					<input class='input' type='password' placeholder='Password...' v-model='$parent.register.password' v-on:keypress='$parent.submitOnEnter(submitModal, $event)'>
-				</p>
-				<div id="recaptcha"></div>
-				<p>By logging in/registering you agree to our <a href="/terms" v-link="{ path: '/terms' }">Terms of Service</a> and <a href="/privacy" v-link="{ path: '/privacy' }">Privacy Policy</a>.</p>
-			</section>
-			<footer class='modal-card-foot'>
-				<a class='button is-primary' href='#' @click='submitModal()'>Submit</a>
-				<a class='button is-github' :href='$parent.serverDomain + "/auth/github/authorize"' @click="githubRedirect()">
-					<div class='icon'>
-						<img class='invert' src='/assets/social/github.svg'/>
-					</div>
-					&nbsp;&nbsp;Register with GitHub
-				</a>
-			</footer>
-		</div>
-	</div>
+  <div class="modal is-active">
+    <div class="modal-background"></div>
+    <div class="modal-card">
+      <header class="modal-card-head">
+        <p class="modal-card-title">Register</p>
+        <button class="delete" v-on:click="closeCurrentModal()"></button>
+      </header>
+      <section class="modal-card-body">
+        <!-- validation to check if exists http://bulma.io/documentation/elements/form/ -->
+        <label class="label">Email</label>
+        <p class="control">
+          <input
+            class="input"
+            type="text"
+            placeholder="Email..."
+            v-model="$parent.register.email"
+            autofocus
+          />
+        </p>
+        <label class="label">Username</label>
+        <p class="control">
+          <input
+            class="input"
+            type="text"
+            placeholder="Username..."
+            v-model="$parent.register.username"
+          />
+        </p>
+        <label class="label">Password</label>
+        <p class="control">
+          <input
+            class="input"
+            type="password"
+            placeholder="Password..."
+            v-model="$parent.register.password"
+            v-on:keypress="$parent.submitOnEnter(submitModal, $event)"
+          />
+        </p>
+        <div id="recaptcha"></div>
+        <p>
+          By logging in/registering you agree to our
+          <router-link to="/terms">Terms of Service</router-link>and
+          <router-link to="/privacy">Privacy Policy</router-link>.
+        </p>
+      </section>
+      <footer class="modal-card-foot">
+        <a class="button is-primary" href="#" v-on:click="submitModal()">Submit</a>
+        <a
+          class="button is-github"
+          :href="$parent.serverDomain + '/auth/github/authorize'"
+          v-on:click="githubRedirect()"
+        >
+          <div class="icon">
+            <img class="invert" src="/assets/social/github.svg" />
+          </div>&nbsp;&nbsp;Register with GitHub
+        </a>
+      </footer>
+    </div>
+  </div>
 </template>
 
 <script>
-	export default {
-		data() {
-			return {
-				recaptcha: {
-					key: ''
-				}
-			}
-		},
-		ready: function () {
-			let _this = this;
-			lofig.get('recaptcha', obj => {
-				_this.recaptcha.key = obj.key;
-				_this.recaptcha.id = grecaptcha.render('recaptcha', {
-					'sitekey' : _this.recaptcha.key
-				});
-			});
-		},
-		methods: {
-			toggleModal: function () {
-				if (this.$router._currentRoute.path === '/register') location.href = '/';
-				else this.$dispatch('toggleModal', 'register');
-			},
-			submitModal: function () {
-				this.$dispatch('register', this.recaptcha.id);
-				this.toggleModal();
-			},
-			githubRedirect: function() {
-				localStorage.setItem('github_redirect', this.$route.path)
-			}
-		},
-		events: {
-			closeModal: function() {
-				this.$dispatch('toggleModal', 'register');
-			}
-		}
-	}
+import { mapActions } from "vuex";
+
+export default {
+  data() {
+    return {
+      recaptcha: {
+        key: ""
+      }
+    };
+  },
+  mounted: function() {
+    let _this = this;
+    lofig.get("recaptcha", obj => {
+      _this.recaptcha.key = obj.key;
+      _this.recaptcha.id = grecaptcha.render("recaptcha", {
+        sitekey: _this.recaptcha.key
+      });
+    });
+  },
+  methods: {
+    submitModal: function() {
+      // this.$dispatch('register', this.recaptcha.id);
+      this.toggleModal();
+    },
+    githubRedirect: function() {
+      localStorage.setItem("github_redirect", this.$route.path);
+    },
+    ...mapActions("modals", ["toggleModal", "closeCurrentModal"])
+  }
+};
 </script>
 
-<style type='scss' scoped>
-	.button.is-github {
-		background-color: #333;
-		color: #fff !important;
-	}
+<style lang='scss' scoped>
+.button.is-github {
+  background-color: #333;
+  color: #fff !important;
+}
 
-	.is-github:focus { background-color: #1a1a1a; }
-	.is-primary:focus { background-color: #028bca !important; }
+.is-github:focus {
+  background-color: #1a1a1a;
+}
+.is-primary:focus {
+  background-color: #028bca !important;
+}
 
-	.invert { filter: brightness(5); }
+.invert {
+  filter: brightness(5);
+}
 
-	#recaptcha { padding: 10px 0; }
+#recaptcha {
+  padding: 10px 0;
+}
 
-	a { color: #029ce3; }
+a {
+  color: #029ce3;
+}
 </style>

+ 9 - 9
frontend/components/Modals/Report.vue

@@ -3,7 +3,7 @@
 		<div slot='body'>
 			<div class='columns song-types'>
 				<div class='column song-type' v-if='$parent.previousSong !== null'>
-					<div class='card is-fullwidth' :class="{ 'is-highlight-active': isPreviousSongActive }" @click="highlight('previousSong')">
+					<div class='card is-fullwidth' :class="{ 'is-highlight-active': isPreviousSongActive }" v-on:click="highlight('previousSong')">
 						<header class='card-header'>
 							<p class='card-header-title'>
 								Previous Song
@@ -27,11 +27,11 @@
 								</div>
 							</article>
 						</div>
-						<a @click=highlight('previousSong') href='#' class='absolute-a'></a>
+						<a v-on:click=highlight('previousSong') href='#' class='absolute-a'></a>
 					</div>
 				</div>
 				<div class='column song-type' v-if='$parent.currentSong !== {}'>
-					<div class='card is-fullwidth'  :class="{ 'is-highlight-active': isCurrentSongActive }" @click="highlight('currentSong')">
+					<div class='card is-fullwidth'  :class="{ 'is-highlight-active': isCurrentSongActive }" v-on:click="highlight('currentSong')">
 						<header class='card-header'>
 							<p class='card-header-title'>
 								Current Song
@@ -55,7 +55,7 @@
 								</div>
 							</article>
 						</div>
-						<a @click=highlight('currentSong') href='#' class='absolute-a'></a>
+						<a v-on:click=highlight('currentSong') href='#' class='absolute-a'></a>
 					</div>
 				</div>
 			</div>
@@ -65,7 +65,7 @@
 						<label class='label'>{{ issue.name }}</label>
 						<p class='control' v-for='reason in issue.reasons' track-by='$index'>
 							<label class='checkbox'>
-								<input type='checkbox' @click='toggleIssue(issue.name, reason)'>
+								<input type='checkbox' v-on:click='toggleIssue(issue.name, reason)'>
 								{{ reason }}
 							</label>
 						</p>
@@ -79,11 +79,11 @@
 			</div>
 		</div>
 		<div slot='footer'>
-			<a class='button is-success' @click='create()' href='#'>
+			<a class='button is-success' v-on:click='create()' href='#'>
 				<i class='material-icons save-changes'>done</i>
 				<span>&nbsp;Create</span>
 			</a>
-			<a class='button is-danger' @click='$parent.modals.report = !$parent.modals.report' href='#'>
+			<a class='button is-danger' v-on:click='$parent.modals.report = !$parent.modals.report' href='#'>
 				<span>&nbsp;Cancel</span>
 			</a>
 		</div>
@@ -197,7 +197,7 @@
 				this.$parent.modals.report = !this.$parent.modals.report;
 			}
 		},
-		ready: function () {
+		mounted: function () {
 			let _this = this;
 			io.getSocket((socket) => {
 				_this.socket = socket;
@@ -206,7 +206,7 @@
 	}
 </script>
 
-<style type='scss' scoped>
+<style lang='scss' scoped>
 	h6 { margin-bottom: 15px; }
 
 	.song-type:first-of-type { padding-left: 0; }

+ 61 - 58
frontend/components/Modals/ViewPunishment.vue

@@ -1,64 +1,67 @@
 <template>
-	<div>
-		<modal title='View Punishment'>
-			<div slot='body'>
-				<article class="message">
-					<div class="message-body">
-						<strong>Type: </strong>{{ punishment.type }}<br/>
-						<strong>Value: </strong>{{ punishment.value }}<br/>
-						<strong>Reason: </strong>{{ punishment.reason }}<br/>
-						<strong>Active: </strong>{{ punishment.active }}<br/>
-						<strong>Expires at: </strong>{{ moment(punishment.expiresAt).format('MMMM Do YYYY, h:mm:ss a'); }} ({{ moment(punishment.expiresAt).fromNow() }})<br/>
-						<strong>Punished at: </strong>{{ moment(punishment.punishedAt).format('MMMM Do YYYY, h:mm:ss a') }} ({{ moment(punishment.punishedAt).fromNow() }})<br/>
-						<strong>Punished by: </strong>{{ punishment.punishedBy }}<br/>
-					</div>
-				</article>
-			</div>
-			<div slot='footer'>
-				<button class='button is-danger' @click='$parent.toggleModal()'>
-					<span>&nbsp;Close</span>
-				</button>
-			</div>
-		</modal>
-	</div>
+  <div>
+    <modal title="View Punishment">
+      <div slot="body">
+        <article class="message">
+          <div class="message-body">
+            <strong>Type:</strong>
+            {{ punishment.type }}
+            <br />
+            <strong>Value:</strong>
+            {{ punishment.value }}
+            <br />
+            <strong>Reason:</strong>
+            {{ punishment.reason }}
+            <br />
+            <strong>Active:</strong>
+            {{ punishment.active }}
+            <br />
+            <strong>Expires at:</strong>
+            {{ moment(punishment.expiresAt).format('MMMM Do YYYY, h:mm:ss a') }} ({{ moment(punishment.expiresAt).fromNow() }})
+            <br />
+            <strong>Punished at:</strong>
+            {{ moment(punishment.punishedAt).format('MMMM Do YYYY, h:mm:ss a') }} ({{ moment(punishment.punishedAt).fromNow() }})
+            <br />
+            <strong>Punished by:</strong>
+            {{ punishment.punishedBy }}
+            <br />
+          </div>
+        </article>
+      </div>
+      <div slot="footer">
+        <button class="button is-danger" v-on:click="$parent.toggleModal()">
+          <span>&nbsp;Close</span>
+        </button>
+      </div>
+    </modal>
+  </div>
 </template>
 
 <script>
-	import io from '../../io';
-	import { Toast } from 'vue-roaster';
-	import Modal from './Modal.vue';
-	import validation from '../../validation';
+import { mapState } from "vuex";
 
-	export default {
-		components: { Modal },
-		data() {
-			return {
-				punishment: {},
-				ban: {},
-				moment
-			}
-		},
-		methods: {},
-		ready: function () {
-			let _this = this;
-			io.getSocket(socket => _this.socket = socket );
-		},
-		events: {
-			closeModal: function () {
-				this.$parent.modals.viewPunishment = false;
-			},
-			viewPunishment: function (punishment) {
-				this.punishment = {
-					type: punishment.type,
-					value: punishment.value,
-					reason: punishment.reason,
-					active: punishment.active,
-					expiresAt: punishment.expiresAt,
-					punishedAt: punishment.punishedAt,
-					punishedBy: punishment.punishedBy
-				};
-				this.$parent.toggleModal();
-			}
-		}
-	}
+import io from "../../io";
+import { Toast } from "vue-roaster";
+import Modal from "./Modal.vue";
+import validation from "../../validation";
+
+export default {
+  components: { Modal },
+  data() {
+    return {
+      ban: {},
+      moment
+    };
+  },
+  computed: {
+    ...mapState("admin/punishments", {
+      punishment: state => state.punishment
+    })
+  },
+  methods: {},
+  mounted: function() {
+    let _this = this;
+    io.getSocket(socket => (_this.socket = socket));
+  }
+};
 </script>

+ 2 - 2
frontend/components/Modals/WhatIsNew.vue

@@ -4,7 +4,7 @@
 		<div class='modal-card'>
 			<header class='modal-card-head'>
 				<p class='modal-card-title'><strong>{{ news.title }}</strong> ({{ formatDate(news.createdAt) }})</p>
-				<button class='delete' @click='toggleModal()'></button>
+				<button class='delete' v-on:click='toggleModal()'></button>
 			</header>
 			<section class='modal-card-body'>
 				<div class='content'>
@@ -49,7 +49,7 @@
 				news: null
 			}
 		},
-		ready: function () {
+		mounted: function () {
 			let _this = this;
 			io.getSocket(true, socket => {
 				_this.socket = socket;

+ 185 - 153
frontend/components/Sidebars/Playlist.vue

@@ -1,160 +1,192 @@
 <template>
-	<div class='sidebar' transition='slide' v-if='$parent.sidebars.playlist'>
-		<div class='inner-wrapper'>
-			<div class='title'>Playlists</div>
-
-			<aside class='menu' v-if='playlists.length > 0'>
-				<ul class='menu-list'>
-					<li v-for='playlist in playlists'>
-						<span>{{ playlist.displayName }}</span>
-						<!--Will play playlist in community station Kris-->
-						<div class='icons-group'>
-							<a href='#' @click='selectPlaylist(playlist._id)' v-if="isNotSelected(playlist._id) && !this.$parent.$parent.station.partyMode">
-								<i class='material-icons'>play_arrow</i>
-							</a>
-							<a href='#' @click='editPlaylist(playlist._id)'>
-								<i class='material-icons'>edit</i>
-							</a>
-						</div>
-					</li>
-				</ul>
-			</aside>
-
-			<div class='none-found' v-else>No Playlists found</div>
-
-			<a class='button create-playlist' href='#' @click='$parent.modals.createPlaylist = !$parent.modals.createPlaylist'>Create Playlist</a>
-		</div>
-	</div>
+  <div class="sidebar" transition="slide">
+    <div class="inner-wrapper">
+      <div class="title">Playlists</div>
+
+      <aside class="menu" v-if="playlists.length > 0">
+        <ul class="menu-list">
+          <li v-for="(playlist, index) in playlists" :key="index">
+            <span>{{ playlist.displayName }}</span>
+            <!--Will play playlist in community station Kris-->
+            <div class="icons-group">
+              <a
+                href="#"
+                v-on:click="selectPlaylist(playlist._id)"
+                v-if="isNotSelected(playlist._id) && !$parent.station.partyMode"
+              >
+                <i class="material-icons">play_arrow</i>
+              </a>
+              <a href="#" v-on:click="edit(playlist._id)">
+                <i class="material-icons">edit</i>
+              </a>
+            </div>
+          </li>
+        </ul>
+      </aside>
+
+      <div class="none-found" v-else>No Playlists found</div>
+
+      <a
+        class="button create-playlist"
+        href="#"
+        v-on:click="toggleModal({ sector: 'station', modal: 'createPlaylist' })"
+      >Create Playlist</a>
+    </div>
+  </div>
 </template>
 
 <script>
-	import { Toast } from 'vue-roaster';
-	import { Edit } from '../Modals/Playlists/Edit.vue';
-	import io from '../../io';
-
-	export default {
-		data() {
-			return {
-				playlists: []
-			}
-		},
-		methods: {
-			editPlaylist: function(id) {
-				this.$parent.editPlaylist(id);
-			},
-			selectPlaylist: function(id) {
-				this.socket.emit('stations.selectPrivatePlaylist', this.$parent.station._id, id, (res) => {
-					if (res.status === 'failure') return Toast.methods.addToast(res.message, 8000);
-					Toast.methods.addToast(res.message, 4000);
-				});
-			},
-			isNotSelected: function(id) {
-				let _this = this;
-				//TODO Also change this once it changes for a station
-				if (_this.$parent.station && _this.$parent.station.privatePlaylist === id) return false;
-				return true;
-			}
-		},
-		ready: function () {
-			// TODO: Update when playlist is removed/created
-			let _this = this;
-			io.getSocket((socket) => {
-				_this.socket = socket;
-				_this.socket.emit('playlists.indexForUser', res => {
-					if (res.status == 'success') _this.playlists = res.data;
-				});
-				_this.socket.on('event:playlist.create', (playlist) => {
-					_this.playlists.push(playlist);
-				});
-				_this.socket.on('event:playlist.delete', (playlistId) => {
-					_this.playlists.forEach((playlist, index) => {
-						if (playlist._id === playlistId) {
-							_this.playlists.splice(index, 1);
-						}
-					});
-				});
-				_this.socket.on('event:playlist.addSong', (data) => {
-					_this.playlists.forEach((playlist, index) => {
-						if (playlist._id === data.playlistId) {
-							_this.playlists[index].songs.push(data.song);
-						}
-					});
-				});
-				_this.socket.on('event:playlist.removeSong', (data) => {
-					_this.playlists.forEach((playlist, index) => {
-						if (playlist._id === data.playlistId) {
-							_this.playlists[index].songs.forEach((song, index2) => {
-								if (song._id === data.songId) {
-									_this.playlists[index].songs.splice(index2, 1);
-								}
-							});
-						}
-					});
-				});
-				_this.socket.on('event:playlist.updateDisplayName', (data) => {
-					_this.playlists.forEach((playlist, index) => {
-						if (playlist._id === data.playlistId) {
-							_this.playlists[index].displayName = data.displayName;
-						}
-					});
-				});
-			});
-		}
-	}
+import { mapActions } from "vuex";
+
+import { Toast } from "vue-roaster";
+import { Edit } from "../Modals/Playlists/Edit.vue";
+import io from "../../io";
+
+export default {
+  data() {
+    return {
+      playlists: []
+    };
+  },
+  methods: {
+    edit: function(id) {
+      this.editPlaylist(id);
+      this.toggleModal({ sector: "station", modal: "editPlaylist" });
+    },
+    selectPlaylist: function(id) {
+      this.socket.emit(
+        "stations.selectPrivatePlaylist",
+        this.$parent.station._id,
+        id,
+        res => {
+          if (res.status === "failure")
+            return Toast.methods.addToast(res.message, 8000);
+          Toast.methods.addToast(res.message, 4000);
+        }
+      );
+    },
+    isNotSelected: function(id) {
+      let _this = this;
+      //TODO Also change this once it changes for a station
+      if (_this.$parent.station && _this.$parent.station.privatePlaylist === id)
+        return false;
+      return true;
+    },
+    ...mapActions("modals", ["toggleModal"]),
+    ...mapActions("user/playlists", ["editPlaylist"])
+  },
+  mounted: function() {
+    // TODO: Update when playlist is removed/created
+    let _this = this;
+    io.getSocket(socket => {
+      _this.socket = socket;
+      _this.socket.emit("playlists.indexForUser", res => {
+        if (res.status == "success") _this.playlists = res.data;
+      });
+      _this.socket.on("event:playlist.create", playlist => {
+        _this.playlists.push(playlist);
+      });
+      _this.socket.on("event:playlist.delete", playlistId => {
+        _this.playlists.forEach((playlist, index) => {
+          if (playlist._id === playlistId) {
+            _this.playlists.splice(index, 1);
+          }
+        });
+      });
+      _this.socket.on("event:playlist.addSong", data => {
+        _this.playlists.forEach((playlist, index) => {
+          if (playlist._id === data.playlistId) {
+            _this.playlists[index].songs.push(data.song);
+          }
+        });
+      });
+      _this.socket.on("event:playlist.removeSong", data => {
+        _this.playlists.forEach((playlist, index) => {
+          if (playlist._id === data.playlistId) {
+            _this.playlists[index].songs.forEach((song, index2) => {
+              if (song._id === data.songId) {
+                _this.playlists[index].songs.splice(index2, 1);
+              }
+            });
+          }
+        });
+      });
+      _this.socket.on("event:playlist.updateDisplayName", data => {
+        _this.playlists.forEach((playlist, index) => {
+          if (playlist._id === data.playlistId) {
+            _this.playlists[index].displayName = data.displayName;
+          }
+        });
+      });
+    });
+  }
+};
 </script>
 
-<style type='scss' scoped>
-	.sidebar {
-		position: fixed;
-		z-index: 1;
-		top: 0;
-		right: 0;
-		width: 300px;
-		height: 100vh;
-		background-color: #fff;
-		box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12);
-	}
-
-	.icons-group a {
-		display: flex;
-    	align-items: center;
-	}
-
-	.menu-list li { align-items: center; }
-
-	.inner-wrapper {	
-		top: 64px;
-		position: relative;
-	}
-
-	.slide-transition {
-		transition: transform 0.6s ease-in-out;
-		transform: translateX(0);
-	}
-
-	.slide-enter, .slide-leave { transform: translateX(100%); }
-
-	.title {
-		background-color: rgb(3, 169, 244);
-		text-align: center;
-		padding: 10px;
-		color: white;
-		font-weight: 600;
-	}
-
-	.create-playlist {
-		width: 100%;
-    	margin-top: 20px;
-		height: 40px;
-		border-radius: 0;
-		background: rgba(3, 169, 244, 1);
-    	color: #fff !important;
-		border: 0;
-
-		&:active, &:focus { border: 0; }
-	}
-
-	.create-playlist:focus { background: #029ce3; }
-
-	.none-found { text-align: center; }
+<style lang='scss' scoped>
+.sidebar {
+  position: fixed;
+  z-index: 1;
+  top: 0;
+  right: 0;
+  width: 300px;
+  height: 100vh;
+  background-color: #fff;
+  box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12);
+}
+
+.icons-group a {
+  display: flex;
+  align-items: center;
+}
+
+.menu-list li {
+  align-items: center;
+}
+
+.inner-wrapper {
+  top: 64px;
+  position: relative;
+}
+
+.slide-transition {
+  transition: transform 0.6s ease-in-out;
+  transform: translateX(0);
+}
+
+.slide-enter,
+.slide-leave {
+  transform: translateX(100%);
+}
+
+.title {
+  background-color: rgb(3, 169, 244);
+  text-align: center;
+  padding: 10px;
+  color: white;
+  font-weight: 600;
+}
+
+.create-playlist {
+  width: 100%;
+  margin-top: 20px;
+  height: 40px;
+  border-radius: 0;
+  background: rgba(3, 169, 244, 1);
+  color: #fff !important;
+  border: 0;
+
+  &:active,
+  &:focus {
+    border: 0;
+  }
+}
+
+.create-playlist:focus {
+  background: #029ce3;
+}
+
+.none-found {
+  text-align: center;
+}
 </style>

+ 212 - 160
frontend/components/Sidebars/SongsList.vue

@@ -1,171 +1,223 @@
 <template>
-	<div class='sidebar' transition='slide' v-if='$parent.sidebars.songslist'>
-		<div class='inner-wrapper'>
-			<div class='title' v-if='$parent.type === "community"'>Queue</div>
-			<div class='title' v-else>Playlist</div>
-
-			<article class="media" v-if="!$parent.noSong">
-				<figure class="media-left" v-if="$parent.currentSong.thumbnail">
-					<p class="image is-64x64">
-						<img :src="$parent.currentSong.thumbnail" onerror="this.src='/assets/notes-transparent.png'">
-					</p>
-				</figure>
-				<div class="media-content">
-					<div class="content">
-						<p>
-							Current Song: <strong>{{ $parent.currentSong.title }}</strong>
-							<br>
-							<small>{{ $parent.currentSong.artists }}</small>
-						</p>
-					</div>
-				</div>
-				<div class="media-right">
-					{{ $parent.formatTime($parent.currentSong.duration) }}
-				</div>
-			</article>
-			<p v-if="$parent.noSong" class="center">There is currently no song playing.</p>
-
-			<article class="media" v-for='song in $parent.songsList'>
-				<div class="media-content">
-					<div class="content" style="display: block;padding-top: 10px;">
-							<strong class="songTitle">{{ song.title }}</strong>
-							<small>{{ song.artists.join(', ') }}</small>
-							<div v-if="this.$parent.$parent.type === 'community' && this.$parent.$parent.station.partyMode === true">
-								<small>Requested by <b>{{this.$parent.$parent.$parent.getUsernameFromId(song.requestedBy)}} {{this.userIdMap['Z' + song.requestedBy]}}</b></small>
-								<i class="material-icons" style="vertical-align: middle;" @click="removeFromQueue(song.songId)" v-if="isOwnerOnly() || isAdminOnly()">delete_forever</i>
-							</div>
-					</div>
-				</div>
-				<div class="media-right">
-					{{ $parent.$parent.formatTime(song.duration) }}
-				</div>
-			</article>
-			<div v-if="$parent.type === 'community' && $parent.$parent.loggedIn && $parent.station.partyMode === true">
-				<button class='button add-to-queue' @click='$parent.modals.addSongToQueue = !$parent.modals.addSongToQueue' v-if="($parent.station.locked && isOwnerOnly()) || !$parent.station.locked || ($parent.station.locked && isAdminOnly() && dismissedWarning)">Add Song to Queue</button>
-				<button class='button add-to-queue add-to-queue-warning' @click='dismissedWarning = true' v-if="$parent.station.locked && isAdminOnly() && !isOwnerOnly() && !dismissedWarning">THIS STATION'S QUEUE IS LOCKED.</button>
-				<button class='button add-to-queue add-to-queue-disabled' v-if="$parent.station.locked && !isAdminOnly() && !isOwnerOnly()">THIS STATION'S QUEUE IS LOCKED.</button>
-			</div>
-		</div>
-	</div>
+  <div class="sidebar" transition="slide">
+    <div class="inner-wrapper">
+      <div class="title" v-if="$parent.type === 'community'">Queue</div>
+      <div class="title" v-else>Playlist</div>
+
+      <article class="media" v-if="!$parent.noSong">
+        <figure class="media-left" v-if="$parent.currentSong.thumbnail">
+          <p class="image is-64x64">
+            <img
+              :src="$parent.currentSong.thumbnail"
+              onerror="this.src='/assets/notes-transparent.png'"
+            />
+          </p>
+        </figure>
+        <div class="media-content">
+          <div class="content">
+            <p>
+              Current Song:
+              <strong>{{ $parent.currentSong.title }}</strong>
+              <br />
+              <small>{{ $parent.currentSong.artists }}</small>
+            </p>
+          </div>
+        </div>
+        <div class="media-right">{{ $parent.formatTime($parent.currentSong.duration) }}</div>
+      </article>
+      <p v-if="$parent.noSong" class="center">There is currently no song playing.</p>
+
+      <article class="media" v-for="(song, index) in $parent.songsList" :key="index">
+        <div class="media-content">
+          <div class="content" style="display: block;padding-top: 10px;">
+            <strong class="songTitle">{{ song.title }}</strong>
+            <small>{{ song.artists.join(', ') }}</small>
+            <div v-if="$parent.type === 'community' && $parent.station.partyMode === true">
+              <small>
+                Requested by
+                <b>{{$parent.$parent.getUsernameFromId(song.requestedBy)}} {{userIdMap['Z' + song.requestedBy]}}</b>
+              </small>
+              <i
+                class="material-icons"
+                style="vertical-align: middle;"
+                v-on:click="removeFromQueue(song.songId)"
+                v-if="isOwnerOnly() || isAdminOnly()"
+              >delete_forever</i>
+            </div>
+          </div>
+        </div>
+        <div class="media-right">{{ $parent.formatTime(song.duration) }}</div>
+      </article>
+      <div
+        v-if="$parent.type === 'community' && $parent.$parent.loggedIn && $parent.station.partyMode === true"
+      >
+        <button
+          class="button add-to-queue"
+          v-on:click="toggleModal({ sector: 'station', modal: 'addSongToQueue' })"
+          v-if="($parent.station.locked && isOwnerOnly()) || !$parent.station.locked || ($parent.station.locked && isAdminOnly() && dismissedWarning)"
+        >Add Song to Queue</button>
+        <button
+          class="button add-to-queue add-to-queue-warning"
+          v-on:click="dismissedWarning = true"
+          v-if="$parent.station.locked && isAdminOnly() && !isOwnerOnly() && !dismissedWarning"
+        >THIS STATION'S QUEUE IS LOCKED.</button>
+        <button
+          class="button add-to-queue add-to-queue-disabled"
+          v-if="$parent.station.locked && !isAdminOnly() && !isOwnerOnly()"
+        >THIS STATION'S QUEUE IS LOCKED.</button>
+      </div>
+    </div>
+  </div>
 </template>
 
 <script>
-	import io from '../../io';
-	import { Toast } from 'vue-roaster';
-
-	export default {
-		data: function () {
-			return {
-				dismissedWarning: false,
-				userIdMap: this.$parent.$parent.userIdMap
-			}
-		},
-		methods: {
-			isOwnerOnly: function () {
-				return this.$parent.$parent.loggedIn && this.$parent.$parent.userId === this.$parent.station.owner;
-			},
-			isAdminOnly: function() {
-				return this.$parent.$parent.loggedIn && this.$parent.$parent.role === 'admin';
-			},
-			removeFromQueue: function(songId) {
-				socket.emit('stations.removeFromQueue', this.$parent.station._id, songId, res => {
-					if (res.status === 'success') {
-						Toast.methods.addToast('Successfully removed song from the queue.', 4000);
-					} else Toast.methods.addToast(res.message, 8000);
-				});
-			}
-		},
-		ready: function () {
-			/*let _this = this;
+import { mapActions } from "vuex";
+
+import io from "../../io";
+import { Toast } from "vue-roaster";
+
+export default {
+  data: function() {
+    return {
+      dismissedWarning: false,
+      userIdMap: this.$parent.$parent.userIdMap
+    };
+  },
+  methods: {
+    isOwnerOnly: function() {
+      return (
+        this.$parent.$parent.loggedIn &&
+        this.$parent.$parent.userId === this.$parent.station.owner
+      );
+    },
+    isAdminOnly: function() {
+      return (
+        this.$parent.$parent.loggedIn && this.$parent.$parent.role === "admin"
+      );
+    },
+    removeFromQueue: function(songId) {
+      socket.emit(
+        "stations.removeFromQueue",
+        this.$parent.station._id,
+        songId,
+        res => {
+          if (res.status === "success") {
+            Toast.methods.addToast(
+              "Successfully removed song from the queue.",
+              4000
+            );
+          } else Toast.methods.addToast(res.message, 8000);
+        }
+      );
+    },
+    ...mapActions("modals", ["toggleModal"])
+  },
+  mounted: function() {
+    /*let _this = this;
 			io.getSocket((socket) => {
 				_this.socket = socket;
 
 			});*/
-		}
-	}
+  }
+};
 </script>
 
-<style type='scss' scoped>
-	.sidebar {
-		position: fixed;
-		z-index: 1;
-		top: 0;
-		right: 0;
-		width: 300px;
-		height: 100vh;
-		background-color: #fff;
-		box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12);
-	}
-
-	.inner-wrapper {
-		top: 64px;
-		position: relative;
-		overflow: auto;
-		height: 100%;
-	}
-
-	.slide-transition {
-		transition: transform 0.6s ease-in-out;
-		transform: translateX(0);
-	}
-
-	.slide-enter, .slide-leave { transform: translateX(100%); }
-
-	.title {
-		background-color: rgb(3, 169, 244);
-		text-align: center;
-		padding: 10px;
-		color: white;
-		font-weight: 600;
-	}
-
-	.media { padding: 0 25px; }
-
-	.media-content .content {
-		min-height: 64px;
-		display: flex;
-		align-items: center;
-	}
-
-	.content p strong { word-break: break-word; }
-
-	.content p small { word-break: break-word; }
-
-	.add-to-queue {
-		width: 100%;
-		margin-top: 25px;
-		height: 40px;
-		border-radius: 0;
-		background: rgb(3, 169, 244);
-		color: #fff !important;
-		border: 0;
-		&:active, &:focus { border: 0; }
-	}
-
-	.add-to-queue.add-to-queue-warning {
-		background-color: red;
-	}
-
-	.add-to-queue.add-to-queue-disabled {
-		background-color: gray;
-	}
-	.add-to-queue.add-to-queue-disabled:focus {
-		background-color: gray;
-	}
-
-	.add-to-queue:focus { background: #029ce3; }
-
-	.media-right { line-height: 64px; }
-
-	.songTitle {
-		word-wrap: break-word;
-		overflow: hidden;
-		text-overflow: ellipsis;
-		display: -webkit-box;
-		-webkit-box-orient: vertical;
-		-webkit-line-clamp: 2;
-		line-height: 20px;
-		max-height: 40px;
-	}
-
+<style lang='scss' scoped>
+.sidebar {
+  position: fixed;
+  z-index: 1;
+  top: 0;
+  right: 0;
+  width: 300px;
+  height: 100vh;
+  background-color: #fff;
+  box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12);
+}
+
+.inner-wrapper {
+  top: 64px;
+  position: relative;
+  overflow: auto;
+  height: 100%;
+}
+
+.slide-transition {
+  transition: transform 0.6s ease-in-out;
+  transform: translateX(0);
+}
+
+.slide-enter,
+.slide-leave {
+  transform: translateX(100%);
+}
+
+.title {
+  background-color: rgb(3, 169, 244);
+  text-align: center;
+  padding: 10px;
+  color: white;
+  font-weight: 600;
+}
+
+.media {
+  padding: 0 25px;
+}
+
+.media-content .content {
+  min-height: 64px;
+  display: flex;
+  align-items: center;
+}
+
+.content p strong {
+  word-break: break-word;
+}
+
+.content p small {
+  word-break: break-word;
+}
+
+.add-to-queue {
+  width: 100%;
+  margin-top: 25px;
+  height: 40px;
+  border-radius: 0;
+  background: rgb(3, 169, 244);
+  color: #fff !important;
+  border: 0;
+  &:active,
+  &:focus {
+    border: 0;
+  }
+}
+
+.add-to-queue.add-to-queue-warning {
+  background-color: red;
+}
+
+.add-to-queue.add-to-queue-disabled {
+  background-color: gray;
+}
+.add-to-queue.add-to-queue-disabled:focus {
+  background-color: gray;
+}
+
+.add-to-queue:focus {
+  background: #029ce3;
+}
+
+.media-right {
+  line-height: 64px;
+}
+
+.songTitle {
+  word-wrap: break-word;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  display: -webkit-box;
+  -webkit-box-orient: vertical;
+  -webkit-line-clamp: 2;
+  line-height: 20px;
+  max-height: 40px;
+}
 </style>

+ 52 - 44
frontend/components/Sidebars/UsersList.vue

@@ -1,54 +1,62 @@
 <template>
-	<div class='sidebar' transition='slide' v-if='$parent.sidebars.users'>
-		<div class='inner-wrapper'>
-			<div class='title'>Users</div>
-			<h5 class="center">Total users: {{$parent.userCount}}</h5>
-			<aside class="menu">
-				<ul class="menu-list">
-					<li v-for="user in $parent.users">
-						<a href="#" v-link="{ path: '/u/' + user }" target="_blank">{{user}}</a>
-					</li>
-				</ul>
-			</aside>
-		</div>
-	</div>
+  <div class="sidebar" transition="slide">
+    <div class="inner-wrapper">
+      <div class="title">Users</div>
+      <h5 class="center">Total users: {{$parent.userCount}}</h5>
+      <aside class="menu">
+        <ul class="menu-list">
+          <li v-for="(username, index) in $parent.users" :key="index">
+            <router-link
+              :to="{ name: 'profile', params: { username } }"
+              target="_blank"
+            >{{username}}</router-link>
+          </li>
+        </ul>
+      </aside>
+    </div>
+  </div>
 </template>
 
-<style type='scss' scoped>
-	.sidebar {
-		position: fixed;
-		z-index: 1;
-		top: 0;
-		right: 0;
-		width: 300px;
-		height: 100vh;
-		background-color: #fff;
-		box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12);
-	}
+<style lang='scss' scoped>
+.sidebar {
+  position: fixed;
+  z-index: 1;
+  top: 0;
+  right: 0;
+  width: 300px;
+  height: 100vh;
+  background-color: #fff;
+  box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12);
+}
 
-	.inner-wrapper {
-		top: 64px;
-		position: relative;
-	}
+.inner-wrapper {
+  top: 64px;
+  position: relative;
+}
 
-	.slide-transition {
-		transition: transform 0.6s ease-in-out;
-		transform: translateX(0);
-	}
+.slide-transition {
+  transition: transform 0.6s ease-in-out;
+  transform: translateX(0);
+}
 
-	.slide-enter, .slide-leave {
-		transform: translateX(100%);
-	}
+.slide-enter,
+.slide-leave {
+  transform: translateX(100%);
+}
 
-	.title {
-		background-color: rgb(3, 169, 244);
-		text-align: center;
-		padding: 10px;
-		color: white;
-		font-weight: 600;
-	}
+.title {
+  background-color: rgb(3, 169, 244);
+  text-align: center;
+  padding: 10px;
+  color: white;
+  font-weight: 600;
+}
 
-	.menu { padding: 0 20px; }
+.menu {
+  padding: 0 20px;
+}
 
-	.menu-list li a:hover { color: #000 !important; }
+.menu-list li a:hover {
+  color: #000 !important;
+}
 </style>

+ 360 - 308
frontend/components/Station/CommunityHeader.vue

@@ -1,339 +1,391 @@
 <template>
-	<nav class='nav'>
-		<div class='nav-left'>
-			<a class='nav-item is-brand' href='#' v-link='{ path: "/" }' @click='this.$dispatch("leaveStation", title)'>
-				Musare
-			</a>
-		</div>
+  <div>
+    <nav class="nav">
+      <div class="nav-left">
+        <router-link
+          class="nav-item is-brand"
+          href="#"
+          :to="{ path: '/' }"
+          v-on:click="this.$dispatch('leaveStation', title)"
+        >Musare</router-link>
+      </div>
 
-		<div class='nav-center stationDisplayName'>
-			{{$parent.station.displayName}}
-		</div>
+      <div class="nav-center stationDisplayName">{{$parent.station.displayName}}</div>
 
-		<span class="nav-toggle" @click="controlBar = !controlBar">
-			<span></span>
-			<span></span>
-			<span></span>
-		</span>
+      <span class="nav-toggle" v-on:click="controlBar = !controlBar">
+        <span></span>
+        <span></span>
+        <span></span>
+      </span>
 
-		<div class="nav-right nav-menu" :class="{ 'is-active': isMobile }">
-			<a class="nav-item is-tab admin" href="#" v-link="{ path: '/admin' }" v-if="$parent.$parent.role === 'admin'">
-				<strong>Admin</strong>
-			</a>
-			<!--a class="nav-item is-tab" href="#">
-				About
-			</a-->
-			<a class="nav-item is-tab" href="#" v-link="{ path: '/team' }">
-				Team
-			</a>
-			<a class="nav-item is-tab" href="#" v-link="{ path: '/about' }">
-				About
-			</a>
-			<a class="nav-item is-tab" href="#" v-link="{ path: '/news' }">
-				News
-			</a>
-			<span class="grouped" v-if="$parent.$parent.loggedIn">
-				<a class="nav-item is-tab" href="#" v-link="{ path: '/u/' + $parent.$parent.username }">
-					Profile
-				</a>
-				<a class="nav-item is-tab" href="#" v-link="{ path: '/settings' }">
-					Settings
-				</a>
-				<a class="nav-item is-tab" href="#" @click="$parent.$parent.logout()">
-					Logout
-				</a>
-			</span>
-			<span class="grouped" v-else>
-				<a class="nav-item" href="#" @click="toggleModal('login')">
-					Login
-				</a>
-				<a class="nav-item" href="#" @click="toggleModal('register')">
-					Register
-				</a>
-			</span>
-		</div>
-
-	</nav>
-	<div class="control-sidebar" :class="{ 'show-controlBar': controlBar }">
-		<div class='inner-wrapper'>
-			<div v-if='isOwner()'>
-				<a class="sidebar-item" href='#' v-if='isOwner()' @click='$parent.editStation()'>
-					<span class='icon'>
-						<i class='material-icons'>settings</i>
-					</span>
-					<span class="icon-purpose">Station settings</span>
-				</a>
-				<a v-if='isOwner()' class="sidebar-item" href='#' @click='$parent.skipStation()'>
-					<span class='icon'>
-						<i class='material-icons'>skip_next</i>
-					</span>
-					<span class="icon-purpose">Skip current song</span>
-				</a>
-				<a class="sidebar-item" href='#' v-if='isOwner() && $parent.paused' @click='$parent.resumeStation()'>
-					<span class='icon'>
-						<i class='material-icons'>play_arrow</i>
-					</span>
-					<span class="icon-purpose">Resume station</span>
-				</a>
-				<a class="sidebar-item" href='#' v-if='isOwner() && !$parent.paused' @click='$parent.pauseStation()'>
-					<span class='icon'>
-						<i class='material-icons'>pause</i>
-					</span>
-					<span class="icon-purpose">Pause station</span>
-				</a>
-				<hr>
-			</div>
-			<div v-if="$parent.$parent.loggedIn && !$parent.noSong">
-				<a v-if='!isOwner() && $parent.$parent.loggedIn && !$parent.noSong' class="sidebar-item" href='#' @click='$parent.voteSkipStation()'>
-					<span class='icon'>
-						<i class='material-icons'>skip_next</i>
-					</span>
-					<span class="skip-votes">{{ $parent.currentSong.skipVotes }}</span>
-					<span class="icon-purpose">Skip current song</span>
-				</a>
-				<a v-if='$parent.$parent.loggedIn && !$parent.noSong' class="sidebar-item" href='#' @click='$parent.modals.addSongToPlaylist = true'>
-					<span class='icon'>
-						<i class='material-icons'>playlist_add</i>
-					</span>
-					<span class="icon-purpose">Add current song to playlist</span>
-				</a>
-				<hr>
-			</div>
-			<a class="sidebar-item" href='#' @click='$parent.toggleSidebar("songslist")' v-if='$parent.station.partyMode === true'>
-				<span class='icon'>
-					<i class='material-icons'>queue_music</i>
-				</span>
-				<span class="icon-purpose">Show the station queue</span>
-			</a>
-			<a class="sidebar-item" href='#' @click='$parent.toggleSidebar("users")'>
-				<span class='icon'>
-					<i class='material-icons'>people</i>
-				</span>
-				<span class="icon-purpose">Display users in the station</span>
-			</a>
-			<a class="sidebar-item" href='#' @click='$parent.toggleSidebar("playlist")' v-if='$parent.$parent.loggedIn'>
-				<span class='icon'>
-					<i class='material-icons'>library_music</i>
-				</span>
-				<span class="icon-purpose">Show your playlists</span>
-			</a>
-		</div>
-	</div>
+      <div class="nav-right nav-menu" :class="{ 'is-active': isMobile }">
+        <router-link
+          class="nav-item is-tab admin"
+          href="#"
+          :to="{ path: '/admin' }"
+          v-if="$parent.$parent.role === 'admin'"
+        >
+          <strong>Admin</strong>
+        </router-link>
+        <router-link class="nav-item is-tab" to="/team">Team</router-link>
+        <router-link class="nav-item is-tab" to="/about">About</router-link>
+        <router-link class="nav-item is-tab" to="/news">News</router-link>
+        <span class="grouped" v-if="$parent.$parent.loggedIn">
+          <router-link
+            class="nav-item is-tab"
+            :to="{ path: '/u/' + $parent.$parent.username }"
+          >Profile</router-link>
+          <router-link class="nav-item is-tab" to="/settings">Settings</router-link>
+          <a class="nav-item is-tab" href="#" v-on:click="$parent.$parent.logout()">Logout</a>
+        </span>
+        <span class="grouped" v-else>
+          <a
+            class="nav-item"
+            href="#"
+            v-on:click="toggleModal({ sector: 'header', modal: 'login' })"
+          >Login</a>
+          <a
+            class="nav-item"
+            href="#"
+            v-on:click="toggleModal({ sector: 'header', modal: 'register' })"
+          >Register</a>
+        </span>
+      </div>
+    </nav>
+    <div class="control-sidebar" :class="{ 'show-controlBar': controlBar }">
+      <div class="inner-wrapper">
+        <div v-if="isOwner()">
+          <a class="sidebar-item" href="#" v-if="isOwner()" v-on:click="settings()">
+            <span class="icon">
+              <i class="material-icons">settings</i>
+            </span>
+            <span class="icon-purpose">Station settings</span>
+          </a>
+          <a v-if="isOwner()" class="sidebar-item" href="#" v-on:click="$parent.skipStation()">
+            <span class="icon">
+              <i class="material-icons">skip_next</i>
+            </span>
+            <span class="icon-purpose">Skip current song</span>
+          </a>
+          <a
+            class="sidebar-item"
+            href="#"
+            v-if="isOwner() && $parent.paused"
+            v-on:click="$parent.resumeStation()"
+          >
+            <span class="icon">
+              <i class="material-icons">play_arrow</i>
+            </span>
+            <span class="icon-purpose">Resume station</span>
+          </a>
+          <a
+            class="sidebar-item"
+            href="#"
+            v-if="isOwner() && !$parent.paused"
+            v-on:click="$parent.pauseStation()"
+          >
+            <span class="icon">
+              <i class="material-icons">pause</i>
+            </span>
+            <span class="icon-purpose">Pause station</span>
+          </a>
+          <hr />
+        </div>
+        <div v-if="$parent.$parent.loggedIn && !$parent.noSong">
+          <a
+            v-if="!isOwner() && $parent.$parent.loggedIn && !$parent.noSong"
+            class="sidebar-item"
+            href="#"
+            v-on:click="$parent.voteSkipStation()"
+          >
+            <span class="icon">
+              <i class="material-icons">skip_next</i>
+            </span>
+            <span class="skip-votes">{{ $parent.currentSong.skipVotes }}</span>
+            <span class="icon-purpose">Skip current song</span>
+          </a>
+          <a
+            v-if="$parent.$parent.loggedIn && !$parent.noSong"
+            class="sidebar-item"
+            href="#"
+            v-on:click="toggleModal({
+              sector: 'station',
+              modal: 'addSongToPlaylist'
+            })"
+          >
+            <span class="icon">
+              <i class="material-icons">playlist_add</i>
+            </span>
+            <span class="icon-purpose">Add current song to playlist</span>
+          </a>
+          <hr />
+        </div>
+        <a
+          class="sidebar-item"
+          href="#"
+          v-on:click="$parent.toggleSidebar('songslist')"
+          v-if="$parent.station.partyMode === true"
+        >
+          <span class="icon">
+            <i class="material-icons">queue_music</i>
+          </span>
+          <span class="icon-purpose">Show the station queue</span>
+        </a>
+        <a class="sidebar-item" href="#" v-on:click="$parent.toggleSidebar('users')">
+          <span class="icon">
+            <i class="material-icons">people</i>
+          </span>
+          <span class="icon-purpose">Display users in the station</span>
+        </a>
+        <a
+          class="sidebar-item"
+          href="#"
+          v-on:click="$parent.toggleSidebar('playlist')"
+          v-if="$parent.$parent.loggedIn"
+        >
+          <span class="icon">
+            <i class="material-icons">library_music</i>
+          </span>
+          <span class="icon-purpose">Show your playlists</span>
+        </a>
+      </div>
+    </div>
+  </div>
 </template>
 
 <script>
-	export default {
-		data() {
-			return {
-				title: this.$route.params.id,
-				isMobile: false,
-				controlBar: true
-			}
-		},
-		methods: {
-			isOwner: function () {
-				return this.$parent.$parent.loggedIn && (this.$parent.$parent.role === 'admin' || this.$parent.$parent.userId === this.$parent.station.owner);
-			},
-			toggleModal: function (type) {
-				this.$dispatch('toggleModal', type);
-			}
-		}
-	}
+import { mapState, mapActions } from "vuex";
+
+export default {
+  data() {
+    return {
+      title: this.$route.params.id,
+      isMobile: false,
+      controlBar: true
+    };
+  },
+  methods: {
+    isOwner: function() {
+      return (
+        this.$parent.$parent.loggedIn &&
+        (this.$parent.$parent.role === "admin" ||
+          this.$parent.$parent.userId === this.$parent.station.owner)
+      );
+    },
+    settings() {
+      this.editStation({
+        _id: this.$parent.station._id,
+        name: this.$parent.station.name,
+        type: this.$parent.type,
+        partyMode: this.$parent.station.partyMode,
+        description: this.$parent.station.description,
+        privacy: this.$parent.station.privacy,
+        displayName: this.$parent.station.displayName
+      });
+      this.toggleModal({
+        sector: "station",
+        modal: "editStation"
+      });
+    },
+    ...mapActions("modals", ["toggleModal"]),
+    ...mapActions("station", ["editStation"])
+  }
+};
 </script>
 
 <style lang='scss' scoped>
-	.nav {
-		background-color: #03a9f4;
-		line-height: 64px;
+.nav {
+  background-color: #03a9f4;
+  line-height: 64px;
 
-		.is-brand {
-			font-size: 2.1rem !important;
-			line-height: 64px !important;
-			padding: 0 20px;
-		}
-	}
+  .is-brand {
+    font-size: 2.1rem !important;
+    line-height: 64px !important;
+    padding: 0 20px;
+  }
+}
 
-	a.nav-item {
-		color: hsl(0, 0%, 100%);
-		font-size: 15px;
+a.nav-item {
+  color: hsl(0, 0%, 100%);
+  font-size: 15px;
 
-		&:hover {
-			color: hsl(0, 0%, 100%);
-		}
+  &:hover {
+    color: hsl(0, 0%, 100%);
+  }
 
-		.admin {
-			color: #424242;
-		}
+  .admin {
+    color: #424242;
+  }
 
-		padding: 0 12px;
-		.icon {
-			height: 64px;
-			i {
-				font-size: 2rem;
-				line-height: 64px;
-				height: 64px;
-				width: 34px;
-			}
-		}
-	}
+  padding: 0 12px;
+  .icon {
+    height: 64px;
+    i {
+      font-size: 2rem;
+      line-height: 64px;
+      height: 64px;
+      width: 34px;
+    }
+  }
+}
 
-	.grouped {
-		margin: 0;
-		display: flex;
-		text-decoration: none;
-	}
+.grouped {
+  margin: 0;
+  display: flex;
+  text-decoration: none;
+}
 
-	.skip-votes {
-		position: relative;
-		left: 11px;
-	}
+.skip-votes {
+  position: relative;
+  left: 11px;
+}
 
-	.nav-toggle {
-		height: 64px;
-	}
+.nav-toggle {
+  height: 64px;
+}
 
-	@media screen and (max-width: 998px) {
-		.nav-menu {
-		    background-color: white;
-		    box-shadow: 0 4px 7px rgba(10, 10, 10, 0.1);
-		    left: 0;
-		    display: none;
-		    right: 0;
-		    top: 100%;
-		    position: absolute;
-		}
-		.nav-toggle {
-	    	display: block;
-		}
-	}
+@media screen and (max-width: 998px) {
+  .nav-menu {
+    background-color: white;
+    box-shadow: 0 4px 7px rgba(10, 10, 10, 0.1);
+    left: 0;
+    display: none;
+    right: 0;
+    top: 100%;
+    position: absolute;
+  }
+  .nav-toggle {
+    display: block;
+  }
+}
 
-	.logo {
-		font-size: 2.1rem;
-		line-height: 64px;
-		padding-left: 20px !important;
-		padding-right: 20px !important;
-	}
+.logo {
+  font-size: 2.1rem;
+  line-height: 64px;
+  padding-left: 20px !important;
+  padding-right: 20px !important;
+}
 
-	.nav-center {
-		display: flex;
-    align-items: center;
-		color: #03a9f4;
-		font-size: 22px;
-		position: absolute;
-		margin: auto;
-		top: 50%;
-		left: 50%;
-		transform: translate(-50%, -50%);
-	}
+.nav-center {
+  display: flex;
+  align-items: center;
+  color: #03a9f4;
+  font-size: 22px;
+  position: absolute;
+  margin: auto;
+  top: 50%;
+  left: 50%;
+  transform: translate(-50%, -50%);
+}
 
-	.nav-right.is-active .nav-item {
-		background: #03a9f4;
-    	border: 0;
-	}
+.nav-right.is-active .nav-item {
+  background: #03a9f4;
+  border: 0;
+}
 
-	.control-sidebar {
-		position: fixed;
-		z-index: 1;
-		top: 0;
-		left: 0;
-		width: 64px;
-		height: 100vh;
-		background-color: #03a9f4;
-		box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12);
+.control-sidebar {
+  position: fixed;
+  z-index: 1;
+  top: 0;
+  left: 0;
+  width: 64px;
+  height: 100vh;
+  background-color: #03a9f4;
+  box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12);
 
-		@media (max-width: 998px) {
-			display: none;
-		}
-		.inner-wrapper {
-			@media (min-width: 999px) {
-				.mobile-only {
-					display: none;
-				}
-				.desktop-only {
-					display: flex;
-				}
-			}
-			@media (max-width: 998px) {
-				.mobile-only {
-					display: flex;
-				}
-				.desktop-only {
-					display: none;
-					visibility: hidden;
-				}
-			}
-		}
-	}
+  @media (max-width: 998px) {
+    display: none;
+  }
+  .inner-wrapper {
+    @media (min-width: 999px) {
+      .mobile-only {
+        display: none;
+      }
+      .desktop-only {
+        display: flex;
+      }
+    }
+    @media (max-width: 998px) {
+      .mobile-only {
+        display: flex;
+      }
+      .desktop-only {
+        display: none;
+        visibility: hidden;
+      }
+    }
+  }
+}
 
-	.show-controlBar {
-		display: block;
-	}
+.show-controlBar {
+  display: block;
+}
 
-	.inner-wrapper {
-		top: 64px;
-		position: relative;
-	}
+.inner-wrapper {
+  top: 64px;
+  position: relative;
+}
 
-	.control-sidebar .material-icons {
-		width: 100%;
-		font-size: 2rem;
-	}
-	.control-sidebar .sidebar-item {
-		font-size: 2rem;
-		height: 50px;
-		color: white;
-		-webkit-box-align: center;
-		-ms-flex-align: center;
-		align-items: center;
-		display: -webkit-box;
-		display: -ms-flexbox;
-		display: flex;
-		-webkit-box-flex: 0;
-		-ms-flex-positive: 0;
-		flex-grow: 0;
-		-ms-flex-negative: 0;
-		flex-shrink: 0;
-		-webkit-box-pack: center;
-		-ms-flex-pack: center;
-		justify-content: center;
-		width: 100%;
-		position: relative;
-	}
-	.control-sidebar .sidebar-top-hr {
-		margin: 0 0 20px 0;
-	}
+.control-sidebar .material-icons {
+  width: 100%;
+  font-size: 2rem;
+}
+.control-sidebar .sidebar-item {
+  font-size: 2rem;
+  height: 50px;
+  color: white;
+  -webkit-box-align: center;
+  -ms-flex-align: center;
+  align-items: center;
+  display: -webkit-box;
+  display: -ms-flexbox;
+  display: flex;
+  -webkit-box-flex: 0;
+  -ms-flex-positive: 0;
+  flex-grow: 0;
+  -ms-flex-negative: 0;
+  flex-shrink: 0;
+  -webkit-box-pack: center;
+  -ms-flex-pack: center;
+  justify-content: center;
+  width: 100%;
+  position: relative;
+}
+.control-sidebar .sidebar-top-hr {
+  margin: 0 0 20px 0;
+}
 
-	.sidebar-item .icon-purpose {
-		visibility: hidden;
-		width: 160px;
-		font-size: 12px;
-		background-color: rgba(3, 169, 244, 0.8);
-		color: #fff;
-		text-align: center;
-		border-radius: 6px;
-		padding: 5px;
-		position: absolute;
-		z-index: 1;
-		left: 115%;
-		opacity: 0;
-    	transition: opacity 0.5s;
-		display: none;
-	}
+.sidebar-item .icon-purpose {
+  visibility: hidden;
+  width: 160px;
+  font-size: 12px;
+  background-color: rgba(3, 169, 244, 0.8);
+  color: #fff;
+  text-align: center;
+  border-radius: 6px;
+  padding: 5px;
+  position: absolute;
+  z-index: 1;
+  left: 115%;
+  opacity: 0;
+  transition: opacity 0.5s;
+  display: none;
+}
 
-	.sidebar-item .icon-purpose::after {
-		content: "";
-	    position: absolute;
-	    top: 50%;
-	    right: 100%;
-	    margin-top: -5px;
-	    border-width: 5px;
-	    border-style: solid;
-	    border-color: transparent rgba(3, 169, 244, 0.8) transparent transparent;
-	}
+.sidebar-item .icon-purpose::after {
+  content: "";
+  position: absolute;
+  top: 50%;
+  right: 100%;
+  margin-top: -5px;
+  border-width: 5px;
+  border-style: solid;
+  border-color: transparent rgba(3, 169, 244, 0.8) transparent transparent;
+}
 
-	.sidebar-item:hover .icon-purpose {
-		visibility: visible;
-		opacity: 1;
-		display: block;
-	}
+.sidebar-item:hover .icon-purpose {
+  visibility: visible;
+  opacity: 1;
+  display: block;
+}
 </style>

+ 373 - 317
frontend/components/Station/OfficialHeader.vue

@@ -1,349 +1,405 @@
 <template>
-	<nav class='nav'>
-		<div class='nav-left'>
-			<a class='nav-item is-brand' href='#' v-link='{ path: "/" }' @click='this.$dispatch("leaveStation", title)'>
-				Musare
-			</a>
-		</div>
+  <div>
+    <nav class="nav">
+      <div class="nav-left">
+        <router-link
+          class="nav-item is-brand"
+          to="/"
+          v-on:click="this.$dispatch('leaveStation', title)"
+        >Musare</router-link>
+      </div>
 
-		<div class='nav-center stationDisplayName'>
-			{{ $parent.station.displayName }}
-		</div>
+      <div class="nav-center stationDisplayName">{{ $parent.station.displayName }}</div>
 
-		<span class="nav-toggle" @click="controlBar = !controlBar">
-			<span></span>
-			<span></span>
-			<span></span>
-		</span>
+      <span class="nav-toggle" v-on:click="controlBar = !controlBar">
+        <span></span>
+        <span></span>
+        <span></span>
+      </span>
 
-		<div class="nav-right nav-menu" :class="{ 'is-active': isMobile }">
-			<a class="nav-item is-tab admin" href="#" v-link="{ path: '/admin' }" v-if="$parent.$parent.role === 'admin'">
-				<strong>Admin</strong>
-			</a>
-			<!--a class="nav-item is-tab" href="#">
-				About
-			</a-->
-			<a class="nav-item is-tab" href="#" v-link="{ path: '/team' }">
-				Team
-			</a>
-			<a class="nav-item is-tab" href="#" v-link="{ path: '/about' }">
-				About
-			</a>
-			<a class="nav-item is-tab" href="#" v-link="{ path: '/news' }">
-				News
-			</a>
-			<span class="grouped" v-if="$parent.$parent.loggedIn">
-				<a class="nav-item is-tab" href="#" v-link="{ path: '/u/' + $parent.$parent.username }">
-					Profile
-				</a>
-				<a class="nav-item is-tab" href="#" v-link="{ path: '/settings' }">
-					Settings
-				</a>
-				<a class="nav-item is-tab" href="#" @click="$parent.$parent.logout()">
-					Logout
-				</a>
-			</span>
-			<span class="grouped" v-else>
-				<a class="nav-item" href="#" @click="toggleModal('login')">
-					Login
-				</a>
-				<a class="nav-item" href="#" @click="toggleModal('register')">
-					Register
-				</a>
-			</span>
-		</div>
-
-	</nav>
-	<div class="control-sidebar" :class="{ 'show-controlBar': controlBar }">
-		<div class='inner-wrapper'>
-			<div v-if='isOwner()'>
-				<a class="sidebar-item" href='#' v-if='isOwner()' @click='$parent.editStation()'>
-					<span class='icon'>
-						<i class='material-icons'>settings</i>
-					</span>
-					<span class="icon-purpose">Station settings</span>
-				</a>
-				<a v-if='isOwner()' class="sidebar-item" href='#' @click='$parent.skipStation()'>
-					<span class='icon'>
-						<i class='material-icons'>skip_next</i>
-					</span>
-					<span class="icon-purpose">Skip current song</span>
-				</a>
-				<a class="sidebar-item" href='#' v-if='isOwner() && !$parent.paused' @click='$parent.pauseStation()'>
-					<span class='icon'>
-						<i class='material-icons'>pause</i>
-					</span>
-					<span class="icon-purpose">Pause station</span>
-				</a>
-				<a class="sidebar-item" href='#' v-if='isOwner() && $parent.paused' @click='$parent.resumeStation()'>
-					<span class='icon'>
-						<i class='material-icons'>play_arrow</i>
-					</span>
-					<span class="icon-purpose">Resume station</span>
-				</a>
-				<hr>
-			</div>
-			<div v-if="$parent.$parent.loggedIn">
-				<a class="sidebar-item" href='#' @click='$parent.modals.addSongToQueue = !$parent.modals.addSongToQueue' v-if='$parent.type === "official" && $parent.$parent.loggedIn'>
-					<span class='icon'>
-						<i class='material-icons'>queue</i>
-					</span>
-					<span class="icon-purpose">Add song to queue</span>
-				</a>
-				<a v-if='!isOwner() && $parent.$parent.loggedIn && !$parent.noSong' class="sidebar-item" href='#' @click='$parent.voteSkipStation()'>
-					<span class='icon'>
-						<i class='material-icons'>skip_next</i>
-					</span>
-					<span class="skip-votes">{{$parent.currentSong.skipVotes}}</span>
-					<span class="icon-purpose">Skip current song</span>
-				</a>
-				<a v-if='$parent.$parent.loggedIn && !$parent.noSong && !$parent.simpleSong' class="sidebar-item" href='#' @click='$parent.modals.report = !$parent.modals.report'>
-					<span class='icon'>
-						<i class='material-icons'>report</i>
-					</span>
-					<span class="icon-purpose">Report a song</span>
-				</a>
-				<a v-if='$parent.$parent.loggedIn && !$parent.noSong' class="sidebar-item" href='#' @click='$parent.modals.addSongToPlaylist = true'>
-					<span class='icon'>
-						<i class='material-icons'>playlist_add</i>
-					</span>
-					<span class="icon-purpose">Add current song to playlist</span>
-				</a>
-				<hr>
-			</div>
-			<a class="sidebar-item" href='#' @click='$parent.toggleSidebar("songslist")'>
-				<span class='icon'>
-					<i class='material-icons'>queue_music</i>
-				</span>
-				<span class="icon-purpose">Show the station queue</span>
-			</a>
-			<a class="sidebar-item" href='#' @click='$parent.toggleSidebar("users")'>
-				<span class='icon'>
-					<i class='material-icons'>people</i>
-				</span>
-				<span class="icon-purpose">Display users in the station</span>
-			</a>
-		</div>
-	</div>
+      <div class="nav-right nav-menu" :class="{ 'is-active': isMobile }">
+        <router-link
+          class="nav-item is-tab admin"
+          href="#"
+          to="admin"
+          v-if="$parent.$parent.role === 'admin'"
+        >
+          <strong>Admin</strong>
+        </router-link>
+        <router-link class="nav-item is-tab" to="/team">Team</router-link>
+        <router-link class="nav-item is-tab" to="/about">About</router-link>
+        <router-link class="nav-item is-tab" to="/news">News</router-link>
+        <span class="grouped" v-if="$parent.$parent.loggedIn">
+          <router-link
+            class="nav-item is-tab"
+            href="#"
+            :to="{ path: '/u/' + $parent.$parent.username }"
+          >Profile</router-link>
+          <router-link class="nav-item is-tab" to="/settings">Settings</router-link>
+          <a class="nav-item is-tab" v-on:click="$parent.$parent.logout()">Logout</a>
+        </span>
+        <span class="grouped" v-else>
+          <a
+            class="nav-item"
+            href="#"
+            v-on:click="toggleModal({ sector: 'header', modal: 'login' })"
+          >Login</a>
+          <a
+            class="nav-item"
+            href="#"
+            v-on:click="toggleModal({ sector: 'header', modal: 'register' })"
+          >Register</a>
+        </span>
+      </div>
+    </nav>
+    <div class="control-sidebar" :class="{ 'show-controlBar': controlBar }">
+      <div class="inner-wrapper">
+        <div v-if="isOwner()">
+          <a class="sidebar-item" href="#" v-if="isOwner()" v-on:click="settings()">
+            <span class="icon">
+              <i class="material-icons">settings</i>
+            </span>
+            <span class="icon-purpose">Station settings</span>
+          </a>
+          <a v-if="isOwner()" class="sidebar-item" href="#" v-on:click="$parent.skipStation()">
+            <span class="icon">
+              <i class="material-icons">skip_next</i>
+            </span>
+            <span class="icon-purpose">Skip current song</span>
+          </a>
+          <a
+            class="sidebar-item"
+            href="#"
+            v-if="isOwner() && !$parent.paused"
+            v-on:click="$parent.pauseStation()"
+          >
+            <span class="icon">
+              <i class="material-icons">pause</i>
+            </span>
+            <span class="icon-purpose">Pause station</span>
+          </a>
+          <a
+            class="sidebar-item"
+            href="#"
+            v-if="isOwner() && $parent.paused"
+            v-on:click="$parent.resumeStation()"
+          >
+            <span class="icon">
+              <i class="material-icons">play_arrow</i>
+            </span>
+            <span class="icon-purpose">Resume station</span>
+          </a>
+          <hr />
+        </div>
+        <div v-if="$parent.$parent.loggedIn">
+          <a
+            class="sidebar-item"
+            href="#"
+            v-on:click="toggleModal({
+              sector: 'station',
+              modal: 'addSongToQueue'
+            })"
+            v-if="$parent.type === 'official' && $parent.$parent.loggedIn"
+          >
+            <span class="icon">
+              <i class="material-icons">queue</i>
+            </span>
+            <span class="icon-purpose">Add song to queue</span>
+          </a>
+          <a
+            v-if="!isOwner() && $parent.$parent.loggedIn && !$parent.noSong"
+            class="sidebar-item"
+            href="#"
+            v-on:click="$parent.voteSkipStation()"
+          >
+            <span class="icon">
+              <i class="material-icons">skip_next</i>
+            </span>
+            <span class="skip-votes">{{$parent.currentSong.skipVotes}}</span>
+            <span class="icon-purpose">Skip current song</span>
+          </a>
+          <a
+            v-if="$parent.$parent.loggedIn && !$parent.noSong && !$parent.simpleSong"
+            class="sidebar-item"
+            href="#"
+            v-on:click="toggleModal({
+              sector: 'station',
+              modal: 'report'
+            })"
+          >
+            <span class="icon">
+              <i class="material-icons">report</i>
+            </span>
+            <span class="icon-purpose">Report a song</span>
+          </a>
+          <a
+            v-if="$parent.$parent.loggedIn && !$parent.noSong"
+            class="sidebar-item"
+            href="#"
+            v-on:click="toggleModal({
+              sector: 'station',
+              modal: 'addSongToPlaylist'
+            })"
+          >
+            <span class="icon">
+              <i class="material-icons">playlist_add</i>
+            </span>
+            <span class="icon-purpose">Add current song to playlist</span>
+          </a>
+          <hr />
+        </div>
+        <a class="sidebar-item" href="#" v-on:click="$parent.toggleSidebar('songslist')">
+          <span class="icon">
+            <i class="material-icons">queue_music</i>
+          </span>
+          <span class="icon-purpose">Show the station queue</span>
+        </a>
+        <a class="sidebar-item" href="#" v-on:click="$parent.toggleSidebar('users')">
+          <span class="icon">
+            <i class="material-icons">people</i>
+          </span>
+          <span class="icon-purpose">Display users in the station</span>
+        </a>
+      </div>
+    </div>
+  </div>
 </template>
 
 <script>
-	export default {
-		data() {
-			return {
-				title: this.$route.params.id,
-				isMobile: false,
-				controlBar: false
-			}
-		},
-		methods: {
-			isOwner: function () {
-				return this.$parent.$parent.loggedIn && this.$parent.$parent.role === 'admin';
-			},
-			toggleModal: function (type) {
-				this.$dispatch('toggleModal', type);
-			}
-		}
-	}
+import { mapState, mapActions } from "vuex";
+
+export default {
+  data() {
+    return {
+      title: this.$route.params.id,
+      isMobile: false,
+      controlBar: false
+    };
+  },
+  methods: {
+    isOwner: function() {
+      return (
+        this.$parent.$parent.loggedIn && this.$parent.$parent.role === "admin"
+      );
+    },
+    settings() {
+      this.editStation({
+        _id: this.$parent.station._id,
+        name: this.$parent.station.name,
+        type: this.$parent.type,
+        partyMode: this.$parent.station.partyMode,
+        description: this.$parent.station.description,
+        privacy: this.$parent.station.privacy,
+        displayName: this.$parent.station.displayName
+      });
+      this.toggleModal({
+        sector: "station",
+        modal: "editStation"
+      });
+    },
+    ...mapActions("modals", ["toggleModal"]),
+    ...mapActions("station", ["editStation"])
+  }
+};
 </script>
 
 <style lang='scss' scoped>
-	.nav {
-		background-color: #03a9f4;
-		line-height: 64px;
+.nav {
+  background-color: #03a9f4;
+  line-height: 64px;
 
-		.is-brand {
-			font-size: 2.1rem !important;
-			line-height: 64px !important;
-			padding: 0 20px;
-		}
-	}
+  .is-brand {
+    font-size: 2.1rem !important;
+    line-height: 64px !important;
+    padding: 0 20px;
+  }
+}
 
-	a.nav-item {
-		color: hsl(0, 0%, 100%);
-		font-size: 15px;
+a.nav-item {
+  color: hsl(0, 0%, 100%);
+  font-size: 15px;
 
-		&:hover {
-			color: hsl(0, 0%, 100%);
-		}
+  &:hover {
+    color: hsl(0, 0%, 100%);
+  }
 
-		.admin {
-			color: #424242;
-		}
+  .admin {
+    color: #424242;
+  }
 
-		padding: 0 12px;
-		.icon {
-			height: 64px;
-			i {
-				font-size: 2rem;
-				line-height: 64px;
-				height: 64px;
-				width: 34px;
-			}
-		}
-	}
+  padding: 0 12px;
+  .icon {
+    height: 64px;
+    i {
+      font-size: 2rem;
+      line-height: 64px;
+      height: 64px;
+      width: 34px;
+    }
+  }
+}
 
-	.grouped {
-		margin: 0;
-		display: flex;
-		text-decoration: none;
-	}
+.grouped {
+  margin: 0;
+  display: flex;
+  text-decoration: none;
+}
 
-	.skip-votes {
-		position: relative;
-		left: 11px;
-	}
+.skip-votes {
+  position: relative;
+  left: 11px;
+}
 
-	.nav-toggle {
-		height: 64px;
-	}
+.nav-toggle {
+  height: 64px;
+}
 
-	@media screen and (max-width: 998px) {
-		.nav-menu {
-		    background-color: white;
-		    box-shadow: 0 4px 7px rgba(10, 10, 10, 0.1);
-		    left: 0;
-		    display: none;
-		    right: 0;
-		    top: 100%;
-		    position: absolute;
-		}
-		.nav-toggle {
-	    	display: block;
-		}
-	}
+@media screen and (max-width: 998px) {
+  .nav-menu {
+    background-color: white;
+    box-shadow: 0 4px 7px rgba(10, 10, 10, 0.1);
+    left: 0;
+    display: none;
+    right: 0;
+    top: 100%;
+    position: absolute;
+  }
+  .nav-toggle {
+    display: block;
+  }
+}
 
-	.logo {
-		font-size: 2.1rem;
-		line-height: 64px;
-		padding-left: 20px !important;
-		padding-right: 20px !important;
-	}
+.logo {
+  font-size: 2.1rem;
+  line-height: 64px;
+  padding-left: 20px !important;
+  padding-right: 20px !important;
+}
 
-	.nav-center {
-		display: flex;
-    	align-items: center;
-		color: #03a9f4;
-		font-size: 22px;
-		position: absolute;
-		margin: auto;
-		top: 50%;
-		left: 50%;
-		transform: translate(-50%, -50%);
-	}
+.nav-center {
+  display: flex;
+  align-items: center;
+  color: #03a9f4;
+  font-size: 22px;
+  position: absolute;
+  margin: auto;
+  top: 50%;
+  left: 50%;
+  transform: translate(-50%, -50%);
+}
 
-	.nav-right.is-active .nav-item {
-		background: #03a9f4;
-    	border: 0;
-	}
+.nav-right.is-active .nav-item {
+  background: #03a9f4;
+  border: 0;
+}
 
-	.hidden {
-		display: none;
-	}
+.hidden {
+  display: none;
+}
 
-	.control-sidebar {
-		position: fixed;
-		z-index: 1;
-		top: 0;
-		left: 0;
-		width: 64px;
-		height: 100vh;
-		background-color: #03a9f4;
-		box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12);
+.control-sidebar {
+  position: fixed;
+  z-index: 1;
+  top: 0;
+  left: 0;
+  width: 64px;
+  height: 100vh;
+  background-color: #03a9f4;
+  box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12);
 
-		@media (max-width: 998px) {
-			display: none;
-		}
-		.inner-wrapper {
-			@media (min-width: 999px) {
-				.mobile-only {
-					display: none;
-				}
-				.desktop-only {
-					display: flex;
-				}
-			}
-			@media (max-width: 998px) {
-				.mobile-only {
-					display: flex;
-				}
-				.desktop-only {
-					display: none;
-					visibility: hidden;
-				}
-			}
-		}
-	}
+  @media (max-width: 998px) {
+    display: none;
+  }
+  .inner-wrapper {
+    @media (min-width: 999px) {
+      .mobile-only {
+        display: none;
+      }
+      .desktop-only {
+        display: flex;
+      }
+    }
+    @media (max-width: 998px) {
+      .mobile-only {
+        display: flex;
+      }
+      .desktop-only {
+        display: none;
+        visibility: hidden;
+      }
+    }
+  }
+}
 
-	.show-controlBar {
-		display: block;
-	}
+.show-controlBar {
+  display: block;
+}
 
-	.inner-wrapper {
-		top: 64px;
-		position: relative;
-	}
+.inner-wrapper {
+  top: 64px;
+  position: relative;
+}
 
-	.control-sidebar .material-icons {
-		width: 100%;
-		font-size: 2rem;
-	}
-	.control-sidebar .sidebar-item {
-		font-size: 2rem;
-		height: 50px;
-		color: white;
-		-webkit-box-align: center;
-	    -ms-flex-align: center;
-	    align-items: center;
-	    display: -webkit-box;
-	    display: -ms-flexbox;
-	    display: flex;
-	    -webkit-box-flex: 0;
-	    -ms-flex-positive: 0;
-	    flex-grow: 0;
-	    -ms-flex-negative: 0;
-	    flex-shrink: 0;
-	    -webkit-box-pack: center;
-	    -ms-flex-pack: center;
-	    justify-content: center;
-		width: 100%;
-		position: relative;
-	}
-	.control-sidebar .sidebar-top-hr {
-		margin: 0 0 20px 0;
-	}
+.control-sidebar .material-icons {
+  width: 100%;
+  font-size: 2rem;
+}
+.control-sidebar .sidebar-item {
+  font-size: 2rem;
+  height: 50px;
+  color: white;
+  -webkit-box-align: center;
+  -ms-flex-align: center;
+  align-items: center;
+  display: -webkit-box;
+  display: -ms-flexbox;
+  display: flex;
+  -webkit-box-flex: 0;
+  -ms-flex-positive: 0;
+  flex-grow: 0;
+  -ms-flex-negative: 0;
+  flex-shrink: 0;
+  -webkit-box-pack: center;
+  -ms-flex-pack: center;
+  justify-content: center;
+  width: 100%;
+  position: relative;
+}
+.control-sidebar .sidebar-top-hr {
+  margin: 0 0 20px 0;
+}
 
-	.sidebar-item .icon-purpose {
-		visibility: hidden;
-		width: 160px;
-		font-size: 12px;
-		background-color: rgba(3, 169, 244, 0.8);
-		color: #fff;
-		text-align: center;
-		border-radius: 6px;
-		padding: 5px;
-		position: absolute;
-		z-index: 1;
-		left: 115%;
-		opacity: 0;
-    	transition: opacity 0.5s;
-		display: none;
-	}
+.sidebar-item .icon-purpose {
+  visibility: hidden;
+  width: 160px;
+  font-size: 12px;
+  background-color: rgba(3, 169, 244, 0.8);
+  color: #fff;
+  text-align: center;
+  border-radius: 6px;
+  padding: 5px;
+  position: absolute;
+  z-index: 1;
+  left: 115%;
+  opacity: 0;
+  transition: opacity 0.5s;
+  display: none;
+}
 
-	.sidebar-item .icon-purpose::after {
-		content: "";
-	    position: absolute;
-	    top: 50%;
-	    right: 100%;
-	    margin-top: -5px;
-	    border-width: 5px;
-	    border-style: solid;
-	    border-color: transparent rgba(3, 169, 244, 0.8) transparent transparent;
-	}
+.sidebar-item .icon-purpose::after {
+  content: "";
+  position: absolute;
+  top: 50%;
+  right: 100%;
+  margin-top: -5px;
+  border-width: 5px;
+  border-style: solid;
+  border-color: transparent rgba(3, 169, 244, 0.8) transparent transparent;
+}
 
-	.sidebar-item:hover .icon-purpose {
-		visibility: visible;
-		opacity: 1;
-		display: block;
-	}
+.sidebar-item:hover .icon-purpose {
+  visibility: visible;
+  opacity: 1;
+  display: block;
+}
 </style>

+ 746 - 641
frontend/components/Station/Station.vue

@@ -1,163 +1,245 @@
 <template>
-	<official-header v-if='type == "official"'></official-header>
-	<community-header v-if='type == "community"'></community-header>
-
-	<song-queue v-if='modals.addSongToQueue'></song-queue>
-	<add-to-playlist v-if='modals.addSongToPlaylist'></add-to-playlist>
-	<edit-playlist v-if='modals.editPlaylist'></edit-playlist>
-	<create-playlist v-if='modals.createPlaylist'></create-playlist>
-	<edit-station v-show='modals.editStation'></edit-station>
-	<report v-if='modals.report'></report>
-
-	<songs-list-sidebar v-if='sidebars.songslist'></songs-list-sidebar>
-	<playlist-sidebar v-if='sidebars.playlist'></playlist-sidebar>
-	<users-sidebar v-if='sidebars.users'></users-sidebar>
-
-	<div class='progress' v-show='!ready'></div>
-	<div class='station' v-show="ready">
-		<div v-show="noSong" class="no-song">
-			<h1>No song is currently playing</h1>
-			<h4 v-if='type === "community" && station.partyMode && (!station.locked || (station.locked && $parent.loggedIn && $parent.userId === station.owner))'>
-				<a href='#' class='no-song' @click='modals.addSongToQueue = true'>Add a song to the queue</a>
-			</h4>
-			<h4 v-if='type === "community" && !station.partyMode && $parent.userId === station.owner && !station.privatePlaylist'>
-				<a href='#' class='no-song' @click='sidebars.playlist = true'>Play a private playlist</a>
-			</h4>
-			<h1 v-if='type === "community" && !station.partyMode && $parent.userId === station.owner && station.privatePlaylist'>Maybe you can add some songs to your selected private playlist and then press the skip button</h1>
-		</div>
-		<div class="columns" v-show="!noSong">
-			<div class="column is-8-desktop is-offset-2-desktop is-12-mobile">
-				<div class="video-container">
-					<div id="player"></div>
-				</div>
-				<div class="seeker-bar-container white" id="preview-progress">
-					<div class="seeker-bar light-blue" style="width: 0%;"></div>
-				</div>
-			</div>
-			<div class="desktop-only column is-3-desktop card playlistCard experimental">
-				<div class='title' v-if='type === "community"'>Queue</div>
-				<div class='title' v-else>Playlist</div>
-				<article class="media" v-if="!noSong">
-					<figure class="media-left">
-						<p class="image is-64x64">
-							<img :src="currentSong.thumbnail" onerror="this.src='/assets/notes-transparent.png'">
-						</p>
-					</figure>
-					<div class="media-content">
-						<div class="content">
-							<p>
-								Current Song:
-								<br>
-								<strong>{{ currentSong.title }}</strong>
-								<br>
-								<small>{{ currentSong.artists }}</small>
-							</p>
-						</div>
-					</div>
-					<div class="media-right">
-						{{ formatTime(currentSong.duration) }}
-					</div>
-				</article>
-				<p v-if="noSong" class="center">There is currently no song playing.</p>
-
-				<article class="media" v-for='song in songsList'>
-					<div class="media-content">
-						<div class="content">
-								<strong class="songTitle">{{ song.title }}</strong>
-								<br>
-								<small>{{ song.artists.join(', ') }}</small>
-								<br>
-								<div v-if="station.partyMode">
-									<br>
-									<small>Requested by <b>{{this.$parent.$parent.getUsernameFromId(song.requestedBy)}} {{this.userIdMap['Z' + song.requestedBy]}}</b></small>
-									<button class="button" @click="removeFromQueue(song.songId)" v-if="isOwnerOnly() || isAdminOnly()">REMOVE</button>
-								</div>
-						</div>
-					</div>
-					<div class="media-right">
-						{{ $parent.formatTime(song.duration) }}
-					</div>
-				</article>
-				<a class='button add-to-queue' href='#' @click='modals.addSongToQueue = !modals.addSongToQueue' v-if="type === 'community' && $parent.loggedIn">Add Song to Queue</a>
-			</div>
-		</div>
-		<div class="desktop-only columns is-mobile" v-show="!noSong">
-			<div class="column is-8-desktop is-offset-2-desktop is-12-mobile">
-				<div class="columns is-mobile">
-					<div class="column is-12-desktop">
-						<h4 id="time-display">{{timeElapsed}} / {{formatTime(currentSong.duration)}}</h4>
-						<h3>{{currentSong.title}}</h3>
-						<h4 class="thin" style="margin-left: 0">{{currentSong.artists}}</h4>
-						<div class="columns is-mobile">
-							<form style="margin-top: 12px; margin-bottom: 0;" action="#" class="column is-7-desktop is-4-mobile">
-								<p class='volume-slider-wrapper'>
-									<i class="material-icons" @click='toggleMute()' v-if='muted'>volume_mute</i>
-									<i class="material-icons" @click='toggleMute()' v-else>volume_down</i>
-									<input type="range" id="volumeSlider" min="0" max="10000" class="active" v-on:change="changeVolume()" v-on:input="changeVolume()">
-									<i class="material-icons" @click='increaseVolume()'>volume_up</i>
-								</p>
-							</form>
-							<div class="column is-8-mobile is-5-desktop" style="float: right;">
-								<ul id="ratings" v-if="currentSong.likes !== -1 && currentSong.dislikes !== -1">
-									<li id="like" class="right" @click="toggleLike()">
-										<span class="flow-text">{{currentSong.likes}} </span>
-										<i id="thumbs_up" class="material-icons grey-text" v-bind:class="{ liked: liked }">thumb_up</i>
-										<a class='absolute-a behind' @click="toggleLike()" href='#'></a>
-									</li>
-									<li style="margin-right: 10px;" id="dislike" class="right" @click="toggleDislike()">
-										<span class="flow-text">{{currentSong.dislikes}} </span>
-										<i id="thumbs_down" class="material-icons grey-text" v-bind:class="{ disliked: disliked }">thumb_down</i>
-										<a class='absolute-a behind' @click="toggleDislike()" href='#'></a>
-									</li>
-								</ul>
-							</div>
-						</div>
-					</div>
-					<div class="column is-3-desktop experimental" v-if="!simpleSong">
-						<img class="image" :src="currentSong.thumbnail" alt="Song Thumbnail" onerror="this.src='/assets/notes-transparent.png'" />
-					</div>
-				</div>
-			</div>
-		</div>
-		<div class="mobile-only" v-show="!noSong">
-			<div>
-				<div>
-					<div>
-						<h3>{{currentSong.title}}</h3>
-						<h4 class="thin">{{currentSong.artists}}</h4>
-						<h5>{{timeElapsed}} / {{formatTime(currentSong.duration)}}</h5>
-						<div>
-							<form class="columns" action="#">
-								<p class='column is-11-mobile volume-slider-wrapper'>
-									<i class="material-icons" @click='toggleMute()' v-if='muted'>volume_mute</i>
-									<i class="material-icons" @click='toggleMute()' v-else>volume_down</i>
-									<input type="range" id="volumeSlider" min="0" max="10000" class="active" v-on:change="changeVolume()" v-on:input="changeVolume()">
-									<i class="material-icons" @click='increaseVolume()'>volume_up</i>
-								</p>
-							</form>
-							<div>
-								<ul id="ratings" style="display: inline-block;" v-if="currentSong.likes !== -1 && currentSong.dislikes !== -1">
-									<li id="dislike" style="display: inline-block;margin-right: 10px;" @click="toggleDislike()">
-										<span class="flow-text">{{currentSong.dislikes}} </span>
-										<i id="thumbs_down" class="material-icons grey-text" v-bind:class="{ disliked: disliked }">thumb_down</i>
-										<a class='absolute-a behind' @click="toggleDislike()" href='#'></a>
-									</li>
-									<li id="like" style="display: inline-block;" @click="toggleLike()">
-										<span class="flow-text">{{currentSong.likes}} </span>
-										<i id="thumbs_up" class="material-icons grey-text" v-bind:class="{ liked: liked }">thumb_up</i>
-										<a class='absolute-a behind' @click="toggleLike()" href='#'></a>
-									</li>
-								</ul>
-							</div>
-						</div>
-					</div>
-				</div>
-			</div>
-		</div>
-	</div>
+  <div>
+    <official-header v-if="type == 'official'"></official-header>
+    <community-header v-if="type == 'community'"></community-header>
+
+    <song-queue v-if="modals.addSongToQueue"></song-queue>
+    <add-to-playlist v-if="modals.addSongToPlaylist"></add-to-playlist>
+    <edit-playlist v-if="modals.editPlaylist"></edit-playlist>
+    <create-playlist v-if="modals.createPlaylist"></create-playlist>
+    <edit-station v-show="modals.editStation"></edit-station>
+    <report v-if="modals.report"></report>
+
+    <songs-list-sidebar v-if="sidebars.songslist"></songs-list-sidebar>
+    <playlist-sidebar v-if="sidebars.playlist"></playlist-sidebar>
+    <users-sidebar v-if="sidebars.users"></users-sidebar>
+
+    <div class="progress" v-show="!ready"></div>
+    <div class="station" v-show="ready">
+      <div v-show="noSong" class="no-song">
+        <h1>No song is currently playing</h1>
+        <h4
+          v-if="type === 'community' && station.partyMode && (!station.locked || (station.locked && $parent.loggedIn && $parent.userId === station.owner))"
+        >
+          <a
+            href="#"
+            class="no-song"
+            v-on:click="toggleModal({ sector: 'station', modal: 'addSongToQueue' })"
+          >Add a song to the queue</a>
+        </h4>
+        <h4
+          v-if="type === 'community' && !station.partyMode && $parent.userId === station.owner && !station.privatePlaylist"
+        >
+          <a href="#" class="no-song" v-on:click="sidebars.playlist = true">Play a private playlist</a>
+        </h4>
+        <h1
+          v-if="type === 'community' && !station.partyMode && $parent.userId === station.owner && station.privatePlaylist"
+        >Maybe you can add some songs to your selected private playlist and then press the skip button</h1>
+      </div>
+      <div class="columns" v-show="!noSong">
+        <div class="column is-8-desktop is-offset-2-desktop is-12-mobile">
+          <div class="video-container">
+            <div id="player"></div>
+          </div>
+          <div class="seeker-bar-container white" id="preview-progress">
+            <div class="seeker-bar light-blue" style="width: 0%;"></div>
+          </div>
+        </div>
+        <div class="desktop-only column is-3-desktop card playlistCard experimental">
+          <div class="title" v-if="type === 'community'">Queue</div>
+          <div class="title" v-else>Playlist</div>
+          <article class="media" v-if="!noSong">
+            <figure class="media-left">
+              <p class="image is-64x64">
+                <img
+                  :src="currentSong.thumbnail"
+                  onerror="this.src='/assets/notes-transparent.png'"
+                />
+              </p>
+            </figure>
+            <div class="media-content">
+              <div class="content">
+                <p>
+                  Current Song:
+                  <br />
+                  <strong>{{ currentSong.title }}</strong>
+                  <br />
+                  <small>{{ currentSong.artists }}</small>
+                </p>
+              </div>
+            </div>
+            <div class="media-right">{{ formatTime(currentSong.duration) }}</div>
+          </article>
+          <p v-if="noSong" class="center">There is currently no song playing.</p>
+
+          <article class="media" v-for="(song, index) in songsList" :key="index">
+            <div class="media-content">
+              <div class="content">
+                <strong class="songTitle">{{ song.title }}</strong>
+                <br />
+                <small>{{ song.artists.join(', ') }}</small>
+                <br />
+                <div v-if="station.partyMode">
+                  <br />
+                  <small>
+                    Requested by
+                    <b>{{$parent.getUsernameFromId(song.requestedBy)}} {{userIdMap['Z' + song.requestedBy]}}</b>
+                  </small>
+                  <button
+                    class="button"
+                    v-on:click="removeFromQueue(song.songId)"
+                    v-if="isOwnerOnly() || isAdminOnly()"
+                  >REMOVE</button>
+                </div>
+              </div>
+            </div>
+            <div class="media-right">{{ formatTime(song.duration) }}</div>
+          </article>
+          <a
+            class="button add-to-queue"
+            href="#"
+            v-on:click="toggleModal({
+						sector: 'station',
+						modal: 'addSongToQueue'
+					})"
+            v-if="type === 'community' && $parent.loggedIn"
+          >Add Song to Queue</a>
+        </div>
+      </div>
+      <div class="desktop-only columns is-mobile" v-show="!noSong">
+        <div class="column is-8-desktop is-offset-2-desktop is-12-mobile">
+          <div class="columns is-mobile">
+            <div class="column is-12-desktop">
+              <h4 id="time-display">{{timeElapsed}} / {{formatTime(currentSong.duration)}}</h4>
+              <h3>{{currentSong.title}}</h3>
+              <h4 class="thin" style="margin-left: 0">{{currentSong.artists}}</h4>
+              <div class="columns is-mobile">
+                <form
+                  style="margin-top: 12px; margin-bottom: 0;"
+                  action="#"
+                  class="column is-7-desktop is-4-mobile"
+                >
+                  <p class="volume-slider-wrapper">
+                    <i class="material-icons" v-on:click="toggleMute()" v-if="muted">volume_mute</i>
+                    <i class="material-icons" v-on:click="toggleMute()" v-else>volume_down</i>
+                    <input
+                      type="range"
+                      id="volumeSlider"
+                      min="0"
+                      max="10000"
+                      class="active"
+                      v-on:change="changeVolume()"
+                      v-on:input="changeVolume()"
+                    />
+                    <i class="material-icons" v-on:click="increaseVolume()">volume_up</i>
+                  </p>
+                </form>
+                <div class="column is-8-mobile is-5-desktop" style="float: right;">
+                  <ul id="ratings" v-if="currentSong.likes !== -1 && currentSong.dislikes !== -1">
+                    <li id="like" class="right" v-on:click="toggleLike()">
+                      <span class="flow-text">{{currentSong.likes}}</span>
+                      <i
+                        id="thumbs_up"
+                        class="material-icons grey-text"
+                        v-bind:class="{ liked: liked }"
+                      >thumb_up</i>
+                      <a class="absolute-a behind" v-on:click="toggleLike()" href="#"></a>
+                    </li>
+                    <li
+                      style="margin-right: 10px;"
+                      id="dislike"
+                      class="right"
+                      v-on:click="toggleDislike()"
+                    >
+                      <span class="flow-text">{{currentSong.dislikes}}</span>
+                      <i
+                        id="thumbs_down"
+                        class="material-icons grey-text"
+                        v-bind:class="{ disliked: disliked }"
+                      >thumb_down</i>
+                      <a class="absolute-a behind" v-on:click="toggleDislike()" href="#"></a>
+                    </li>
+                  </ul>
+                </div>
+              </div>
+            </div>
+            <div class="column is-3-desktop experimental" v-if="!simpleSong">
+              <img
+                class="image"
+                :src="currentSong.thumbnail"
+                alt="Song Thumbnail"
+                onerror="this.src='/assets/notes-transparent.png'"
+              />
+            </div>
+          </div>
+        </div>
+      </div>
+      <div class="mobile-only" v-show="!noSong">
+        <div>
+          <div>
+            <div>
+              <h3>{{currentSong.title}}</h3>
+              <h4 class="thin">{{currentSong.artists}}</h4>
+              <h5>{{timeElapsed}} / {{formatTime(currentSong.duration)}}</h5>
+              <div>
+                <form class="columns" action="#">
+                  <p class="column is-11-mobile volume-slider-wrapper">
+                    <i class="material-icons" v-on:click="toggleMute()" v-if="muted">volume_mute</i>
+                    <i class="material-icons" v-on:click="toggleMute()" v-else>volume_down</i>
+                    <input
+                      type="range"
+                      id="volumeSlider"
+                      min="0"
+                      max="10000"
+                      class="active"
+                      v-on:change="changeVolume()"
+                      v-on:input="changeVolume()"
+                    />
+                    <i class="material-icons" v-on:click="increaseVolume()">volume_up</i>
+                  </p>
+                </form>
+                <div>
+                  <ul
+                    id="ratings"
+                    style="display: inline-block;"
+                    v-if="currentSong.likes !== -1 && currentSong.dislikes !== -1"
+                  >
+                    <li
+                      id="dislike"
+                      style="display: inline-block;margin-right: 10px;"
+                      v-on:click="toggleDislike()"
+                    >
+                      <span class="flow-text">{{currentSong.dislikes}}</span>
+                      <i
+                        id="thumbs_down"
+                        class="material-icons grey-text"
+                        v-bind:class="{ disliked: disliked }"
+                      >thumb_down</i>
+                      <a class="absolute-a behind" v-on:click="toggleDislike()" href="#"></a>
+                    </li>
+                    <li id="like" style="display: inline-block;" v-on:click="toggleLike()">
+                      <span class="flow-text">{{currentSong.likes}}</span>
+                      <i
+                        id="thumbs_up"
+                        class="material-icons grey-text"
+                        v-bind:class="{ liked: liked }"
+                      >thumb_up</i>
+                      <a class="absolute-a behind" v-on:click="toggleLike()" href="#"></a>
+                    </li>
+                  </ul>
+                </div>
+              </div>
+            </div>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
 </template>
 
 <script>
+	import { mapState, mapActions } from "vuex";
+
 	import { Toast } from 'vue-roaster';
 
 	import SongQueue from '../Modals/AddSongToQueue.vue';
@@ -192,14 +274,6 @@
 				timeElapsed: '0:00',
 				liked: false,
 				disliked: false,
-				modals: {
-					addSongToQueue: false,
-					addSongToPlaylist: false,
-					editPlaylist: false,
-					createPlaylist: false,
-					editStation: false,
-					report: false
-				},
 				sidebars: {
 					songslist: false,
 					users: false,
@@ -209,7 +283,6 @@
 				simpleSong: false,
 				songsList: [],
 				timeBeforePause: 0,
-				station: {},
 				skipVotes: 0,
 				privatePlaylistQueueSelected: null,
 				automaticallyRequestedSongId: null,
@@ -219,6 +292,14 @@
 				userIdMap: this.$parent.userIdMap
 			}
 		},
+		computed: {
+			...mapState("modals", {
+				modals: state => state.modals.station
+			}),
+			...mapState("station", {
+				station: state => state.station
+			})
+		},
 		methods: {
 			isOwnerOnly: function () {
 				return this.$parent.loggedIn && this.$parent.userId === this.station.owner;
@@ -233,22 +314,6 @@
 					} else Toast.methods.addToast(res.message, 8000);
 				});
 			},
-			editPlaylist: function (id) {
-				this.playlistBeingEdited = id;
-				this.modals.editPlaylist = !this.modals.editPlaylist;
-			},
-			editStation: function () {
-				let _this = this;
-				this.$broadcast('editStation', {
-					_id: _this.station._id,
-					name: _this.station.name,
-					type: _this.type,
-					partyMode: _this.station.partyMode,
-					description: _this.station.description,
-					privacy: _this.station.privacy,
-					displayName: _this.station.displayName
-				});
-			},
 			toggleSidebar: function (type) {
 				Object.keys(this.sidebars).forEach(sidebar => {
 					if (sidebar !== type) this.sidebars[sidebar] = false;
@@ -366,6 +431,7 @@
 				}
 			},
 			pauseLocalStation: function() {
+        console.log("pause locally");
 				this.paused = true;
 				if (!this.noSong) {
 					this.timeBeforePause = this.getTimeElapsed();
@@ -476,21 +542,22 @@
 					}
 				}
 			},
-			joinStation: function () {
+			join: function () {
 				let _this = this;
 				_this.socket.emit('stations.join', _this.stationName, res => {
 					if (res.status === 'success') {
-						_this.station = {
-							_id: res.data._id,
+						const { _id, displayName, description, privacy, locked, partyMode, owner, privatePlaylist } = res.data;
+						_this.joinStation({
+							_id,
 							name: _this.stationName,
-							displayName: res.data.displayName,
-							description: res.data.description,
-							privacy: res.data.privacy,
-							locked: res.data.locked,
-							partyMode: res.data.partyMode,
-							owner: res.data.owner,
-							privatePlaylist: res.data.privatePlaylist
-						};
+							displayName,
+							description,
+							privacy,
+							locked,
+							partyMode,
+							owner,
+							privatePlaylist
+						});
 						_this.currentSong = (res.data.currentSong) ? res.data.currentSong : {};
 						_this.type = res.data.type;
 						_this.startedAt = res.data.startedAt;
@@ -549,9 +616,11 @@
 						_this.systemDifference = difference;
 					});
 				});
-			}
+			},
+			...mapActions("modals", ["toggleModal"]),
+			...mapActions("station", ["joinStation"]),
 		},
-		ready: function() {
+		mounted: function() {
 			let _this = this;
 
 			Date.currently = () => {
@@ -566,10 +635,8 @@
 				_this.socket = socket;
 
 				io.removeAllListeners();
-				if (_this.socket.connected) _this.joinStation();
-				io.onConnect(() => {
-					_this.joinStation();
-				});
+				if (_this.socket.connected) _this.join();
+				io.onConnect(_this.join());
 				_this.socket.emit('stations.findByName', _this.stationName, res => {
 					if (res.status === 'error') {
 						_this.$router.go('/404');
@@ -611,18 +678,17 @@
 					}
 				});
 
-				_this.socket.on('event:stations.pause', data => {
-					_this.pauseLocalStation();
-				});
+				_this.socket.on('event:stations.pause', () => {
+          _this.pauseLocalStation();
+          console.log("local pause");
+        });
 
 				_this.socket.on('event:stations.resume', data => {
 					_this.timePaused = data.timePaused;
 					_this.resumeLocalStation();
 				});
 
-				_this.socket.on('event:stations.remove', () => {
-					location.href = '/';
-				});
+				_this.socket.on('event:stations.remove', () => location.href = '/');
 
 				_this.socket.on('event:song.like', data => {
 					if (!this.noSong) {
@@ -732,441 +798,480 @@
 </script>
 
 <style lang="scss">
-	.no-song {
-		color: #03A9F4;
-		text-align: center;
-	}
-
-	#volumeSlider {
-		padding: 0 15px;
-    	background: transparent;
-	}
-
-	.volume-slider-wrapper {
-		margin-top: 0;
-		position: relative;
-		display: flex;
-		align-items: center;
-		.material-icons { user-select: none; }
-	}
-
-	.material-icons { cursor: pointer; }
-
-	.stationDisplayName {
-		color: white !important;
-	}
-
-	.add-to-playlist {
-		display: flex;
-	    align-items: center;
-	    justify-content: center;
-	}
-
-	.slideout {
-		top: 50px;
-		height: 100%;
-		position: fixed;
-		right: 0;
-		width: 350px;
-		background-color: white;
-		box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12);
-		.slideout-header {
-			text-align: center;
-			background-color: rgb(3, 169, 244) !important;
-			margin: 0;
-			padding-top: 5px;
-			padding-bottom: 7px;
-			color: white;
-		}
-
-		.slideout-content {
-			height: 100%;
-		}
-	}
-
-	.modal-large {
-		width: 75%;
-	}
-
-	.station {
-		flex: 1 0 auto;
-		padding-top: 0.5vw;
-		transition: all 0.1s;
-		margin: 0 auto;
-		max-width: 100%;
-		width: 90%;
-
-		@media only screen and (min-width: 993px) {
-			width: 70%;
-		}
-
-		@media only screen and (min-width: 601px) {
-			width: 85%;
-		}
-
-		@media (min-width: 999px) {
-			.mobile-only {
-				display: none;
-			}
-			.desktop-only {
-				display: block;
-			}
-		}
-		@media (max-width: 998px) {
-			.mobile-only {
-				display: block;
-			}
-			.desktop-only {
-				display: none;
-				visibility: hidden;
-			}
-		}
-
-		.mobile-only {
-			text-align: center;
-		}
-
-		.playlistCard {
-			margin: 10px;
-			position: relative;
-			padding-bottom: calc(31.25% + 7px);
-			height: 0;
-			overflow-y: scroll;
-
-			.title {
-				background-color: rgb(3, 169, 244);
-				text-align: center;
-				padding: 10px;
-				color: white;
-				font-weight: 600;
-			}
-
-			.media { padding: 0 25px; }
-
-			.media-content .content {
-				min-height: 64px;
-				max-height: 64px;
-				display: flex;
-				align-items: center;
-			}
-
-			.content p strong { word-break: break-word; }
-
-			.content p small { word-break: break-word; }
-
-			.add-to-queue {
-				width: 100%;
-				margin-top: 25px;
-				height: 40px;
-				border-radius: 0;
-				background: rgb(3, 169, 244);
-				color: #fff !important;
-				border: 0;
-				&:active, &:focus { border: 0; }
-			}
-
-			.add-to-queue:focus { background: #029ce3; }
-
-			.media-right { line-height: 64px; }
-
-			.songTitle {
-				word-wrap: break-word;
-				overflow: hidden;
-				text-overflow: ellipsis;
-				display: -webkit-box;
-				-webkit-box-orient: vertical;
-				-webkit-line-clamp: 2;
-				line-height: 20px;
-				max-height: 40px;
-				width: 100%;
-			}
-
-		}
-
-		input[type=range] {
-			-webkit-appearance: none;
-			width: 100%;
-			margin: 7.3px 0;
-		}
-
-		input[type=range]:focus {
-			outline: none;
-		}
-
-		input[type=range]::-webkit-slider-runnable-track {
-			width: 100%;
-			height: 5.2px;
-			cursor: pointer;
-			box-shadow: 0;
-			background: #c2c0c2;
-			border-radius: 0;
-			border: 0;
-		}
-
-		input[type=range]::-webkit-slider-thumb {
-			box-shadow: 0;
-			border: 0;
-			height: 19px;
-			width: 19px;
-			border-radius: 15px;
-			background: #03a9f4;
-			cursor: pointer;
-			-webkit-appearance: none;
-			margin-top: -6.5px;
-		}
-
-		input[type=range]::-moz-range-track {
-			width: 100%;
-			height: 5.2px;
-			cursor: pointer;
-			box-shadow: 0;
-			background: #c2c0c2;
-			border-radius: 0;
-			border: 0;
-		}
-
-		input[type=range]::-moz-range-thumb {
-			box-shadow: 0;
-			border: 0;
-			height: 19px;
-			width: 19px;
-			border-radius: 15px;
-			background: #03a9f4;
-			cursor: pointer;
-			-webkit-appearance: none;
-			margin-top: -6.5px;
-		}
-
-		input[type=range]::-ms-track {
-			width: 100%;
-			height: 5.2px;
-			cursor: pointer;
-			box-shadow: 0;
-			background: #c2c0c2;
-			border-radius: 1.3px;
-		}
-
-		input[type=range]::-ms-fill-lower {
-			background: #c2c0c2;
-			border: 0;
-			border-radius: 0;
-			box-shadow: 0;
-		}
-
-		input[type=range]::-ms-fill-upper {
-			background: #c2c0c2;
-			border: 0;
-			border-radius: 0;
-			box-shadow: 0;
-		}
-
-		input[type=range]::-ms-thumb {
-			box-shadow: 0;
-			border: 0;
-			height: 15px;
-			width: 15px;
-			border-radius: 15px;
-			background: #03a9f4;
-			cursor: pointer;
-			-webkit-appearance: none;
-			margin-top: 1.5px;
-		}
-
-		.video-container {
-			position: relative;
-			padding-bottom: 56.25%;
-			height: 0;
-			overflow: hidden;
-
-			iframe {
-				position: absolute;
-				top: 0;
-				left: 0;
-				width: 100%;
-				height: 100%;
-			}
-		}
-		.video-col {
-			padding-right: 0.75rem;
-			padding-left: 0.75rem;
-		}
-	}
-
-	.room-title {
-		left: 50%;
-		-webkit-transform: translateX(-50%);
-		transform: translateX(-50%);
-		font-size: 2.1em;
-	}
-
-	#ratings {
-		span {
-			font-size: 1.68rem;
-		}
-
-		i {
-			color: #9e9e9e !important;
-			cursor: pointer;
-			transition: 0.1s color;
-		}
-	}
-
-	#time-display {
-		margin-top: 30px;
-		float: right;
-	}
-
-	#thumbs_up:hover, #thumbs_up.liked {
-		color: #87D37C !important;
-	}
-
-	#thumbs_down:hover, #thumbs_down.disliked {
-		color: #EC644B !important;
-	}
-
-	#song-thumbnail {
-		max-width: 100%;
-		width: 85%;
-	}
-
-	.seeker-bar-container {
-		position: relative;
-		height: 7px;
-		display: block;
-		width: 100%;
-		overflow: hidden;
-	}
-
-	.seeker-bar {
-		top: 0;
-		left: 0;
-		bottom: 0;
-		position: absolute;
-	}
-
-	ul {
-		list-style: none;
-		margin: 0;
-		display: block;
-	}
-
-	h1, h2, h3, h4, h5, h6 {
-		font-weight: 400;
-		line-height: 1.1;
-	}
-
-	h1 a, h2 a, h3 a, h4 a, h5 a, h6 a {
-		font-weight: inherit;
-	}
-
-	h1 {
-		font-size: 4.2rem;
-		line-height: 110%;
-		margin: 2.1rem 0 1.68rem 0;
-	}
-
-	h2 {
-		font-size: 3.56rem;
-		line-height: 110%;
-		margin: 1.78rem 0 1.424rem 0;
-	}
-
-	h3 {
-		font-size: 2.92rem;
-		line-height: 110%;
-		margin: 1.46rem 0 1.168rem 0;
-	}
-
-	h4 {
-		font-size: 2.28rem;
-		line-height: 110%;
-		margin: 1.14rem 0 0.912rem 0;
-	}
-
-	h5 {
-		font-size: 1.64rem;
-		line-height: 110%;
-		margin: 0.82rem 0 0.656rem 0;
-	}
-
-	h6 {
-		font-size: 1rem;
-		line-height: 110%;
-		margin: 0.5rem 0 0.4rem 0;
-	}
-
-	.thin {
-		font-weight: 200;
-	}
-
-	.left {
-		float: left !important;
-	}
-
-	.right {
-		float: right !important;
-	}
-
-	.light-blue {
-		background-color: #03a9f4 !important;
-	}
-
-	.white {
-		background-color: #FFFFFF !important;
-	}
-
-	.btn-search {
-		font-size: 14px;
-	}
-
-	.menu { padding: 0 10px; }
-
-	.menu-list li a:hover { color: #000 !important; }
-
-	.menu-list li {
-		display: flex;
-		justify-content: space-between;
-	}
-
-	.menu-list a {
-		/*padding: 0 10px !important;*/
-	}
-
-	.menu-list a:hover {
-		background-color : transparent;
-	}
-
-	.icons-group { display: flex; }
-
-	#like, #dislike {
-		position: relative;
-	}
-
-	.behind {
-		z-index: -1;
-	}
-
-	.behind:focus {
-		z-index: 0;
-	}
-
-	.progress {
-		width: 50px;
-		animation: rotate 0.8s infinite linear;
-		border: 8px solid #03a9f4;
-		border-right-color: transparent;
-		height: 50px;
-		position: absolute;
-		top: 50%;
-		left: 50%;
-	}
-
-	@keyframes rotate {
-		0% { transform: rotate(0deg); }
-		100% { transform: rotate(360deg); }
-	}
-
-	.experimental {
-		display: none !important;
-	}
+.no-song {
+  color: #03a9f4;
+  text-align: center;
+}
+
+#volumeSlider {
+  padding: 0 15px;
+  background: transparent;
+}
+
+.volume-slider-wrapper {
+  margin-top: 0;
+  position: relative;
+  display: flex;
+  align-items: center;
+  .material-icons {
+    user-select: none;
+  }
+}
+
+.material-icons {
+  cursor: pointer;
+}
+
+.stationDisplayName {
+  color: white !important;
+}
+
+.add-to-playlist {
+  display: flex;
+  align-items: center;
+  justify-content: center;
+}
+
+.slideout {
+  top: 50px;
+  height: 100%;
+  position: fixed;
+  right: 0;
+  width: 350px;
+  background-color: white;
+  box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.16), 0 2px 10px 0 rgba(0, 0, 0, 0.12);
+  .slideout-header {
+    text-align: center;
+    background-color: rgb(3, 169, 244) !important;
+    margin: 0;
+    padding-top: 5px;
+    padding-bottom: 7px;
+    color: white;
+  }
+
+  .slideout-content {
+    height: 100%;
+  }
+}
+
+.modal-large {
+  width: 75%;
+}
+
+.station {
+  flex: 1 0 auto;
+  padding-top: 0.5vw;
+  transition: all 0.1s;
+  margin: 0 auto;
+  max-width: 100%;
+  width: 90%;
+
+  @media only screen and (min-width: 993px) {
+    width: 70%;
+  }
+
+  @media only screen and (min-width: 601px) {
+    width: 85%;
+  }
+
+  @media (min-width: 999px) {
+    .mobile-only {
+      display: none;
+    }
+    .desktop-only {
+      display: block;
+    }
+  }
+  @media (max-width: 998px) {
+    .mobile-only {
+      display: block;
+    }
+    .desktop-only {
+      display: none;
+      visibility: hidden;
+    }
+  }
+
+  .mobile-only {
+    text-align: center;
+  }
+
+  .playlistCard {
+    margin: 10px;
+    position: relative;
+    padding-bottom: calc(31.25% + 7px);
+    height: 0;
+    overflow-y: scroll;
+
+    .title {
+      background-color: rgb(3, 169, 244);
+      text-align: center;
+      padding: 10px;
+      color: white;
+      font-weight: 600;
+    }
+
+    .media {
+      padding: 0 25px;
+    }
+
+    .media-content .content {
+      min-height: 64px;
+      max-height: 64px;
+      display: flex;
+      align-items: center;
+    }
+
+    .content p strong {
+      word-break: break-word;
+    }
+
+    .content p small {
+      word-break: break-word;
+    }
+
+    .add-to-queue {
+      width: 100%;
+      margin-top: 25px;
+      height: 40px;
+      border-radius: 0;
+      background: rgb(3, 169, 244);
+      color: #fff !important;
+      border: 0;
+      &:active,
+      &:focus {
+        border: 0;
+      }
+    }
+
+    .add-to-queue:focus {
+      background: #029ce3;
+    }
+
+    .media-right {
+      line-height: 64px;
+    }
+
+    .songTitle {
+      word-wrap: break-word;
+      overflow: hidden;
+      text-overflow: ellipsis;
+      display: -webkit-box;
+      -webkit-box-orient: vertical;
+      -webkit-line-clamp: 2;
+      line-height: 20px;
+      max-height: 40px;
+      width: 100%;
+    }
+  }
+
+  input[type="range"] {
+    -webkit-appearance: none;
+    width: 100%;
+    margin: 7.3px 0;
+  }
+
+  input[type="range"]:focus {
+    outline: none;
+  }
+
+  input[type="range"]::-webkit-slider-runnable-track {
+    width: 100%;
+    height: 5.2px;
+    cursor: pointer;
+    box-shadow: 0;
+    background: #c2c0c2;
+    border-radius: 0;
+    border: 0;
+  }
+
+  input[type="range"]::-webkit-slider-thumb {
+    box-shadow: 0;
+    border: 0;
+    height: 19px;
+    width: 19px;
+    border-radius: 15px;
+    background: #03a9f4;
+    cursor: pointer;
+    -webkit-appearance: none;
+    margin-top: -6.5px;
+  }
+
+  input[type="range"]::-moz-range-track {
+    width: 100%;
+    height: 5.2px;
+    cursor: pointer;
+    box-shadow: 0;
+    background: #c2c0c2;
+    border-radius: 0;
+    border: 0;
+  }
+
+  input[type="range"]::-moz-range-thumb {
+    box-shadow: 0;
+    border: 0;
+    height: 19px;
+    width: 19px;
+    border-radius: 15px;
+    background: #03a9f4;
+    cursor: pointer;
+    -webkit-appearance: none;
+    margin-top: -6.5px;
+  }
+
+  input[type="range"]::-ms-track {
+    width: 100%;
+    height: 5.2px;
+    cursor: pointer;
+    box-shadow: 0;
+    background: #c2c0c2;
+    border-radius: 1.3px;
+  }
+
+  input[type="range"]::-ms-fill-lower {
+    background: #c2c0c2;
+    border: 0;
+    border-radius: 0;
+    box-shadow: 0;
+  }
+
+  input[type="range"]::-ms-fill-upper {
+    background: #c2c0c2;
+    border: 0;
+    border-radius: 0;
+    box-shadow: 0;
+  }
+
+  input[type="range"]::-ms-thumb {
+    box-shadow: 0;
+    border: 0;
+    height: 15px;
+    width: 15px;
+    border-radius: 15px;
+    background: #03a9f4;
+    cursor: pointer;
+    -webkit-appearance: none;
+    margin-top: 1.5px;
+  }
+
+  .video-container {
+    position: relative;
+    padding-bottom: 56.25%;
+    height: 0;
+    overflow: hidden;
+
+    iframe {
+      position: absolute;
+      top: 0;
+      left: 0;
+      width: 100%;
+      height: 100%;
+    }
+  }
+  .video-col {
+    padding-right: 0.75rem;
+    padding-left: 0.75rem;
+  }
+}
+
+.room-title {
+  left: 50%;
+  -webkit-transform: translateX(-50%);
+  transform: translateX(-50%);
+  font-size: 2.1em;
+}
+
+#ratings {
+  span {
+    font-size: 1.68rem;
+  }
+
+  i {
+    color: #9e9e9e !important;
+    cursor: pointer;
+    transition: 0.1s color;
+  }
+}
+
+#time-display {
+  margin-top: 30px;
+  float: right;
+}
+
+#thumbs_up:hover,
+#thumbs_up.liked {
+  color: #87d37c !important;
+}
+
+#thumbs_down:hover,
+#thumbs_down.disliked {
+  color: #ec644b !important;
+}
+
+#song-thumbnail {
+  max-width: 100%;
+  width: 85%;
+}
+
+.seeker-bar-container {
+  position: relative;
+  height: 7px;
+  display: block;
+  width: 100%;
+  overflow: hidden;
+}
+
+.seeker-bar {
+  top: 0;
+  left: 0;
+  bottom: 0;
+  position: absolute;
+}
+
+ul {
+  list-style: none;
+  margin: 0;
+  display: block;
+}
+
+h1,
+h2,
+h3,
+h4,
+h5,
+h6 {
+  font-weight: 400;
+  line-height: 1.1;
+}
+
+h1 a,
+h2 a,
+h3 a,
+h4 a,
+h5 a,
+h6 a {
+  font-weight: inherit;
+}
+
+h1 {
+  font-size: 4.2rem;
+  line-height: 110%;
+  margin: 2.1rem 0 1.68rem 0;
+}
+
+h2 {
+  font-size: 3.56rem;
+  line-height: 110%;
+  margin: 1.78rem 0 1.424rem 0;
+}
+
+h3 {
+  font-size: 2.92rem;
+  line-height: 110%;
+  margin: 1.46rem 0 1.168rem 0;
+}
+
+h4 {
+  font-size: 2.28rem;
+  line-height: 110%;
+  margin: 1.14rem 0 0.912rem 0;
+}
+
+h5 {
+  font-size: 1.64rem;
+  line-height: 110%;
+  margin: 0.82rem 0 0.656rem 0;
+}
+
+h6 {
+  font-size: 1rem;
+  line-height: 110%;
+  margin: 0.5rem 0 0.4rem 0;
+}
+
+.thin {
+  font-weight: 200;
+}
+
+.left {
+  float: left !important;
+}
+
+.right {
+  float: right !important;
+}
+
+.light-blue {
+  background-color: #03a9f4 !important;
+}
+
+.white {
+  background-color: #ffffff !important;
+}
+
+.btn-search {
+  font-size: 14px;
+}
+
+.menu {
+  padding: 0 10px;
+}
+
+.menu-list li a:hover {
+  color: #000 !important;
+}
+
+.menu-list li {
+  display: flex;
+  justify-content: space-between;
+}
+
+.menu-list a {
+  /*padding: 0 10px !important;*/
+}
+
+.menu-list a:hover {
+  background-color: transparent;
+}
+
+.icons-group {
+  display: flex;
+}
+
+#like,
+#dislike {
+  position: relative;
+}
+
+.behind {
+  z-index: -1;
+}
+
+.behind:focus {
+  z-index: 0;
+}
+
+.progress {
+  width: 50px;
+  animation: rotate 0.8s infinite linear;
+  border: 8px solid #03a9f4;
+  border-right-color: transparent;
+  height: 50px;
+  position: absolute;
+  top: 50%;
+  left: 50%;
+}
+
+@keyframes rotate {
+  0% {
+    transform: rotate(0deg);
+  }
+  100% {
+    transform: rotate(360deg);
+  }
+}
+
+.experimental {
+  display: none !important;
+}
 </style>

+ 116 - 92
frontend/components/User/ResetPassword.vue

@@ -1,107 +1,131 @@
 <template>
-	<main-header></main-header>
-	<div class="container">
-		<!--Implement Validation-->
-		<h1>Step {{step}}</h1>
+  <div>
+    <main-header></main-header>
+    <div class="container">
+      <!--Implement Validation-->
+      <h1>Step {{step}}</h1>
 
-		<label class="label" v-if="step === 1">Email Address</label>
-		<div class="control is-grouped" v-if="step === 1">
-			<p class="control is-expanded has-icon has-icon-right">
-				<input class="input" type="email" placeholder="The email address associated with your account" v-model="email">
-			</p>
-			<p class="control">
-				<button class="button is-success" @click="submitEmail()">Request</button>
-				<button @click="step = 2" v-if="step === 1" class="button is-default skip-step">Skip this step</button>
-			</p>
-		</div>
+      <label class="label" v-if="step === 1">Email Address</label>
+      <div class="control is-grouped" v-if="step === 1">
+        <p class="control is-expanded has-icon has-icon-right">
+          <input
+            class="input"
+            type="email"
+            placeholder="The email address associated with your account"
+            v-model="email"
+          />
+        </p>
+        <p class="control">
+          <button class="button is-success" v-on:click="submitEmail()">Request</button>
+          <button
+            v-on:click="step = 2"
+            v-if="step === 1"
+            class="button is-default skip-step"
+          >Skip this step</button>
+        </p>
+      </div>
 
-		<label class="label" v-if="step === 2">Reset Code</label>
-		<div class="control is-grouped" v-if="step === 2">
-			<p class="control is-expanded has-icon has-icon-right">
-				<input class="input" type="text" placeholder="The reset code that was sent to your account's email address" v-model="code">
-			</p>
-			<p class="control">
-				<button class="button is-success" @click="verifyCode()">Verify reset code</button>
-			</p>
-		</div>
+      <label class="label" v-if="step === 2">Reset Code</label>
+      <div class="control is-grouped" v-if="step === 2">
+        <p class="control is-expanded has-icon has-icon-right">
+          <input
+            class="input"
+            type="text"
+            placeholder="The reset code that was sent to your account's email address"
+            v-model="code"
+          />
+        </p>
+        <p class="control">
+          <button class="button is-success" v-on:click="verifyCode()">Verify reset code</button>
+        </p>
+      </div>
 
-		<label class="label" v-if="step === 3">Change password</label>
-		<div class="control is-grouped" v-if="step === 3">
-			<p class="control is-expanded has-icon has-icon-right">
-				<input class="input" type="password" placeholder="New password" v-model="newPassword">
-			</p>
-			<p class="control">
-				<button class="button is-success" @click="changePassword()">Change password</button>
-			</p>
-		</div>
-	</div>
-	<main-footer></main-footer>
+      <label class="label" v-if="step === 3">Change password</label>
+      <div class="control is-grouped" v-if="step === 3">
+        <p class="control is-expanded has-icon has-icon-right">
+          <input class="input" type="password" placeholder="New password" v-model="newPassword" />
+        </p>
+        <p class="control">
+          <button class="button is-success" v-on:click="changePassword()">Change password</button>
+        </p>
+      </div>
+    </div>
+    <main-footer></main-footer>
+  </div>
 </template>
 
 <script>
-	import { Toast } from 'vue-roaster';
+import { Toast } from "vue-roaster";
 
-	import MainHeader from '../MainHeader.vue';
-	import MainFooter from '../MainFooter.vue';
+import MainHeader from "../MainHeader.vue";
+import MainFooter from "../MainFooter.vue";
 
-	import LoginModal from '../Modals/Login.vue'
-	import io from '../../io'
+import LoginModal from "../Modals/Login.vue";
+import io from "../../io";
 
-	export default {
-		data() {
-			return {
-				email: '',
-				code: '',
-				newPassword: '',
-				step: 1
-			}
-		},
-		ready: function() {
-			let _this = this;
-			io.getSocket((socket) => {
-				_this.socket = socket;
-			});
-		},
-		methods: {
-			submitEmail: function () {
-				if (!this.email) return Toast.methods.addToast('Email cannot be empty', 8000);
-				this.socket.emit('users.requestPasswordReset', this.email, res => {
-					Toast.methods.addToast(res.message, 8000);
-					if (res.status === 'success') {
-						this.step = 2;
-					}
-				});
-			},
-			verifyCode: function () {
-				if (!this.code) return Toast.methods.addToast('Code cannot be empty', 8000);
-				this.socket.emit('users.verifyPasswordResetCode', this.code, res => {
-					Toast.methods.addToast(res.message, 8000);
-					if (res.status === 'success') {
-						this.step = 3;
-					}
-				});
-			},
-			changePassword: function () {
-				if (!this.newPassword) return Toast.methods.addToast('Password cannot be empty', 8000);
-				this.socket.emit('users.changePasswordWithResetCode', this.code, this.newPassword, res => {
-					Toast.methods.addToast(res.message, 8000);
-					if (res.status === 'success') {
-						this.$router.go('/login');
-					}
-				});
-			}
-		},
-		components: { MainHeader, MainFooter, LoginModal }
-	}
+export default {
+  data() {
+    return {
+      email: "",
+      code: "",
+      newPassword: "",
+      step: 1
+    };
+  },
+  mounted: function() {
+    let _this = this;
+    io.getSocket(socket => {
+      _this.socket = socket;
+    });
+  },
+  methods: {
+    submitEmail: function() {
+      if (!this.email)
+        return Toast.methods.addToast("Email cannot be empty", 8000);
+      this.socket.emit("users.requestPasswordReset", this.email, res => {
+        Toast.methods.addToast(res.message, 8000);
+        if (res.status === "success") {
+          this.step = 2;
+        }
+      });
+    },
+    verifyCode: function() {
+      if (!this.code)
+        return Toast.methods.addToast("Code cannot be empty", 8000);
+      this.socket.emit("users.verifyPasswordResetCode", this.code, res => {
+        Toast.methods.addToast(res.message, 8000);
+        if (res.status === "success") {
+          this.step = 3;
+        }
+      });
+    },
+    changePassword: function() {
+      if (!this.newPassword)
+        return Toast.methods.addToast("Password cannot be empty", 8000);
+      this.socket.emit(
+        "users.changePasswordWithResetCode",
+        this.code,
+        this.newPassword,
+        res => {
+          Toast.methods.addToast(res.message, 8000);
+          if (res.status === "success") {
+            this.$router.go("/login");
+          }
+        }
+      );
+    }
+  },
+  components: { MainHeader, MainFooter, LoginModal }
+};
 </script>
 
 <style lang="scss" scoped>
-	.container {
-		padding: 25px;
-	}
+.container {
+  padding: 25px;
+}
 
-	.skip-step {
-		background-color: #7e7e7e;
-		color: #fff;
-	}
+.skip-step {
+  background-color: #7e7e7e;
+  color: #fff;
+}
 </style>

+ 275 - 202
frontend/components/User/Settings.vue

@@ -1,211 +1,284 @@
 <template>
-	<main-header></main-header>
-	<div class="container">
-		<!--Implement Validation-->
-		<label class="label">Username</label>
-		<div class="control is-grouped">
-			<p class="control is-expanded has-icon has-icon-right">
-				<input class="input" type="text" placeholder="Change username" v-model="user.username">
-				<!--Remove validation if it's their own without changing-->
-			</p>
-			<p class="control">
-				<button class="button is-success" @click="changeUsername()">Save changes</button>
-			</p>
-		</div>
-		<label class="label">Email</label>
-		<div class="control is-grouped" v-if="user.email">
-			<p class="control is-expanded has-icon has-icon-right">
-				<input class="input" type="text" placeholder="Change email address" v-model="user.email.address">
-				<!--Remove validation if it's their own without changing-->
-			</p>
-			<p class="control is-expanded">
-				<button class="button is-success" @click="changeEmail()">Save changes</button>
-			</p>
-		</div>
-		<label class="label" v-if="password">Change Password</label>
-		<div class="control is-grouped" v-if="password">
-			<p class="control is-expanded has-icon has-icon-right">
-				<input class="input" type="password" placeholder="Change password" v-model="newPassword">
-			</p>
-			<p class="control is-expanded">
-				<button class="button is-success" @click="changePassword()">Change password</button>
-			</p>
-		</div>
-
-		<label class="label" v-if="!password">Add password</label>
-		<div class="control is-grouped" v-if="!password">
-			<button class="button is-success" @click="requestPassword()" v-if="passwordStep === 1">Request password email</button><br>
-
-			<p class="control is-expanded has-icon has-icon-right" v-if="passwordStep === 2">
-				<input class="input" type="text" placeholder="Code" v-model="passwordCode">
-			</p>
-			<p class="control is-expanded" v-if="passwordStep === 2">
-				<button class="button is-success" @click="verifyCode()">Verify code</button>
-			</p>
-
-			<p class="control is-expanded has-icon has-icon-right" v-if="passwordStep === 3">
-				<input class="input" type="password" placeholder="New password" v-model="setNewPassword">
-			</p>
-			<p class="control is-expanded" v-if="passwordStep === 3">
-				<button class="button is-success" @click="setPassword()">Set password</button>
-			</p>
-		</div>
-		<a href="#" v-if="passwordStep === 1 && !password" @click="passwordStep = 2">Skip this step</a>
-
-		<a class="button is-github" v-if="!github" :href='$parent.serverDomain + "/auth/github/link"'>
-			<div class='icon'>
-				<img class='invert' src='/assets/social/github.svg'/>
-			</div>
-			&nbsp; Link GitHub to account
-		</a>
-
-		<button class="button is-danger" @click="unlinkPassword()" v-if="password && github">Remove logging in with password</button>
-		<button class="button is-danger" @click="unlinkGitHub()" v-if="password && github">Remove logging in with GitHub</button>
-
-		<br>
-		<button class="button is-warning" @click="removeSessions()" style="margin-top: 30px;">Log out everywhere</button>
-	</div>
-	<main-footer></main-footer>
+  <div>
+    <main-header></main-header>
+    <div class="container">
+      <!--Implement Validation-->
+      <label class="label">Username</label>
+      <div class="control is-grouped">
+        <p class="control is-expanded has-icon has-icon-right">
+          <input class="input" type="text" placeholder="Change username" v-model="user.username" />
+          <!--Remove validation if it's their own without changing-->
+        </p>
+        <p class="control">
+          <button class="button is-success" v-on:click="changeUsername()">Save changes</button>
+        </p>
+      </div>
+      <label class="label">Email</label>
+      <div class="control is-grouped" v-if="user.email">
+        <p class="control is-expanded has-icon has-icon-right">
+          <input
+            class="input"
+            type="text"
+            placeholder="Change email address"
+            v-model="user.email.address"
+          />
+          <!--Remove validation if it's their own without changing-->
+        </p>
+        <p class="control is-expanded">
+          <button class="button is-success" v-on:click="changeEmail()">Save changes</button>
+        </p>
+      </div>
+      <label class="label" v-if="password">Change Password</label>
+      <div class="control is-grouped" v-if="password">
+        <p class="control is-expanded has-icon has-icon-right">
+          <input class="input" type="password" placeholder="Change password" v-model="newPassword" />
+        </p>
+        <p class="control is-expanded">
+          <button class="button is-success" v-on:click="changePassword()">Change password</button>
+        </p>
+      </div>
+
+      <label class="label" v-if="!password">Add password</label>
+      <div class="control is-grouped" v-if="!password">
+        <button
+          class="button is-success"
+          v-on:click="requestPassword()"
+          v-if="passwordStep === 1"
+        >Request password email</button>
+        <br />
+
+        <p class="control is-expanded has-icon has-icon-right" v-if="passwordStep === 2">
+          <input class="input" type="text" placeholder="Code" v-model="passwordCode" />
+        </p>
+        <p class="control is-expanded" v-if="passwordStep === 2">
+          <button class="button is-success" v-on:click="verifyCode()">Verify code</button>
+        </p>
+
+        <p class="control is-expanded has-icon has-icon-right" v-if="passwordStep === 3">
+          <input class="input" type="password" placeholder="New password" v-model="setNewPassword" />
+        </p>
+        <p class="control is-expanded" v-if="passwordStep === 3">
+          <button class="button is-success" v-on:click="setPassword()">Set password</button>
+        </p>
+      </div>
+      <a
+        href="#"
+        v-if="passwordStep === 1 && !password"
+        v-on:click="passwordStep = 2"
+      >Skip this step</a>
+
+      <a
+        class="button is-github"
+        v-if="!github"
+        :href="`http://${$parent.serverDomain}/auth/github/link`"
+      >
+        <div class="icon">
+          <img class="invert" src="/assets/social/github.svg" />
+        </div>&nbsp; Link GitHub to account
+      </a>
+
+      <button
+        class="button is-danger"
+        v-on:click="unlinkPassword()"
+        v-if="password && github"
+      >Remove logging in with password</button>
+      <button
+        class="button is-danger"
+        v-on:click="unlinkGitHub()"
+        v-if="password && github"
+      >Remove logging in with GitHub</button>
+
+      <br />
+      <button
+        class="button is-warning"
+        v-on:click="removeSessions()"
+        style="margin-top: 30px;"
+      >Log out everywhere</button>
+    </div>
+    <main-footer></main-footer>
+  </div>
 </template>
 
 <script>
-	import { Toast } from 'vue-roaster';
-
-	import MainHeader from '../MainHeader.vue';
-	import MainFooter from '../MainFooter.vue';
-
-	import LoginModal from '../Modals/Login.vue'
-	import io from '../../io'
-	import validation from '../../validation';
-
-	export default {
-		data() {
-			return {
-				user: {},
-				newPassword: '',
-				password: false,
-				github: false,
-				setNewPassword: '',
-				passwordStep: 1,
-				passwordCode: ''
-			}
-		},
-		ready: function() {
-			let _this = this;
-			io.getSocket(socket => {
-				_this.socket = socket;
-				_this.socket.emit('users.findBySession', res => {
-					if (res.status == 'success') {
-						_this.user = res.data;
-						_this.password = _this.user.password;
-						_this.github = _this.user.github;
-					} else {
-						_this.$parent.isLoginActive = true;
-						Toast.methods.addToast('Your are currently not signed in', 3000);
-					}
-				});
-				_this.socket.on('event:user.username.changed', username => {
-					_this.$parent.username = username;
-				});
-				_this.socket.on('event:user.linkPassword', () => {
-					_this.password = true;
-				});
-				_this.socket.on('event:user.linkGitHub', () => {
-					_this.github = true;
-				});
-				_this.socket.on('event:user.unlinkPassword', () => {
-					_this.password = false;
-				});
-				_this.socket.on('event:user.unlinkGitHub', () => {
-					_this.github = false;
-				});
-			});
-		},
-		methods: {
-			changeEmail: function () {
-				const email = this.user.email.address;
-				if (!validation.isLength(email, 3, 254)) return Toast.methods.addToast('Email must have between 3 and 254 characters.', 8000);
-				if (email.indexOf('@') !== email.lastIndexOf('@') || !validation.regex.emailSimple.test(email)) return Toast.methods.addToast('Invalid email format.', 8000);
-
-
-				this.socket.emit('users.updateEmail', this.$parent.userId, email, res => {
-					if (res.status !== 'success') Toast.methods.addToast(res.message, 8000);
-					else Toast.methods.addToast('Successfully changed email address', 4000);
-				});
-			},
-			changeUsername: function () {
-				const username = this.user.username;
-				if (!validation.isLength(username, 2, 32)) return Toast.methods.addToast('Username must have between 2 and 32 characters.', 8000);
-				if (!validation.regex.azAZ09_.test(username)) return Toast.methods.addToast('Invalid username format. Allowed characters: a-z, A-Z, 0-9 and _.', 8000);
-
-
-				this.socket.emit('users.updateUsername', this.$parent.userId, username, res => {
-					if (res.status !== 'success') Toast.methods.addToast(res.message, 8000);
-					else Toast.methods.addToast('Successfully changed username', 4000);
-				});
-			},
-			changePassword: function () {
-				const newPassword = this.newPassword;
-				if (!validation.isLength(newPassword, 6, 200)) return Toast.methods.addToast('Password must have between 6 and 200 characters.', 8000);
-				if (!validation.regex.password.test(newPassword)) return Toast.methods.addToast('Invalid password format. Must have one lowercase letter, one uppercase letter, one number and one special character.', 8000);
-
-
-				this.socket.emit('users.updatePassword', newPassword, res => {
-					if (res.status !== 'success') Toast.methods.addToast(res.message, 8000);
-					else Toast.methods.addToast('Successfully changed password', 4000);
-				});
-			},
-			requestPassword: function() {
-				this.socket.emit('users.requestPassword', res => {
-					Toast.methods.addToast(res.message, 8000);
-					if (res.status === 'success') {
-						this.passwordStep = 2;
-					}
-				});
-			},
-			verifyCode: function () {
-				if (!this.passwordCode) return Toast.methods.addToast('Code cannot be empty', 8000);
-				this.socket.emit('users.verifyPasswordCode', this.passwordCode, res => {
-					Toast.methods.addToast(res.message, 8000);
-					if (res.status === 'success') {
-						this.passwordStep = 3;
-					}
-				});
-			},
-			setPassword: function () {
-				const newPassword = this.setNewPassword;
-				if (!validation.isLength(newPassword, 6, 200)) return Toast.methods.addToast('Password must have between 6 and 200 characters.', 8000);
-				if (!validation.regex.password.test(newPassword)) return Toast.methods.addToast('Invalid password format. Must have one lowercase letter, one uppercase letter, one number and one special character.', 8000);
-
-
-				this.socket.emit('users.changePasswordWithCode', this.passwordCode, newPassword, res => {
-					Toast.methods.addToast(res.message, 8000);
-				});
-			},
-			unlinkPassword: function () {
-				this.socket.emit('users.unlinkPassword', res => {
-					Toast.methods.addToast(res.message, 8000);
-				});
-			},
-			unlinkGitHub: function () {
-				this.socket.emit('users.unlinkGitHub', res => {
-					Toast.methods.addToast(res.message, 8000);
-				});
-			},
-			removeSessions: function () {
-				this.socket.emit(`users.removeSessions`, this.$parent.userId, res => {
-					Toast.methods.addToast(res.message, 4000);
-				});
-			}
-		},
-		components: { MainHeader, MainFooter, LoginModal }
-	}
+import { Toast } from "vue-roaster";
+
+import MainHeader from "../MainHeader.vue";
+import MainFooter from "../MainFooter.vue";
+
+import LoginModal from "../Modals/Login.vue";
+import io from "../../io";
+import validation from "../../validation";
+
+export default {
+  data() {
+    return {
+      user: {},
+      newPassword: "",
+      password: false,
+      github: false,
+      setNewPassword: "",
+      passwordStep: 1,
+      passwordCode: ""
+    };
+  },
+  mounted: function() {
+    let _this = this;
+    io.getSocket(socket => {
+      _this.socket = socket;
+      _this.socket.emit("users.findBySession", res => {
+        if (res.status == "success") {
+          _this.user = res.data;
+          _this.password = _this.user.password;
+          _this.github = _this.user.github;
+        } else {
+          _this.$parent.isLoginActive = true;
+          Toast.methods.addToast("Your are currently not signed in", 3000);
+        }
+      });
+      _this.socket.on("event:user.username.changed", username => {
+        _this.$parent.username = username;
+      });
+      _this.socket.on("event:user.linkPassword", () => {
+        _this.password = true;
+      });
+      _this.socket.on("event:user.linkGitHub", () => {
+        _this.github = true;
+      });
+      _this.socket.on("event:user.unlinkPassword", () => {
+        _this.password = false;
+      });
+      _this.socket.on("event:user.unlinkGitHub", () => {
+        _this.github = false;
+      });
+    });
+  },
+  methods: {
+    changeEmail: function() {
+      const email = this.user.email.address;
+      if (!validation.isLength(email, 3, 254))
+        return Toast.methods.addToast(
+          "Email must have between 3 and 254 characters.",
+          8000
+        );
+      if (
+        email.indexOf("@") !== email.lastIndexOf("@") ||
+        !validation.regex.emailSimple.test(email)
+      )
+        return Toast.methods.addToast("Invalid email format.", 8000);
+
+      this.socket.emit("users.updateEmail", this.$parent.userId, email, res => {
+        if (res.status !== "success") Toast.methods.addToast(res.message, 8000);
+        else Toast.methods.addToast("Successfully changed email address", 4000);
+      });
+    },
+    changeUsername: function() {
+      const username = this.user.username;
+      if (!validation.isLength(username, 2, 32))
+        return Toast.methods.addToast(
+          "Username must have between 2 and 32 characters.",
+          8000
+        );
+      if (!validation.regex.azAZ09_.test(username))
+        return Toast.methods.addToast(
+          "Invalid username format. Allowed characters: a-z, A-Z, 0-9 and _.",
+          8000
+        );
+
+      this.socket.emit(
+        "users.updateUsername",
+        this.$parent.userId,
+        username,
+        res => {
+          if (res.status !== "success")
+            Toast.methods.addToast(res.message, 8000);
+          else Toast.methods.addToast("Successfully changed username", 4000);
+        }
+      );
+    },
+    changePassword: function() {
+      const newPassword = this.newPassword;
+      if (!validation.isLength(newPassword, 6, 200))
+        return Toast.methods.addToast(
+          "Password must have between 6 and 200 characters.",
+          8000
+        );
+      if (!validation.regex.password.test(newPassword))
+        return Toast.methods.addToast(
+          "Invalid password format. Must have one lowercase letter, one uppercase letter, one number and one special character.",
+          8000
+        );
+
+      this.socket.emit("users.updatePassword", newPassword, res => {
+        if (res.status !== "success") Toast.methods.addToast(res.message, 8000);
+        else Toast.methods.addToast("Successfully changed password", 4000);
+      });
+    },
+    requestPassword: function() {
+      this.socket.emit("users.requestPassword", res => {
+        Toast.methods.addToast(res.message, 8000);
+        if (res.status === "success") {
+          this.passwordStep = 2;
+        }
+      });
+    },
+    verifyCode: function() {
+      if (!this.passwordCode)
+        return Toast.methods.addToast("Code cannot be empty", 8000);
+      this.socket.emit("users.verifyPasswordCode", this.passwordCode, res => {
+        Toast.methods.addToast(res.message, 8000);
+        if (res.status === "success") {
+          this.passwordStep = 3;
+        }
+      });
+    },
+    setPassword: function() {
+      const newPassword = this.setNewPassword;
+      if (!validation.isLength(newPassword, 6, 200))
+        return Toast.methods.addToast(
+          "Password must have between 6 and 200 characters.",
+          8000
+        );
+      if (!validation.regex.password.test(newPassword))
+        return Toast.methods.addToast(
+          "Invalid password format. Must have one lowercase letter, one uppercase letter, one number and one special character.",
+          8000
+        );
+
+      this.socket.emit(
+        "users.changePasswordWithCode",
+        this.passwordCode,
+        newPassword,
+        res => {
+          Toast.methods.addToast(res.message, 8000);
+        }
+      );
+    },
+    unlinkPassword: function() {
+      this.socket.emit("users.unlinkPassword", res => {
+        Toast.methods.addToast(res.message, 8000);
+      });
+    },
+    unlinkGitHub: function() {
+      this.socket.emit("users.unlinkGitHub", res => {
+        Toast.methods.addToast(res.message, 8000);
+      });
+    },
+    removeSessions: function() {
+      this.socket.emit(`users.removeSessions`, this.$parent.userId, res => {
+        Toast.methods.addToast(res.message, 4000);
+      });
+    }
+  },
+  components: { MainHeader, MainFooter, LoginModal }
+};
 </script>
 
 <style lang="scss" scoped>
-	.container {
-		padding: 25px;
-	}
+.container {
+  padding: 25px;
+}
 
-	a { color: #029ce3 !important; }
+a {
+  color: #029ce3 !important;
+}
 </style>

+ 120 - 92
frontend/components/User/Show.vue

@@ -1,108 +1,136 @@
 <template>
-	<div v-if="isUser">
-		<main-header></main-header>
-		<div class="container">
-			<img class="avatar" src="/assets/notes.png"/>
-			<h2 class="has-text-centered username">@{{user.username}}</h2>
-			<h5>A member since {{user.createdAt}}</h5>
-			<div class="admin-functionality" v-if="$parent.role === 'admin' && !($parent.userId === user._id)">
-				<a class="button is-small is-info is-outlined" @click="changeRank('admin')" v-if="user.role == 'default'">Promote to Admin</a>
-				<a class="button is-small is-danger is-outlined" @click="changeRank('default')" v-if="user.role == 'admin'">Demote to User</a>
-			</div>
-			<nav class="level">
-				<div class="level-item has-text-centered">
-					<p class="heading">Rank</p>
-					<p class="title role">{{user.role}}</p>
-				</div>
-				<div class="level-item has-text-centered">
-					<p class="heading">Songs Requested</p>
-					<p class="title">{{ user.statistics.songsRequested }}</p>
-				</div>
-				<div class="level-item has-text-centered">
-					<p class="heading">Likes</p>
-					<p class="title">{{ user.liked.length }}</p>
-				</div>
-				<div class="level-item has-text-centered">
-					<p class="heading">Dislikes</p>
-					<p class="title">{{ user.disliked.length }}</p>
-				</div>
-			</nav>
-		</div>
-		<main-footer></main-footer>
-	</div>
+  <div v-if="isUser">
+    <main-header></main-header>
+    <div class="container">
+      <img class="avatar" src="/assets/notes.png" />
+      <h2 class="has-text-centered username">@{{user.username}}</h2>
+      <h5>A member since {{user.createdAt}}</h5>
+      <div
+        class="admin-functionality"
+        v-if="$parent.role === 'admin' && !($parent.userId === user._id)"
+      >
+        <a
+          class="button is-small is-info is-outlined"
+          v-on:click="changeRank('admin')"
+          v-if="user.role == 'default'"
+        >Promote to Admin</a>
+        <a
+          class="button is-small is-danger is-outlined"
+          v-on:click="changeRank('default')"
+          v-if="user.role == 'admin'"
+        >Demote to User</a>
+      </div>
+      <nav class="level">
+        <div class="level-item has-text-centered">
+          <p class="heading">Rank</p>
+          <p class="title role">{{user.role}}</p>
+        </div>
+        <div class="level-item has-text-centered">
+          <p class="heading">Songs Requested</p>
+          <p class="title">{{ user.statistics.songsRequested }}</p>
+        </div>
+        <div class="level-item has-text-centered">
+          <p class="heading">Likes</p>
+          <p class="title">{{ user.liked.length }}</p>
+        </div>
+        <div class="level-item has-text-centered">
+          <p class="heading">Dislikes</p>
+          <p class="title">{{ user.disliked.length }}</p>
+        </div>
+      </nav>
+    </div>
+    <main-footer></main-footer>
+  </div>
 </template>
 
 <script>
-	import { Toast } from 'vue-roaster';
+import { Toast } from "vue-roaster";
 
-	import MainHeader from '../MainHeader.vue';
-	import MainFooter from '../MainFooter.vue';
-	import io from '../../io';
+import MainHeader from "../MainHeader.vue";
+import MainFooter from "../MainFooter.vue";
+import io from "../../io";
 
-	export default {
-		data() {
-			return {
-				user: {},
-				isUser: false
-			}
-		},
-		methods: {
-			changeRank(newRank) {
-				this.socket.emit('users.updateRole', this.user._id, ((newRank == 'admin') ? 'admin' : 'default'), res => {
-					if (res.status == 'error') Toast.methods.addToast(res.message, 2000);
-					else this.user.role = newRank; Toast.methods.addToast(`User ${this.$route.params.username}'s rank has been changed to: ${newRank}`, 2000);
-				});
-			}
-		},
-		ready: function() {
-			let _this = this;
-			io.getSocket((socket) => {
-				_this.socket = socket;
-				_this.socket.emit('users.findByUsername', _this.$route.params.username, res => {
-					if (res.status == 'error') this.$router.go('/404');
-					else {
-						_this.user = res.data;
-						this.user.createdAt = moment(this.user.createdAt).format('LL');
-						_this.isUser = true;
-					}
-				});
-			});
-		},
-		components: { MainHeader, MainFooter }
-	}
+export default {
+  data() {
+    return {
+      user: {},
+      isUser: false
+    };
+  },
+  methods: {
+    changeRank(newRank) {
+      this.socket.emit(
+        "users.updateRole",
+        this.user._id,
+        newRank == "admin" ? "admin" : "default",
+        res => {
+          if (res.status == "error") Toast.methods.addToast(res.message, 2000);
+          else this.user.role = newRank;
+          Toast.methods.addToast(
+            `User ${this.$route.params.username}'s rank has been changed to: ${newRank}`,
+            2000
+          );
+        }
+      );
+    }
+  },
+  mounted: function() {
+    let _this = this;
+    io.getSocket(socket => {
+      _this.socket = socket;
+      _this.socket.emit(
+        "users.findByUsername",
+        _this.$route.params.username,
+        res => {
+          if (res.status == "error") this.$router.go("/404");
+          else {
+            _this.user = res.data;
+            this.user.createdAt = moment(this.user.createdAt).format("LL");
+            _this.isUser = true;
+          }
+        }
+      );
+    });
+  },
+  components: { MainHeader, MainFooter }
+};
 </script>
 
 <style lang="scss" scoped>
-	.container {
-		padding: 25px;
-	}
+.container {
+  padding: 25px;
+}
 
-	.avatar {
-		border-radius: 50%;
-		width: 250px;
-		display: block;
-		margin: auto;
-	}
+.avatar {
+  border-radius: 50%;
+  width: 250px;
+  display: block;
+  margin: auto;
+}
 
-	h5 {
-		text-align: center;
-		margin-bottom: 25px;
-		font-size: 17px;
-	}
+h5 {
+  text-align: center;
+  margin-bottom: 25px;
+  font-size: 17px;
+}
 
-	.role { text-transform: capitalize; }
+.role {
+  text-transform: capitalize;
+}
 
-	.level { margin-top: 40px; }
+.level {
+  margin-top: 40px;
+}
 
-	.admin-functionality {
-		text-align: center;
-		margin: 0 auto;
-	}
+.admin-functionality {
+  text-align: center;
+  margin: 0 auto;
+}
 
-	@media (max-width: 350px) {
-		.username {
-			font-size: 2.9rem;
-			word-wrap: break-all;
-		}
-	}
+@media (max-width: 350px) {
+  .username {
+    font-size: 2.9rem;
+    word-wrap: break-all;
+  }
+}
 </style>

+ 1 - 1
frontend/components/pages/About.vue

@@ -64,7 +64,7 @@
 
 			}
 		},
-		ready: function () {
+		mounted: function () {
 
 		}
 	}

+ 131 - 131
frontend/components/pages/Admin.vue

@@ -1,142 +1,142 @@
 <template>
-	<div class='app'>
-		<main-header></main-header>
-		<div class='tabs is-centered'>
-			<ul>
-				<li :class='{ "is-active": currentTab == "queueSongs" }' @click='showTab("queueSongs")'>
-					<a v-link="{ path: '/admin/queuesongs' }">
-						<i class='material-icons'>queue_music</i>
-						<span>&nbsp;Queue Songs</span>
-					</a>
-				</li>
-				<li :class='{ "is-active": currentTab == "songs" }' @click='showTab("songs")'>
-					<a v-link="{ path: '/admin/songs' }">
-						<i class='material-icons'>music_note</i>
-						<span>&nbsp;Songs</span>
-					</a>
-				</li>
-				<li :class='{ "is-active": currentTab == "stations" }' @click='showTab("stations")'>
-					<a v-link="{ path: '/admin/stations' }">
-						<i class='material-icons'>hearing</i>
-						<span>&nbsp;Stations</span>
-					</a>
-				</li>
-				<li :class='{ "is-active": currentTab == "reports" }' @click='showTab("reports")'>
-					<a v-link="{ path: '/admin/reports' }">
-						<i class="material-icons">report_problem</i>
-						<span>&nbsp;Reports</span>
-					</a>
-				</li>
-				<li :class='{ "is-active": currentTab == "news" }' @click='showTab("news")'>
-					<a v-link="{ path: '/admin/news' }">
-						<i class="material-icons">chrome_reader_mode</i>
-						<span>&nbsp;News</span>
-					</a>
-				</li>
-				<li :class='{ "is-active": currentTab == "users" }' @click='showTab("users")'>
-					<a v-link="{ path: '/admin/users' }">
-						<i class="material-icons">person</i>
-						<span>&nbsp;Users</span>
-					</a>
-				</li>
-				<li :class='{ "is-active": currentTab == "statistics" }' @click='showTab("statistics")'>
-					<a v-link="{ path: '/admin/statistics' }">
-						<i class="material-icons">show_chart</i>
-						<span>&nbsp;Statistics</span>
-					</a>
-				</li>
-				<li :class='{ "is-active": currentTab == "punishments" }' @click='showTab("punishments")'>
-					<a v-link="{ path: '/admin/punishments' }">
-						<i class="material-icons">gavel</i>
-						<span>&nbsp;Punishments</span>
-					</a>
-				</li>
-			</ul>
-		</div>
+  <div class="app">
+    <main-header></main-header>
+    <div class="tabs is-centered">
+      <ul>
+        <li :class="{ 'is-active': currentTab == 'queueSongs' }" v-on:click="showTab('queueSongs')">
+          <router-link to="/admin/queuesongs">
+            <i class="material-icons">queue_music</i>
+            <span>&nbsp;Queue Songs</span>
+          </router-link>
+        </li>
+        <li :class="{ 'is-active': currentTab == 'songs' }" v-on:click="showTab('songs')">
+          <router-link to="/admin/songs">
+            <i class="material-icons">music_note</i>
+            <span>&nbsp;Songs</span>
+          </router-link>
+        </li>
+        <li :class="{ 'is-active': currentTab == 'stations' }" v-on:click="showTab('stations')">
+          <router-link to="/admin/stations">
+            <i class="material-icons">hearing</i>
+            <span>&nbsp;Stations</span>
+          </router-link>
+        </li>
+        <li :class="{ 'is-active': currentTab == 'reports' }" v-on:click="showTab('reports')">
+          <router-link to="/admin/reports">
+            <i class="material-icons">report_problem</i>
+            <span>&nbsp;Reports</span>
+          </router-link>
+        </li>
+        <li :class="{ 'is-active': currentTab == 'news' }" v-on:click="showTab('news')">
+          <router-link to="/admin/news">
+            <i class="material-icons">chrome_reader_mode</i>
+            <span>&nbsp;News</span>
+          </router-link>
+        </li>
+        <li :class="{ 'is-active': currentTab == 'users' }" v-on:click="showTab('users')">
+          <router-link to="/admin/users">
+            <i class="material-icons">person</i>
+            <span>&nbsp;Users</span>
+          </router-link>
+        </li>
+        <li :class="{ 'is-active': currentTab == 'statistics' }" v-on:click="showTab('statistics')">
+          <router-link to="/admin/statistics">
+            <i class="material-icons">show_chart</i>
+            <span>&nbsp;Statistics</span>
+          </router-link>
+        </li>
+        <li :class="{ 'is-active': currentTab == 'punishments' }" v-on:click="showTab('punishments')">
+          <router-link to="/admin/punishments">
+            <i class="material-icons">gavel</i>
+            <span>&nbsp;Punishments</span>
+          </router-link>
+        </li>
+      </ul>
+    </div>
 
-		<queue-songs v-if='currentTab == "queueSongs"'></queue-songs>
-		<songs v-if='currentTab == "songs"'></songs>
-		<stations v-if='currentTab == "stations"'></stations>
-		<reports v-if='currentTab == "reports"'></reports>
-		<news v-if='currentTab == "news"'></news>
-		<users v-if='currentTab == "users"'></users>
-		<statistics v-if='currentTab == "statistics"'></statistics>
-		<punishments v-if='currentTab == "punishments"'></punishments>
-	</div>
+    <queue-songs v-if="currentTab == 'queueSongs'"></queue-songs>
+    <songs v-if="currentTab == 'songs'"></songs>
+    <stations v-if="currentTab == 'stations'"></stations>
+    <reports v-if="currentTab == 'reports'"></reports>
+    <news v-if="currentTab == 'news'"></news>
+    <users v-if="currentTab == 'users'"></users>
+    <statistics v-if="currentTab == 'statistics'"></statistics>
+    <punishments v-if="currentTab == 'punishments'"></punishments>
+  </div>
 </template>
 
 <script>
-	import MainHeader from '../MainHeader.vue';
-	import MainFooter from '../MainFooter.vue';
+import MainHeader from "../MainHeader.vue";
+import MainFooter from "../MainFooter.vue";
 
-	import QueueSongs from '../Admin/QueueSongs.vue';
-	import Songs from '../Admin/Songs.vue';
-	import Stations from '../Admin/Stations.vue';
-	import Reports from '../Admin/Reports.vue';
-	import News from '../Admin/News.vue';
-	import Users from '../Admin/Users.vue';
-	import Statistics from '../Admin/Statistics.vue';
-	import Punishments from '../Admin/Punishments.vue';
+import QueueSongs from "../Admin/QueueSongs.vue";
+import Songs from "../Admin/Songs.vue";
+import Stations from "../Admin/Stations.vue";
+import Reports from "../Admin/Reports.vue";
+import News from "../Admin/News.vue";
+import Users from "../Admin/Users.vue";
+import Statistics from "../Admin/Statistics.vue";
+import Punishments from "../Admin/Punishments.vue";
 
-	export default {
-		components: {
-			MainHeader,
-			MainFooter,
-			QueueSongs,
-			Songs,
-			Stations,
-			Reports,
-			News,
-			Users,
-			Statistics,
-			Punishments
-		},
-		ready() {
-			switch(window.location.pathname) {
-				case '/admin/queuesongs':
-					this.currentTab = 'queueSongs';
-					break;
-				case '/admin/songs':
-					this.currentTab = 'songs';
-					break;
-				case '/admin/stations':
-					this.currentTab = 'stations';
-					break;
-				case '/admin/reports':
-					this.currentTab = 'reports';
-					break;
-				case '/admin/news':
-					this.currentTab = 'news';
-					break;
-				case '/admin/users':
-					this.currentTab = 'users';
-					break;
-				case '/admin/statistics':
-					this.currentTab = 'statistics';
-					break;
-				case '/admin/punishments':
-					this.currentTab = 'punishments';
-					break;
-				default:
-					this.currentTab = 'queueSongs';
-			}
-		},
-		data() {
-			return {
-				currentTab: 'queueSongs'
-			}
-		},
-		methods: {
-			showTab: function (tab) {
-				this.currentTab = tab;
-			}
-		}
-	}
+export default {
+  components: {
+    MainHeader,
+    MainFooter,
+    QueueSongs,
+    Songs,
+    Stations,
+    Reports,
+    News,
+    Users,
+    Statistics,
+    Punishments
+  },
+  mounted() {
+    switch (window.location.pathname) {
+      case "/admin/queuesongs":
+        this.currentTab = "queueSongs";
+        break;
+      case "/admin/songs":
+        this.currentTab = "songs";
+        break;
+      case "/admin/stations":
+        this.currentTab = "stations";
+        break;
+      case "/admin/reports":
+        this.currentTab = "reports";
+        break;
+      case "/admin/news":
+        this.currentTab = "news";
+        break;
+      case "/admin/users":
+        this.currentTab = "users";
+        break;
+      case "/admin/statistics":
+        this.currentTab = "statistics";
+        break;
+      case "/admin/punishments":
+        this.currentTab = "punishments";
+        break;
+      default:
+        this.currentTab = "queueSongs";
+    }
+  },
+  data() {
+    return {
+      currentTab: "queueSongs"
+    };
+  },
+  methods: {
+    showTab: function(tab) {
+      this.currentTab = tab;
+    }
+  }
+};
 </script>
 
 <style lang='scss' scoped>
-	.is-active a {
-		color: #03a9f4 !important;
-		border-color: #03a9f4 !important;
-	}
+.is-active a {
+  color: #03a9f4 !important;
+  border-color: #03a9f4 !important;
+}
 </style>

+ 465 - 376
frontend/components/pages/Home.vue

@@ -1,267 +1,344 @@
 <template>
-	<div class="app" :class="{'nightMode': nightMode}">
-		<main-header></main-header>
-		<div class="group">
-			<div class="group-title">Official Stations</div>
-			<div class="card station-card" v-for="station in stations.official" v-link="{ path: '/' + station.name }" @click="this.$dispatch('joinStation', station._id)" :class="{'isPrivate': station.privacy === 'private'}">
-				<div class="card-image">
-					<figure class="image is-square">
-						<img :src="station.currentSong.thumbnail" onerror="this.src='/assets/notes-transparent.png'" />
-					</figure>
-				</div>
-				<div class="card-content">
-					<div class="media">
-						<div class="media-left displayName">
-							<h5>{{ station.displayName }}</h5>
-						</div>
-					</div>
-
-					<div class="content">
-						{{ station.description }}
-					</div>
-
-					<div class="under-content">
-						<i class='material-icons' title="How many users there are in the station.">people</i>
-						<span class="users-count" title="How many users there are in the station.">&nbsp;{{station.userCount}}</span>
-
-						<i class="material-icons right-icon" v-if="station.privacy !== 'public'" title="This station is not visible to other users.">lock</i>
-					</div>
-				</div>
-				<a @click="this.$dispatch('joinStation', station._id)" href='#' class='absolute-a' v-link="{ path: '/' + station.name }"></a>
-			</div>
-		</div>
-		<div class="group">
-			<div class="group-title">
-				Community Stations&nbsp;
-				<a @click='modals.createCommunityStation = !modals.createCommunityStation' v-if="$parent.loggedIn" href='#'>
-				<i class="material-icons community-button">add_circle_outline</i></a>
-			</div>
-			<div class="card station-card" v-for="station in stations.community" v-link="{ path: '/community/' + station.name }" @click="this.$dispatch('joinStation', station._id)" :class="{'isPrivate': station.privacy === 'private','isMine': isOwner(station)}">
-				<div class="card-image">
-					<figure class="image is-square">
-						<img :src="station.currentSong.thumbnail" onerror="this.src='/assets/notes-transparent.png'" />
-					</figure>
-				</div>
-				<div class="card-content">
-					<div class="media">
-						<div class="media-left displayName">
-							<h5>{{ station.displayName }}</h5>
-						</div>
-					</div>
-
-					<div class="content">
-						{{ station.description }}
-					</div>
-					<div class="under-content">
-						<i class='material-icons' title="How many users there are in the station.">people</i>
-						<span class="users-count" title="How many users there are in the station.">&nbsp;{{station.userCount}}</span>
-
-						<i class="material-icons right-icon" v-if="station.privacy !== 'public'" title="This station is not visible to other users.">lock</i>
-						<i class="material-icons right-icon" v-if="isOwner(station)" title="This is your station.">home</i>
-					</div>
-				</div>
-				<a @click="this.$dispatch('joinStation', station._id)" href='#' class='absolute-a' v-link="{ path: '/community/' + station.name }"></a>
-			</div>
-		</div>
-		<main-footer></main-footer>
-	</div>
-	<create-community-station v-if='modals.createCommunityStation'></create-community-station>
+  <div>
+    <div class="app" :class="{'nightMode': nightMode}">
+      <main-header></main-header>
+      <div class="group">
+        <div class="group-title">Official Stations</div>
+        <router-link
+          class="card station-card"
+          :to="{ name: 'official', params: { id: station.name } }"
+          v-for="(station, index) in stations.official"
+          :key="index"
+          :class="{'isPrivate': station.privacy === 'private'}"
+        >
+          <div class="card-image">
+            <figure class="image is-square">
+              <img
+                :src="station.currentSong.thumbnail"
+                onerror="this.src='/assets/notes-transparent.png'"
+              />
+            </figure>
+          </div>
+          <div class="card-content">
+            <div class="media">
+              <div class="media-left displayName">
+                <h5>{{ station.displayName }}</h5>
+              </div>
+            </div>
+
+            <div class="content">{{ station.description }}</div>
+
+            <div class="under-content">
+              <i class="material-icons" title="How many users there are in the station.">people</i>
+              <span
+                class="users-count"
+                title="How many users there are in the station."
+              >&nbsp;{{station.userCount}}</span>
+
+              <i
+                class="material-icons right-icon"
+                v-if="station.privacy !== 'public'"
+                title="This station is not visible to other users."
+              >lock</i>
+            </div>
+          </div>
+          <router-link
+            href="#"
+            class="absolute-a"
+            :to="{ name: 'official', params: { id: station.name } }"
+          ></router-link>
+        </router-link>
+      </div>
+      <div class="group">
+        <div class="group-title">
+          Community Stations&nbsp;
+          <a
+            v-on:click="toggleModal({
+              sector: 'home',
+              modal: 'createCommunityStation'
+            })"
+            v-if="$parent.loggedIn"
+            href="#"
+          >
+            <i class="material-icons community-button">add_circle_outline</i>
+          </a>
+        </div>
+        <router-link
+          :to="{ name: 'community', params: { id: station.name } }"
+          class="card station-card"
+          v-for="(station, index) in stations.community"
+          :key="index"
+          :class="{'isPrivate': station.privacy === 'private','isMine': isOwner(station)}"
+        >
+          <div class="card-image">
+            <figure class="image is-square">
+              <img
+                :src="station.currentSong.thumbnail"
+                onerror="this.src='/assets/notes-transparent.png'"
+              />
+            </figure>
+          </div>
+          <div class="card-content">
+            <div class="media">
+              <div class="media-left displayName">
+                <h5>{{ station.displayName }}</h5>
+              </div>
+            </div>
+
+            <div class="content">{{ station.description }}</div>
+            <div class="under-content">
+              <i class="material-icons" title="How many users there are in the station.">people</i>
+              <span
+                class="users-count"
+                title="How many users there are in the station."
+              >&nbsp;{{station.userCount}}</span>
+
+              <i
+                class="material-icons right-icon"
+                v-if="station.privacy !== 'public'"
+                title="This station is not visible to other users."
+              >lock</i>
+              <i
+                class="material-icons right-icon"
+                v-if="isOwner(station)"
+                title="This is your station."
+              >home</i>
+            </div>
+          </div>
+          <router-link
+            href="#"
+            class="absolute-a"
+            :to="{ name: 'community', params: { id: station.name } }"
+          />
+        </router-link>
+      </div>
+      <main-footer></main-footer>
+    </div>
+    <create-community-station v-if="modals.createCommunityStation"></create-community-station>
+  </div>
 </template>
 
 <script>
-	import MainHeader from '../MainHeader.vue';
-	import MainFooter from '../MainFooter.vue';
-	import CreateCommunityStation from '../Modals/CreateCommunityStation.vue';
-	import auth from '../../auth';
-	import io from '../../io';
-
-	export default {
-		data() {
-			return {
-				recaptcha: {
-					key: ''
-				},
-				stations: {
-					official: [],
-					community: []
-				},
-				modals: {
-					createCommunityStation: false
-				},
-				nightMode: false
-			}
-		},
-		ready() {
-			let _this = this;
-			auth.getStatus((authenticated, role, username, userId) => {
-				io.getSocket((socket) => {
-					_this.socket = socket;
-					if (_this.socket.connected) _this.init();
-					io.onConnect(() => {
-						_this.init();
-					});
-					_this.socket.on('event:stations.created', station => {
-						if (!station.currentSong) station.currentSong = { thumbnail: '/assets/notes-transparent.png' };
-						if (station.currentSong && !station.currentSong.thumbnail) station.currentSong.thumbnail = "/assets/notes-transparent.png";
-						_this.stations[station.type].push(station);
-					});
-					_this.socket.on('event:userCount.updated', (stationId, userCount) => {
-						_this.stations.official.forEach((station) => {
-							if (station._id === stationId) {
-								station.userCount = userCount;
-							}
-						});
-
-						_this.stations.community.forEach((station) => {
-							if (station._id === stationId) {
-								station.userCount = userCount;
-							}
-						});
-					});
-					_this.socket.on('event:station.nextSong', (stationId, newSong) => {
-						_this.stations.official.forEach((station) => {
-							if (station._id === stationId) {
-								if (!newSong) newSong = { thumbnail: '/assets/notes-transparent.png' };
-								if (newSong && !newSong.thumbnail) newSong.thumbnail = "/assets/notes-transparent.png";
-								station.currentSong = newSong;
-							}
-						});
-
-						_this.stations.community.forEach((station) => {
-							if (station._id === stationId) {
-								if (!newSong) newSong = { thumbnail: '/assets/notes-transparent.png' };
-								if (newSong && !newSong.thumbnail) newSong.thumbnail = "/assets/notes-transparent.png";
-								station.currentSong = newSong;
-							}
-						});
-					});
-				});
-			});
-		},
-		methods: {
-			toggleModal: function (type) {
-				this.$dispatch('toggleModal', type);
-			},
-			init: function() {
-				let _this = this;
-				auth.getStatus((authenticated, role, username, userId) => {
-					_this.socket.emit('stations.index', data => {
-						_this.stations.community = [];
-						_this.stations.official = [];
-						if (data.status === "success") data.stations.forEach(station => {
-							if (!station.currentSong) station.currentSong = { thumbnail: '/assets/notes-transparent.png' };
-							if (station.currentSong && !station.currentSong.thumbnail) station.currentSong.thumbnail = "/assets/notes-transparent.png";
-							if (station.privacy !== 'public') station.class = { 'station-red': true }
-							else if (station.type === 'community' && station.owner === userId) station.class = { 'station-blue': true }
-							if (station.type == 'official') _this.stations.official.push(station);
-							else _this.stations.community.push(station);
-						});
-					});
-					_this.socket.emit("apis.joinRoom", 'home', () => {
-					});
-				});
-			},
-			isOwner: function(station) {
-				let _this = this;
-				return station.owner === _this.$parent.userId && station.privacy === 'public';
-			}
-		},
-		components: { MainHeader, MainFooter, CreateCommunityStation }
-	}
+import { mapState, mapActions } from "vuex";
+
+import MainHeader from "../MainHeader.vue";
+import MainFooter from "../MainFooter.vue";
+import CreateCommunityStation from "../Modals/CreateCommunityStation.vue";
+import auth from "../../auth";
+import io from "../../io";
+
+export default {
+  data() {
+    return {
+      recaptcha: {
+        key: ""
+      },
+      stations: {
+        official: [],
+        community: []
+      },
+      nightMode: false
+    };
+  },
+  computed: mapState("modals", {
+    modals: state => state.modals.home
+  }),
+  mounted() {
+    let _this = this;
+    auth.getStatus((authenticated, role, username, userId) => {
+      io.getSocket(socket => {
+        _this.socket = socket;
+        if (_this.socket.connected) _this.init();
+        io.onConnect(() => {
+          _this.init();
+        });
+        _this.socket.on("event:stations.created", station => {
+          if (!station.currentSong)
+            station.currentSong = {
+              thumbnail: "/assets/notes-transparent.png"
+            };
+          if (station.currentSong && !station.currentSong.thumbnail)
+            station.currentSong.thumbnail = "/assets/notes-transparent.png";
+          _this.stations[station.type].push(station);
+        });
+        _this.socket.on("event:userCount.updated", (stationId, userCount) => {
+          _this.stations.official.forEach(station => {
+            if (station._id === stationId) {
+              station.userCount = userCount;
+            }
+          });
+
+          _this.stations.community.forEach(station => {
+            if (station._id === stationId) {
+              station.userCount = userCount;
+            }
+          });
+        });
+        _this.socket.on("event:station.nextSong", (stationId, newSong) => {
+          _this.stations.official.forEach(station => {
+            if (station._id === stationId) {
+              if (!newSong)
+                newSong = { thumbnail: "/assets/notes-transparent.png" };
+              if (newSong && !newSong.thumbnail)
+                newSong.thumbnail = "/assets/notes-transparent.png";
+              station.currentSong = newSong;
+            }
+          });
+
+          _this.stations.community.forEach(station => {
+            if (station._id === stationId) {
+              if (!newSong)
+                newSong = { thumbnail: "/assets/notes-transparent.png" };
+              if (newSong && !newSong.thumbnail)
+                newSong.thumbnail = "/assets/notes-transparent.png";
+              station.currentSong = newSong;
+            }
+          });
+        });
+      });
+    });
+  },
+  methods: {
+    init: function() {
+      let _this = this;
+      auth.getStatus((authenticated, role, username, userId) => {
+        _this.socket.emit("stations.index", data => {
+          _this.stations.community = [];
+          _this.stations.official = [];
+          if (data.status === "success")
+            data.stations.forEach(station => {
+              if (!station.currentSong)
+                station.currentSong = {
+                  thumbnail: "/assets/notes-transparent.png"
+                };
+              if (station.currentSong && !station.currentSong.thumbnail)
+                station.currentSong.thumbnail = "/assets/notes-transparent.png";
+              if (station.privacy !== "public")
+                station.class = { "station-red": true };
+              else if (station.type === "community" && station.owner === userId)
+                station.class = { "station-blue": true };
+              if (station.type == "official")
+                _this.stations.official.push(station);
+              else _this.stations.community.push(station);
+            });
+        });
+        _this.socket.emit("apis.joinRoom", "home", () => {});
+      });
+    },
+    isOwner: function(station) {
+      let _this = this;
+      return (
+        station.owner === _this.$parent.userId && station.privacy === "public"
+      );
+    },
+    ...mapActions("modals", ["toggleModal"])
+  },
+  components: { MainHeader, MainFooter, CreateCommunityStation }
+};
 </script>
 
 <style lang='scss'>
-	* { box-sizing: border-box; }
-
-	html {
-		width: 100%;
-		height: 100%;
-		color: rgba(0, 0, 0, 0.87);
-
-		body {
-			width: 100%;
-			height: 100%;
-			margin: 0;
-			padding: 0;
-		}
-	}
-
-	@media only screen and (min-width: 1200px) {
-		html { font-size: 15px; }
-	}
-
-	@media only screen and (min-width: 992px) {
-		html { font-size: 14.5px; }
-	}
-
-	@media only screen and (min-width: 0) {
-		html { font-size: 14px; }
-	}
-
-	.under-content {
-		width: calc(100% - 40px);
-		left: 20px;
-		right: 20px;
-		bottom: 10px;
-		text-align: left;
-		height: 25px;
-		position: absolute;
-		margin-bottom: 10px;
-		line-height: 1;
-	    font-size: 24px;
-	    vertical-align: middle;
-
-		* {
-			z-index: 10;
-			position: relative;
-		}
-
-		.right-icon {
-			float: right;
-		}
-	}
-
-	.users-count {
-		font-size: 20px;
-		position: relative;
-		top: -4px;
-	}
-
-	.right {
-		float: right;
-	}
-
-	.group { min-height: 64px; }
-
-	.station-card {
-		margin: 10px;
-		cursor: pointer;
-		height: 475px;
-
-		transition: all ease-in-out 0.2s;
-
-		.card-content {
-			max-height: 159px;
-
-			.content {
-				word-wrap: break-word;
-				overflow: hidden;
-				text-overflow: ellipsis;
-				display: -webkit-box;
-				-webkit-box-orient: vertical;
-				-webkit-line-clamp: 3;
-				line-height: 20px;
-				max-height: 60px;
-			}
-		}
-	}
-
-	.station-card:hover {
-		box-shadow: 0 2px 3px rgba(10, 10, 10, 0.3), 0 0 10px rgba(10, 10, 10, 0.3);
-		transition: all ease-in-out 0.2s;
-	}
-
-	/*.isPrivate {
+* {
+  box-sizing: border-box;
+}
+
+html {
+  width: 100%;
+  height: 100%;
+  color: rgba(0, 0, 0, 0.87);
+
+  body {
+    width: 100%;
+    height: 100%;
+    margin: 0;
+    padding: 0;
+  }
+}
+
+@media only screen and (min-width: 1200px) {
+  html {
+    font-size: 15px;
+  }
+}
+
+@media only screen and (min-width: 992px) {
+  html {
+    font-size: 14.5px;
+  }
+}
+
+@media only screen and (min-width: 0) {
+  html {
+    font-size: 14px;
+  }
+}
+
+.under-content {
+  width: calc(100% - 40px);
+  left: 20px;
+  right: 20px;
+  bottom: 10px;
+  text-align: left;
+  height: 25px;
+  position: absolute;
+  margin-bottom: 10px;
+  line-height: 1;
+  font-size: 24px;
+  vertical-align: middle;
+
+  * {
+    z-index: 10;
+    position: relative;
+  }
+
+  .right-icon {
+    float: right;
+  }
+}
+
+.users-count {
+  font-size: 20px;
+  position: relative;
+  top: -4px;
+}
+
+.right {
+  float: right;
+}
+
+.group {
+  min-height: 64px;
+}
+
+.station-card {
+  margin: 10px;
+  cursor: pointer;
+  height: 475px;
+
+  transition: all ease-in-out 0.2s;
+
+  .card-content {
+    max-height: 159px;
+
+    .content {
+      word-wrap: break-word;
+      overflow: hidden;
+      text-overflow: ellipsis;
+      display: -webkit-box;
+      -webkit-box-orient: vertical;
+      -webkit-line-clamp: 3;
+      line-height: 20px;
+      max-height: 60px;
+    }
+  }
+}
+
+.station-card:hover {
+  box-shadow: 0 2px 3px rgba(10, 10, 10, 0.3), 0 0 10px rgba(10, 10, 10, 0.3);
+  transition: all ease-in-out 0.2s;
+}
+
+/*.isPrivate {
 		background-color: #F8BBD0;
 	}
 
@@ -269,123 +346,135 @@
 		background-color: #29B6F6;
 	}*/
 
-	.community-button {
-		cursor: pointer;
-		transition: .25s ease color;
-		font-size: 30px;
-		color: #4a4a4a;
-	}
-
-	.community-button:hover { color: #03a9f4; }
-
-	.station-privacy { text-transform: capitalize; }
-
-	.label { display: flex; }
-
-	.g-recaptcha {
-		display: flex;
-		justify-content: center;
-		margin-top: 20px;
-	}
-
-	.group {
-		text-align: center;
-		width: 100%;
-		margin: 64px 0 0 0;
-
-		.group-title {
-			float: left;
-			clear: none;
-			width: 100%;
-			height: 64px;
-			line-height: 48px;
-			text-align: center;
-			font-size: 48px;
-			margin-bottom: 25px;
-		}
-	}
-
-	.group .card {
-		display: inline-flex;
-    	flex-direction: column;
-		overflow: hidden;
-
-		.content {
-			text-align: left;
-			word-wrap: break-word;
-		}
-
-		.media {
-			display: flex;
-    		align-items: center;
-
-			.station-status { line-height: 13px; }
-
-			h5 { margin: 0; }
-		}
-	}
-
-	.displayName {
-		word-wrap: break-word;
-    	width: 80%;
-		word-wrap: break-word;
-	    overflow: hidden;
-	    text-overflow: ellipsis;
-	    display: -webkit-box;
-	    -webkit-box-orient: vertical;
-	    -webkit-line-clamp: 1;
-	    line-height: 30px;
-	    max-height: 30px;
-	}
-
-	.nightMode {
-		background-color: rgb(51, 51, 51);
-		color: #e6e6e6;
-
-		.community-button {
-			cursor: pointer;
-			transition: .25s ease color;
-			font-size: 30px;
-			color: #e6e6e6;
-		}
-
-		.community-button:hover { color: #03a9f4; }
-
-		.station-card {
-			margin: 10px;
-			cursor: pointer;
-			height: 475px;
-			background-color: rgb(51, 51, 51);
-			color: #e6e6e6;
-
-			.card-content {
-				max-height: 159px;
-				color: #e6e6e6;
-
-				.content {
-					word-wrap: break-word;
-					overflow: hidden;
-					text-overflow: ellipsis;
-					display: -webkit-box;
-					-webkit-box-orient: vertical;
-					-webkit-line-clamp: 3;
-					line-height: 20px;
-					max-height: 60px;
-					color: #e6e6e6;
-				}
-			}
-		}
-
-		.station-card:hover {
-			box-shadow: 0 2px 3px rgba(10, 10, 10, 0.3), 0 0 10px rgba(10, 10, 10, 0.3);
-		}
-
-		.isPrivate {
-			background-color: #d01657;
-		}
-
-		.isMine {
-			background-color: #0777ab;
-		}
-	}
+.community-button {
+  cursor: pointer;
+  transition: 0.25s ease color;
+  font-size: 30px;
+  color: #4a4a4a;
+}
+
+.community-button:hover {
+  color: #03a9f4;
+}
+
+.station-privacy {
+  text-transform: capitalize;
+}
+
+.label {
+  display: flex;
+}
+
+.g-recaptcha {
+  display: flex;
+  justify-content: center;
+  margin-top: 20px;
+}
+
+.group {
+  text-align: center;
+  width: 100%;
+  margin: 64px 0 0 0;
+
+  .group-title {
+    float: left;
+    clear: none;
+    width: 100%;
+    height: 64px;
+    line-height: 48px;
+    text-align: center;
+    font-size: 48px;
+    margin-bottom: 25px;
+  }
+}
+
+.group .card {
+  display: inline-flex;
+  flex-direction: column;
+  overflow: hidden;
+
+  .content {
+    text-align: left;
+    word-wrap: break-word;
+  }
+
+  .media {
+    display: flex;
+    align-items: center;
+
+    .station-status {
+      line-height: 13px;
+    }
+
+    h5 {
+      margin: 0;
+    }
+  }
+}
+
+.displayName {
+  word-wrap: break-word;
+  width: 80%;
+  word-wrap: break-word;
+  overflow: hidden;
+  text-overflow: ellipsis;
+  display: -webkit-box;
+  -webkit-box-orient: vertical;
+  -webkit-line-clamp: 1;
+  line-height: 30px;
+  max-height: 30px;
+}
+
+.nightMode {
+  background-color: rgb(51, 51, 51);
+  color: #e6e6e6;
+
+  .community-button {
+    cursor: pointer;
+    transition: 0.25s ease color;
+    font-size: 30px;
+    color: #e6e6e6;
+  }
+
+  .community-button:hover {
+    color: #03a9f4;
+  }
+
+  .station-card {
+    margin: 10px;
+    cursor: pointer;
+    height: 475px;
+    background-color: rgb(51, 51, 51);
+    color: #e6e6e6;
+
+    .card-content {
+      max-height: 159px;
+      color: #e6e6e6;
+
+      .content {
+        word-wrap: break-word;
+        overflow: hidden;
+        text-overflow: ellipsis;
+        display: -webkit-box;
+        -webkit-box-orient: vertical;
+        -webkit-line-clamp: 3;
+        line-height: 20px;
+        max-height: 60px;
+        color: #e6e6e6;
+      }
+    }
+  }
+
+  .station-card:hover {
+    box-shadow: 0 2px 3px rgba(10, 10, 10, 0.3), 0 0 10px rgba(10, 10, 10, 0.3);
+  }
+
+  .isPrivate {
+    background-color: #d01657;
+  }
+
+  .isMine {
+    background-color: #0777ab;
+  }
+}
 </style>

+ 1 - 1
frontend/components/pages/News.vue

@@ -62,7 +62,7 @@
 				noFound: false
 			}
 		},
-		ready: function () {
+		mounted: function () {
 			let _this = this;
 			io.getSocket((socket) => {
 				_this.socket = socket;

+ 149 - 100
frontend/main.js

@@ -1,143 +1,192 @@
-import Vue from 'vue';
-import VueRouter from 'vue-router';
-import App from './App.vue';
-import auth from './auth';
-import io from './io';
+import Vue from "vue";
+
+import store from "./store";
+
+import VueRouter from "vue-router";
+
+import App from "./App.vue";
+import auth from "./auth";
+import io from "./io";
 
 Vue.use(VueRouter);
 
 let router = new VueRouter({
-	history: true,
-	suppressTransitionError: true
+	mode: "history",
+	routes: [
+		{
+			path: "/",
+			component: () =>
+				import(/* webpackChunkName: "home" */ "./components/pages/Home.vue")
+		},
+		{
+			path: "*",
+			component: () =>
+				import(/* webpackChunkName: "404" */ "./components/404.vue")
+		},
+		{
+			path: "/404",
+			component: () =>
+				import(/* webpackChunkName: "404" */ "./components/404.vue")
+		},
+		{
+			path: "/terms",
+			component: () =>
+				import(/* webpackChunkName: "terms" */ "./components/pages/Terms.vue")
+		},
+		{
+			path: "/privacy",
+			component: () =>
+				import(
+					/* webpackChunkName: "privacy" */ "./components/pages/Privacy.vue"
+				)
+		},
+		{
+			path: "/team",
+			component: () =>
+				import(/* webpackChunkName: "team" */ "./components/pages/Team.vue")
+		},
+		{
+			path: "/news",
+			component: () =>
+				import(/* webpackChunkName: "news" */ "./components/pages/News.vue")
+		},
+		{
+			path: "/about",
+			component: () =>
+				import(/* webpackChunkName: "about" */ "./components/pages/About.vue")
+		},
+		{
+			name: "profile",
+			path: "/u/:username",
+			component: () =>
+				import(/* webpackChunkName: "profile" */ "./components/User/Show.vue")
+		},
+		{
+			path: "/settings",
+			component: () =>
+				import(
+					/* webpackChunkName: "settings" */ "./components/User/Settings.vue"
+				),
+			loginRequired: true
+		},
+		{
+			path: "/reset_password",
+			component: () =>
+				import(
+					/* webpackChunkName: "reset_password" */ "./components/User/ResetPassword.vue"
+				)
+		},
+		{
+			path: "/login",
+			component: () =>
+				import(/* webpackChunkName: "login" */ "./components/Modals/Login.vue")
+		},
+		{
+			path: "/register",
+			component: () =>
+				import(
+					/* webpackChunkName: "register" */ "./components/Modals/Register.vue"
+				)
+		},
+		{
+			path: "/admin",
+			component: () =>
+				import(/* webpackChunkName: "admin" */ "./components/pages/Admin.vue"),
+			adminRequired: true
+		},
+		{
+			path: "/admin/:page",
+			component: () =>
+				import(/* webpackChunkName: "admin" */ "./components/pages/Admin.vue"),
+			adminRequired: true
+		},
+		{
+			name: "official",
+			path: "/official/:id",
+			alias: "/:id",
+			component: () =>
+				import(
+					/* webpackChunkName: "officialStation" */ "./components/Station/Station.vue"
+				),
+			officialRequired: true
+		},
+		{
+			name: "community",
+			path: "/community/:id",
+			component: () =>
+				import(
+					/* webpackChunkName: "communityStation" */ "./components/Station/Station.vue"
+				),
+			communityRequired: true
+		}
+	]
 });
 
 let _this = this;
 
-lofig.folder = '../config/default.json';
-lofig.get('serverDomain', function(res) {
+lofig.folder = "../config/default.json";
+lofig.get("serverDomain", function(res) {
 	io.init(res);
-	io.getSocket((socket) => {
+	io.getSocket(socket => {
 		socket.on("ready", (status, role, username, userId) => {
 			auth.data(status, role, username, userId);
 		});
-		socket.on('keep.event:banned', ban => {
+		socket.on("keep.event:banned", ban => {
 			auth.setBanned(ban);
 		});
 	});
 });
 
-document.onkeydown = event => {
-	event = event || window.event;
-	if (event.keyCode === 27) router.app.$dispatch('closeModal');
-};
+router.beforeEach((to, from, next) => {
+	window.location.hash = "";
 
-router.beforeEach(transition => {
-	window.location.hash = '';
-	//
 	if (window.stationInterval) {
 		clearInterval(window.stationInterval);
 		window.stationInterval = 0;
 	}
 	if (window.socket) io.removeAllListeners();
 	io.clear();
-	if (transition.to.loginRequired || transition.to.adminRequired) {
+	if (to.loginRequired || to.adminRequired) {
 		auth.getStatus((authenticated, role) => {
-			if (transition.to.loginRequired && !authenticated) transition.redirect('/login');
-			else if (transition.to.adminRequired && role !== 'admin') transition.redirect('/');
-			else transition.next();
+			if (to.loginRequired && !authenticated) next({ path: "/login" });
+			else if (to.adminRequired && role !== "admin") next({ path: "/" });
+			else next();
 		});
-	} else transition.next();
+	} else next();
 
-	if (transition.to.officialRequired) {
+	if (to.officialRequired) {
 		io.getSocket(socket => {
-			socket.emit('stations.findByName', transition.to.params.id, res => {
-				if (res.status === 'success') {
-					if (res.data.type === 'community') transition.redirect(`/community/${transition.to.params.id}`);
-					else transition.next();
+			socket.emit("stations.findByName", to.params.id, res => {
+				if (res.status === "success") {
+					if (res.data.type === "community")
+						next({ path: `/community/${to.params.id}` });
+					else next();
 				}
 			});
 		});
 	}
 
-	if (transition.to.communityRequired) {
+	if (to.communityRequired) {
 		io.getSocket(socket => {
-			socket.emit('stations.findByName', transition.to.params.id, res => {
-				if (res.status === 'success') {
-					if (res.data.type === 'official') transition.redirect(`/official/${transition.to.params.id}`);
-					else transition.next();
+			socket.emit("stations.findByName", to.params.id, res => {
+				if (res.status === "success") {
+					if (res.data.type === "official")
+						next({ path: `/official/${to.params.id}` });
+					else next();
 				}
 			});
 		});
 	}
 });
 
-router.afterEach(data => {
-	ga('set', 'page', data.to.path);
-	ga('send', 'pageview');
+router.afterEach(to => {
+	ga("set", "page", to.path);
+	ga("send", "pageview");
 });
 
-
-router.map({
-	'/': {
-		component: resolve => require.ensure([], () => resolve(require('./components/pages/Home.vue')), 'home')
-	},
-	'*': {
-		component: resolve => require.ensure([], () => resolve(require('./components/404.vue')), '404')
-	},
-	'404': {
-		component: resolve => require.ensure([], () => resolve(require('./components/404.vue')), '404')
-	},
-	'/terms': {
-		component: resolve => require.ensure([], () => resolve(require('./components/pages/Terms.vue')), 'terms')
-	},
-	'/privacy': {
-		component: resolve => require.ensure([], () => resolve(require('./components/pages/Privacy.vue')), 'privacy')
-	},
-	'/team': {
-		component: resolve => require.ensure([], () => resolve(require('./components/pages/Team.vue')), 'team')
-	},
-	'/news': {
-		component: resolve => require.ensure([], () => resolve(require('./components/pages/News.vue')), 'news')
-	},
-	'/about': {
-		component: resolve => require.ensure([], () => resolve(require('./components/pages/About.vue')), 'about')
-	},
-	'/u/:username': {
-		component: resolve => require.ensure([], () => resolve(require('./components/User/Show.vue')), 'show-user')
-	},
-	'/settings': {
-		component: resolve => require.ensure([], () => resolve(require('./components/User/Settings.vue')), 'settings'),
-		loginRequired: true
-	},
-	'/reset_password': {
-		component: resolve => require.ensure([], () => resolve(require('./components/User/ResetPassword.vue')), 'reset-password')
-	},
-	'/login': {
-		component: resolve => require.ensure([], () => resolve(require('./components/Modals/Login.vue')), 'login')
-	},
-	'/register': {
-		component: resolve => require.ensure([], () => resolve(require('./components/Modals/Register.vue')), 'register')
-	},
-	'/admin': {
-		component: resolve => require.ensure([], () => resolve(require('./components/pages/Admin.vue')), 'admin'),
-		adminRequired: true
-	},
-	'/admin/:page': {
-		component: resolve => require.ensure([], () => resolve(require('./components/pages/Admin.vue')), 'admin'),
-		adminRequired: true
-	},
-	'/official/:id': {
-		component: resolve => require.ensure([], () => resolve(require('./components/Station/Station.vue')), 'station'),
-		officialRequired: true
-	},
-	'/:id': {
-		component: resolve => require.ensure([], () => resolve(require('./components/Station/Station.vue')), 'station'),
-		officialRequired: true
-	},
-	'/community/:id': {
-		component: resolve => require.ensure([], () => resolve(require('./components/Station/Station.vue')), 'station'),
-		communityRequired: true
-	}
+new Vue({
+	router,
+	store,
+	el: "#root",
+	render: wrapper => wrapper(App)
 });
-
-router.start(App, 'body');

+ 0 - 8548
frontend/package-lock.json

@@ -1,8548 +0,0 @@
-{
-  "name": "musare-frontend",
-  "version": "0.0.0",
-  "lockfileVersion": 1,
-  "requires": true,
-  "dependencies": {
-    "abbrev": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
-      "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
-    },
-    "accepts": {
-      "version": "1.3.7",
-      "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz",
-      "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==",
-      "dev": true,
-      "requires": {
-        "mime-types": "~2.1.24",
-        "negotiator": "0.6.2"
-      }
-    },
-    "acorn": {
-      "version": "5.7.3",
-      "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz",
-      "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw=="
-    },
-    "acorn-jsx": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-3.0.1.tgz",
-      "integrity": "sha1-r9+UiPsezvyDSPb7IvRk4ypYs2s=",
-      "dev": true,
-      "requires": {
-        "acorn": "^3.0.4"
-      },
-      "dependencies": {
-        "acorn": {
-          "version": "3.3.0",
-          "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz",
-          "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=",
-          "dev": true
-        }
-      }
-    },
-    "ajv": {
-      "version": "6.10.1",
-      "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.1.tgz",
-      "integrity": "sha512-w1YQaVGNC6t2UCPjEawK/vo/dG8OOrVtUmhBT1uJJYxbl5kU2Tj3v6LGqBcsysN1yhuCStJCCA3GqdvKY8sqXQ==",
-      "requires": {
-        "fast-deep-equal": "^2.0.1",
-        "fast-json-stable-stringify": "^2.0.0",
-        "json-schema-traverse": "^0.4.1",
-        "uri-js": "^4.2.2"
-      }
-    },
-    "ajv-keywords": {
-      "version": "1.5.1",
-      "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-1.5.1.tgz",
-      "integrity": "sha1-MU3QpLM2j609/NxU7eYXG4htrzw=",
-      "dev": true
-    },
-    "align-text": {
-      "version": "0.1.4",
-      "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz",
-      "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=",
-      "dev": true,
-      "requires": {
-        "kind-of": "^3.0.2",
-        "longest": "^1.0.1",
-        "repeat-string": "^1.5.2"
-      }
-    },
-    "alphanum-sort": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz",
-      "integrity": "sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM=",
-      "dev": true
-    },
-    "amdefine": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz",
-      "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU="
-    },
-    "ansi-escapes": {
-      "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-1.4.0.tgz",
-      "integrity": "sha1-06ioOzGapneTZisT52HHkRQiMG4=",
-      "dev": true
-    },
-    "ansi-regex": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
-      "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
-    },
-    "ansi-styles": {
-      "version": "2.2.1",
-      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
-      "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4="
-    },
-    "anymatch": {
-      "version": "1.3.2",
-      "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz",
-      "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==",
-      "dev": true,
-      "requires": {
-        "micromatch": "^2.1.5",
-        "normalize-path": "^2.0.0"
-      }
-    },
-    "aproba": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
-      "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw=="
-    },
-    "are-we-there-yet": {
-      "version": "1.1.5",
-      "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz",
-      "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==",
-      "requires": {
-        "delegates": "^1.0.0",
-        "readable-stream": "^2.0.6"
-      }
-    },
-    "argparse": {
-      "version": "1.0.10",
-      "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
-      "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==",
-      "dev": true,
-      "requires": {
-        "sprintf-js": "~1.0.2"
-      }
-    },
-    "arr-diff": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz",
-      "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=",
-      "dev": true,
-      "requires": {
-        "arr-flatten": "^1.0.1"
-      }
-    },
-    "arr-flatten": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
-      "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==",
-      "dev": true
-    },
-    "arr-union": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz",
-      "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=",
-      "dev": true
-    },
-    "array-find-index": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz",
-      "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E="
-    },
-    "array-flatten": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
-      "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=",
-      "dev": true
-    },
-    "array-unique": {
-      "version": "0.2.1",
-      "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz",
-      "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=",
-      "dev": true
-    },
-    "asn1": {
-      "version": "0.2.4",
-      "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz",
-      "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==",
-      "requires": {
-        "safer-buffer": "~2.1.0"
-      }
-    },
-    "assert": {
-      "version": "1.5.0",
-      "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz",
-      "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==",
-      "dev": true,
-      "requires": {
-        "object-assign": "^4.1.1",
-        "util": "0.10.3"
-      },
-      "dependencies": {
-        "inherits": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz",
-          "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=",
-          "dev": true
-        },
-        "util": {
-          "version": "0.10.3",
-          "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz",
-          "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=",
-          "dev": true,
-          "requires": {
-            "inherits": "2.0.1"
-          }
-        }
-      }
-    },
-    "assert-plus": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
-      "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
-    },
-    "assign-symbols": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz",
-      "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=",
-      "dev": true
-    },
-    "ast-types": {
-      "version": "0.9.6",
-      "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.9.6.tgz",
-      "integrity": "sha1-ECyenpAF0+fjgpvwxPok7oYu6bk="
-    },
-    "async": {
-      "version": "2.6.2",
-      "resolved": "https://registry.npmjs.org/async/-/async-2.6.2.tgz",
-      "integrity": "sha512-H1qVYh1MYhEEFLsP97cVKqCGo7KfCyTt6uEWqsTBr9SO84oK9Uwbyd/yCW+6rKJLHksBNUVWZDAjfS+Ccx0Bbg==",
-      "dev": true,
-      "requires": {
-        "lodash": "^4.17.11"
-      }
-    },
-    "async-each": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz",
-      "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==",
-      "dev": true
-    },
-    "async-foreach": {
-      "version": "0.1.3",
-      "resolved": "https://registry.npmjs.org/async-foreach/-/async-foreach-0.1.3.tgz",
-      "integrity": "sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI="
-    },
-    "asynckit": {
-      "version": "0.4.0",
-      "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
-      "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
-    },
-    "atob": {
-      "version": "2.1.2",
-      "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
-      "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
-      "dev": true
-    },
-    "autoprefixer": {
-      "version": "6.7.7",
-      "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-6.7.7.tgz",
-      "integrity": "sha1-Hb0cg1ZY41zj+ZhAmdsAWFx4IBQ=",
-      "dev": true,
-      "requires": {
-        "browserslist": "^1.7.6",
-        "caniuse-db": "^1.0.30000634",
-        "normalize-range": "^0.1.2",
-        "num2fraction": "^1.2.2",
-        "postcss": "^5.2.16",
-        "postcss-value-parser": "^3.2.3"
-      }
-    },
-    "aws-sign2": {
-      "version": "0.7.0",
-      "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
-      "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg="
-    },
-    "aws4": {
-      "version": "1.8.0",
-      "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz",
-      "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ=="
-    },
-    "babel-code-frame": {
-      "version": "6.26.0",
-      "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
-      "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=",
-      "dev": true,
-      "requires": {
-        "chalk": "^1.1.3",
-        "esutils": "^2.0.2",
-        "js-tokens": "^3.0.2"
-      }
-    },
-    "babel-core": {
-      "version": "6.26.3",
-      "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.26.3.tgz",
-      "integrity": "sha512-6jyFLuDmeidKmUEb3NM+/yawG0M2bDZ9Z1qbZP59cyHLz8kYGKYwpJP0UwUKKUiTRNvxfLesJnTedqczP7cTDA==",
-      "dev": true,
-      "requires": {
-        "babel-code-frame": "^6.26.0",
-        "babel-generator": "^6.26.0",
-        "babel-helpers": "^6.24.1",
-        "babel-messages": "^6.23.0",
-        "babel-register": "^6.26.0",
-        "babel-runtime": "^6.26.0",
-        "babel-template": "^6.26.0",
-        "babel-traverse": "^6.26.0",
-        "babel-types": "^6.26.0",
-        "babylon": "^6.18.0",
-        "convert-source-map": "^1.5.1",
-        "debug": "^2.6.9",
-        "json5": "^0.5.1",
-        "lodash": "^4.17.4",
-        "minimatch": "^3.0.4",
-        "path-is-absolute": "^1.0.1",
-        "private": "^0.1.8",
-        "slash": "^1.0.0",
-        "source-map": "^0.5.7"
-      },
-      "dependencies": {
-        "source-map": {
-          "version": "0.5.7",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
-          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
-          "dev": true
-        }
-      }
-    },
-    "babel-generator": {
-      "version": "6.26.1",
-      "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.26.1.tgz",
-      "integrity": "sha512-HyfwY6ApZj7BYTcJURpM5tznulaBvyio7/0d4zFOeMPUmfxkCjHocCuoLa2SAGzBI8AREcH3eP3758F672DppA==",
-      "dev": true,
-      "requires": {
-        "babel-messages": "^6.23.0",
-        "babel-runtime": "^6.26.0",
-        "babel-types": "^6.26.0",
-        "detect-indent": "^4.0.0",
-        "jsesc": "^1.3.0",
-        "lodash": "^4.17.4",
-        "source-map": "^0.5.7",
-        "trim-right": "^1.0.1"
-      },
-      "dependencies": {
-        "source-map": {
-          "version": "0.5.7",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
-          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
-          "dev": true
-        }
-      }
-    },
-    "babel-helper-call-delegate": {
-      "version": "6.24.1",
-      "resolved": "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz",
-      "integrity": "sha1-7Oaqzdx25Bw0YfiL/Fdb0Nqi340=",
-      "dev": true,
-      "requires": {
-        "babel-helper-hoist-variables": "^6.24.1",
-        "babel-runtime": "^6.22.0",
-        "babel-traverse": "^6.24.1",
-        "babel-types": "^6.24.1"
-      }
-    },
-    "babel-helper-define-map": {
-      "version": "6.26.0",
-      "resolved": "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.26.0.tgz",
-      "integrity": "sha1-pfVtq0GiX5fstJjH66ypgZ+Vvl8=",
-      "dev": true,
-      "requires": {
-        "babel-helper-function-name": "^6.24.1",
-        "babel-runtime": "^6.26.0",
-        "babel-types": "^6.26.0",
-        "lodash": "^4.17.4"
-      }
-    },
-    "babel-helper-function-name": {
-      "version": "6.24.1",
-      "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz",
-      "integrity": "sha1-00dbjAPtmCQqJbSDUasYOZ01gKk=",
-      "dev": true,
-      "requires": {
-        "babel-helper-get-function-arity": "^6.24.1",
-        "babel-runtime": "^6.22.0",
-        "babel-template": "^6.24.1",
-        "babel-traverse": "^6.24.1",
-        "babel-types": "^6.24.1"
-      }
-    },
-    "babel-helper-get-function-arity": {
-      "version": "6.24.1",
-      "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz",
-      "integrity": "sha1-j3eCqpNAfEHTqlCQj4mwMbG2hT0=",
-      "dev": true,
-      "requires": {
-        "babel-runtime": "^6.22.0",
-        "babel-types": "^6.24.1"
-      }
-    },
-    "babel-helper-hoist-variables": {
-      "version": "6.24.1",
-      "resolved": "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz",
-      "integrity": "sha1-HssnaJydJVE+rbyZFKc/VAi+enY=",
-      "dev": true,
-      "requires": {
-        "babel-runtime": "^6.22.0",
-        "babel-types": "^6.24.1"
-      }
-    },
-    "babel-helper-optimise-call-expression": {
-      "version": "6.24.1",
-      "resolved": "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz",
-      "integrity": "sha1-96E0J7qfc/j0+pk8VKl4gtEkQlc=",
-      "dev": true,
-      "requires": {
-        "babel-runtime": "^6.22.0",
-        "babel-types": "^6.24.1"
-      }
-    },
-    "babel-helper-regex": {
-      "version": "6.26.0",
-      "resolved": "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.26.0.tgz",
-      "integrity": "sha1-MlxZ+QL4LyS3T6zu0DY5VPZJXnI=",
-      "dev": true,
-      "requires": {
-        "babel-runtime": "^6.26.0",
-        "babel-types": "^6.26.0",
-        "lodash": "^4.17.4"
-      }
-    },
-    "babel-helper-replace-supers": {
-      "version": "6.24.1",
-      "resolved": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz",
-      "integrity": "sha1-v22/5Dk40XNpohPKiov3S2qQqxo=",
-      "dev": true,
-      "requires": {
-        "babel-helper-optimise-call-expression": "^6.24.1",
-        "babel-messages": "^6.23.0",
-        "babel-runtime": "^6.22.0",
-        "babel-template": "^6.24.1",
-        "babel-traverse": "^6.24.1",
-        "babel-types": "^6.24.1"
-      }
-    },
-    "babel-helpers": {
-      "version": "6.24.1",
-      "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.24.1.tgz",
-      "integrity": "sha1-NHHenK7DiOXIUOWX5Yom3fN2ArI=",
-      "dev": true,
-      "requires": {
-        "babel-runtime": "^6.22.0",
-        "babel-template": "^6.24.1"
-      }
-    },
-    "babel-loader": {
-      "version": "6.4.1",
-      "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-6.4.1.tgz",
-      "integrity": "sha1-CzQRLVsHSKjc2/Uaz2+b1C1QuMo=",
-      "dev": true,
-      "requires": {
-        "find-cache-dir": "^0.1.1",
-        "loader-utils": "^0.2.16",
-        "mkdirp": "^0.5.1",
-        "object-assign": "^4.0.1"
-      }
-    },
-    "babel-messages": {
-      "version": "6.23.0",
-      "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz",
-      "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=",
-      "dev": true,
-      "requires": {
-        "babel-runtime": "^6.22.0"
-      }
-    },
-    "babel-plugin-check-es2015-constants": {
-      "version": "6.22.0",
-      "resolved": "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz",
-      "integrity": "sha1-NRV7EBQm/S/9PaP3XH0ekYNbv4o=",
-      "dev": true,
-      "requires": {
-        "babel-runtime": "^6.22.0"
-      }
-    },
-    "babel-plugin-transform-es2015-arrow-functions": {
-      "version": "6.22.0",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz",
-      "integrity": "sha1-RSaSy3EdX3ncf4XkQM5BufJE0iE=",
-      "dev": true,
-      "requires": {
-        "babel-runtime": "^6.22.0"
-      }
-    },
-    "babel-plugin-transform-es2015-block-scoped-functions": {
-      "version": "6.22.0",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz",
-      "integrity": "sha1-u8UbSflk1wy42OC5ToICRs46YUE=",
-      "dev": true,
-      "requires": {
-        "babel-runtime": "^6.22.0"
-      }
-    },
-    "babel-plugin-transform-es2015-block-scoping": {
-      "version": "6.26.0",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.26.0.tgz",
-      "integrity": "sha1-1w9SmcEwjQXBL0Y4E7CgnnOxiV8=",
-      "dev": true,
-      "requires": {
-        "babel-runtime": "^6.26.0",
-        "babel-template": "^6.26.0",
-        "babel-traverse": "^6.26.0",
-        "babel-types": "^6.26.0",
-        "lodash": "^4.17.4"
-      }
-    },
-    "babel-plugin-transform-es2015-classes": {
-      "version": "6.24.1",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz",
-      "integrity": "sha1-WkxYpQyclGHlZLSyo7+ryXolhNs=",
-      "dev": true,
-      "requires": {
-        "babel-helper-define-map": "^6.24.1",
-        "babel-helper-function-name": "^6.24.1",
-        "babel-helper-optimise-call-expression": "^6.24.1",
-        "babel-helper-replace-supers": "^6.24.1",
-        "babel-messages": "^6.23.0",
-        "babel-runtime": "^6.22.0",
-        "babel-template": "^6.24.1",
-        "babel-traverse": "^6.24.1",
-        "babel-types": "^6.24.1"
-      }
-    },
-    "babel-plugin-transform-es2015-computed-properties": {
-      "version": "6.24.1",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz",
-      "integrity": "sha1-b+Ko0WiV1WNPTNmZttNICjCBWbM=",
-      "dev": true,
-      "requires": {
-        "babel-runtime": "^6.22.0",
-        "babel-template": "^6.24.1"
-      }
-    },
-    "babel-plugin-transform-es2015-destructuring": {
-      "version": "6.23.0",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz",
-      "integrity": "sha1-mXux8auWf2gtKwh2/jWNYOdlxW0=",
-      "dev": true,
-      "requires": {
-        "babel-runtime": "^6.22.0"
-      }
-    },
-    "babel-plugin-transform-es2015-duplicate-keys": {
-      "version": "6.24.1",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz",
-      "integrity": "sha1-c+s9MQypaePvnskcU3QabxV2Qj4=",
-      "dev": true,
-      "requires": {
-        "babel-runtime": "^6.22.0",
-        "babel-types": "^6.24.1"
-      }
-    },
-    "babel-plugin-transform-es2015-for-of": {
-      "version": "6.23.0",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz",
-      "integrity": "sha1-9HyVsrYT3x0+zC/bdXNiPHUkhpE=",
-      "dev": true,
-      "requires": {
-        "babel-runtime": "^6.22.0"
-      }
-    },
-    "babel-plugin-transform-es2015-function-name": {
-      "version": "6.24.1",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz",
-      "integrity": "sha1-g0yJhTvDaxrw86TF26qU/Y6sqos=",
-      "dev": true,
-      "requires": {
-        "babel-helper-function-name": "^6.24.1",
-        "babel-runtime": "^6.22.0",
-        "babel-types": "^6.24.1"
-      }
-    },
-    "babel-plugin-transform-es2015-literals": {
-      "version": "6.22.0",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz",
-      "integrity": "sha1-T1SgLWzWbPkVKAAZox0xklN3yi4=",
-      "dev": true,
-      "requires": {
-        "babel-runtime": "^6.22.0"
-      }
-    },
-    "babel-plugin-transform-es2015-modules-amd": {
-      "version": "6.24.1",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz",
-      "integrity": "sha1-Oz5UAXI5hC1tGcMBHEvS8AoA0VQ=",
-      "dev": true,
-      "requires": {
-        "babel-plugin-transform-es2015-modules-commonjs": "^6.24.1",
-        "babel-runtime": "^6.22.0",
-        "babel-template": "^6.24.1"
-      }
-    },
-    "babel-plugin-transform-es2015-modules-commonjs": {
-      "version": "6.26.2",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.26.2.tgz",
-      "integrity": "sha512-CV9ROOHEdrjcwhIaJNBGMBCodN+1cfkwtM1SbUHmvyy35KGT7fohbpOxkE2uLz1o6odKK2Ck/tz47z+VqQfi9Q==",
-      "dev": true,
-      "requires": {
-        "babel-plugin-transform-strict-mode": "^6.24.1",
-        "babel-runtime": "^6.26.0",
-        "babel-template": "^6.26.0",
-        "babel-types": "^6.26.0"
-      }
-    },
-    "babel-plugin-transform-es2015-modules-systemjs": {
-      "version": "6.24.1",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz",
-      "integrity": "sha1-/4mhQrkRmpBhlfXxBuzzBdlAfSM=",
-      "dev": true,
-      "requires": {
-        "babel-helper-hoist-variables": "^6.24.1",
-        "babel-runtime": "^6.22.0",
-        "babel-template": "^6.24.1"
-      }
-    },
-    "babel-plugin-transform-es2015-modules-umd": {
-      "version": "6.24.1",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz",
-      "integrity": "sha1-rJl+YoXNGO1hdq22B9YCNErThGg=",
-      "dev": true,
-      "requires": {
-        "babel-plugin-transform-es2015-modules-amd": "^6.24.1",
-        "babel-runtime": "^6.22.0",
-        "babel-template": "^6.24.1"
-      }
-    },
-    "babel-plugin-transform-es2015-object-super": {
-      "version": "6.24.1",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz",
-      "integrity": "sha1-JM72muIcuDp/hgPa0CH1cusnj40=",
-      "dev": true,
-      "requires": {
-        "babel-helper-replace-supers": "^6.24.1",
-        "babel-runtime": "^6.22.0"
-      }
-    },
-    "babel-plugin-transform-es2015-parameters": {
-      "version": "6.24.1",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz",
-      "integrity": "sha1-V6w1GrScrxSpfNE7CfZv3wpiXys=",
-      "dev": true,
-      "requires": {
-        "babel-helper-call-delegate": "^6.24.1",
-        "babel-helper-get-function-arity": "^6.24.1",
-        "babel-runtime": "^6.22.0",
-        "babel-template": "^6.24.1",
-        "babel-traverse": "^6.24.1",
-        "babel-types": "^6.24.1"
-      }
-    },
-    "babel-plugin-transform-es2015-shorthand-properties": {
-      "version": "6.24.1",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz",
-      "integrity": "sha1-JPh11nIch2YbvZmkYi5R8U3jiqA=",
-      "dev": true,
-      "requires": {
-        "babel-runtime": "^6.22.0",
-        "babel-types": "^6.24.1"
-      }
-    },
-    "babel-plugin-transform-es2015-spread": {
-      "version": "6.22.0",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz",
-      "integrity": "sha1-1taKmfia7cRTbIGlQujdnxdG+NE=",
-      "dev": true,
-      "requires": {
-        "babel-runtime": "^6.22.0"
-      }
-    },
-    "babel-plugin-transform-es2015-sticky-regex": {
-      "version": "6.24.1",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz",
-      "integrity": "sha1-AMHNsaynERLN8M9hJsLta0V8zbw=",
-      "dev": true,
-      "requires": {
-        "babel-helper-regex": "^6.24.1",
-        "babel-runtime": "^6.22.0",
-        "babel-types": "^6.24.1"
-      }
-    },
-    "babel-plugin-transform-es2015-template-literals": {
-      "version": "6.22.0",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz",
-      "integrity": "sha1-qEs0UPfp+PH2g51taH2oS7EjbY0=",
-      "dev": true,
-      "requires": {
-        "babel-runtime": "^6.22.0"
-      }
-    },
-    "babel-plugin-transform-es2015-typeof-symbol": {
-      "version": "6.23.0",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz",
-      "integrity": "sha1-3sCfHN3/lLUqxz1QXITfWdzOs3I=",
-      "dev": true,
-      "requires": {
-        "babel-runtime": "^6.22.0"
-      }
-    },
-    "babel-plugin-transform-es2015-unicode-regex": {
-      "version": "6.24.1",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz",
-      "integrity": "sha1-04sS9C6nMj9yk4fxinxa4frrNek=",
-      "dev": true,
-      "requires": {
-        "babel-helper-regex": "^6.24.1",
-        "babel-runtime": "^6.22.0",
-        "regexpu-core": "^2.0.0"
-      }
-    },
-    "babel-plugin-transform-regenerator": {
-      "version": "6.26.0",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.26.0.tgz",
-      "integrity": "sha1-4HA2lvveJ/Cj78rPi03KL3s6jy8=",
-      "dev": true,
-      "requires": {
-        "regenerator-transform": "^0.10.0"
-      }
-    },
-    "babel-plugin-transform-runtime": {
-      "version": "6.23.0",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-runtime/-/babel-plugin-transform-runtime-6.23.0.tgz",
-      "integrity": "sha1-iEkNRGUC6puOfvsP4J7E2ZR5se4=",
-      "dev": true,
-      "requires": {
-        "babel-runtime": "^6.22.0"
-      }
-    },
-    "babel-plugin-transform-strict-mode": {
-      "version": "6.24.1",
-      "resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz",
-      "integrity": "sha1-1fr3qleKZbvlkc9e2uBKDGcCB1g=",
-      "dev": true,
-      "requires": {
-        "babel-runtime": "^6.22.0",
-        "babel-types": "^6.24.1"
-      }
-    },
-    "babel-preset-es2015": {
-      "version": "6.24.1",
-      "resolved": "https://registry.npmjs.org/babel-preset-es2015/-/babel-preset-es2015-6.24.1.tgz",
-      "integrity": "sha1-1EBQ1rwsn+6nAqrzjXJ6AhBTiTk=",
-      "dev": true,
-      "requires": {
-        "babel-plugin-check-es2015-constants": "^6.22.0",
-        "babel-plugin-transform-es2015-arrow-functions": "^6.22.0",
-        "babel-plugin-transform-es2015-block-scoped-functions": "^6.22.0",
-        "babel-plugin-transform-es2015-block-scoping": "^6.24.1",
-        "babel-plugin-transform-es2015-classes": "^6.24.1",
-        "babel-plugin-transform-es2015-computed-properties": "^6.24.1",
-        "babel-plugin-transform-es2015-destructuring": "^6.22.0",
-        "babel-plugin-transform-es2015-duplicate-keys": "^6.24.1",
-        "babel-plugin-transform-es2015-for-of": "^6.22.0",
-        "babel-plugin-transform-es2015-function-name": "^6.24.1",
-        "babel-plugin-transform-es2015-literals": "^6.22.0",
-        "babel-plugin-transform-es2015-modules-amd": "^6.24.1",
-        "babel-plugin-transform-es2015-modules-commonjs": "^6.24.1",
-        "babel-plugin-transform-es2015-modules-systemjs": "^6.24.1",
-        "babel-plugin-transform-es2015-modules-umd": "^6.24.1",
-        "babel-plugin-transform-es2015-object-super": "^6.24.1",
-        "babel-plugin-transform-es2015-parameters": "^6.24.1",
-        "babel-plugin-transform-es2015-shorthand-properties": "^6.24.1",
-        "babel-plugin-transform-es2015-spread": "^6.22.0",
-        "babel-plugin-transform-es2015-sticky-regex": "^6.24.1",
-        "babel-plugin-transform-es2015-template-literals": "^6.22.0",
-        "babel-plugin-transform-es2015-typeof-symbol": "^6.22.0",
-        "babel-plugin-transform-es2015-unicode-regex": "^6.24.1",
-        "babel-plugin-transform-regenerator": "^6.24.1"
-      }
-    },
-    "babel-register": {
-      "version": "6.26.0",
-      "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.26.0.tgz",
-      "integrity": "sha1-btAhFz4vy0htestFxgCahW9kcHE=",
-      "dev": true,
-      "requires": {
-        "babel-core": "^6.26.0",
-        "babel-runtime": "^6.26.0",
-        "core-js": "^2.5.0",
-        "home-or-tmp": "^2.0.0",
-        "lodash": "^4.17.4",
-        "mkdirp": "^0.5.1",
-        "source-map-support": "^0.4.15"
-      }
-    },
-    "babel-runtime": {
-      "version": "6.26.0",
-      "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
-      "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
-      "requires": {
-        "core-js": "^2.4.0",
-        "regenerator-runtime": "^0.11.0"
-      }
-    },
-    "babel-template": {
-      "version": "6.26.0",
-      "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.26.0.tgz",
-      "integrity": "sha1-3gPi0WOWsGn0bdn/+FIfsaDjXgI=",
-      "dev": true,
-      "requires": {
-        "babel-runtime": "^6.26.0",
-        "babel-traverse": "^6.26.0",
-        "babel-types": "^6.26.0",
-        "babylon": "^6.18.0",
-        "lodash": "^4.17.4"
-      }
-    },
-    "babel-traverse": {
-      "version": "6.26.0",
-      "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz",
-      "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=",
-      "dev": true,
-      "requires": {
-        "babel-code-frame": "^6.26.0",
-        "babel-messages": "^6.23.0",
-        "babel-runtime": "^6.26.0",
-        "babel-types": "^6.26.0",
-        "babylon": "^6.18.0",
-        "debug": "^2.6.8",
-        "globals": "^9.18.0",
-        "invariant": "^2.2.2",
-        "lodash": "^4.17.4"
-      }
-    },
-    "babel-types": {
-      "version": "6.26.0",
-      "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz",
-      "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=",
-      "dev": true,
-      "requires": {
-        "babel-runtime": "^6.26.0",
-        "esutils": "^2.0.2",
-        "lodash": "^4.17.4",
-        "to-fast-properties": "^1.0.3"
-      }
-    },
-    "babylon": {
-      "version": "6.18.0",
-      "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz",
-      "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==",
-      "dev": true
-    },
-    "balanced-match": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
-      "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
-    },
-    "base": {
-      "version": "0.11.2",
-      "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz",
-      "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==",
-      "dev": true,
-      "requires": {
-        "cache-base": "^1.0.1",
-        "class-utils": "^0.3.5",
-        "component-emitter": "^1.2.1",
-        "define-property": "^1.0.0",
-        "isobject": "^3.0.1",
-        "mixin-deep": "^1.2.0",
-        "pascalcase": "^0.1.1"
-      },
-      "dependencies": {
-        "define-property": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
-          "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
-          "dev": true,
-          "requires": {
-            "is-descriptor": "^1.0.0"
-          }
-        },
-        "is-accessor-descriptor": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
-          "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
-          "dev": true,
-          "requires": {
-            "kind-of": "^6.0.0"
-          }
-        },
-        "is-data-descriptor": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
-          "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
-          "dev": true,
-          "requires": {
-            "kind-of": "^6.0.0"
-          }
-        },
-        "is-descriptor": {
-          "version": "1.0.2",
-          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
-          "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
-          "dev": true,
-          "requires": {
-            "is-accessor-descriptor": "^1.0.0",
-            "is-data-descriptor": "^1.0.0",
-            "kind-of": "^6.0.2"
-          }
-        },
-        "isobject": {
-          "version": "3.0.1",
-          "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
-          "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
-          "dev": true
-        },
-        "kind-of": {
-          "version": "6.0.2",
-          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
-          "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
-          "dev": true
-        }
-      }
-    },
-    "base62": {
-      "version": "1.2.8",
-      "resolved": "https://registry.npmjs.org/base62/-/base62-1.2.8.tgz",
-      "integrity": "sha512-V6YHUbjLxN1ymqNLb1DPHoU1CpfdL7d2YTIp5W3U4hhoG4hhxNmsFDs66M9EXxBiSEke5Bt5dwdfMwwZF70iLA=="
-    },
-    "base64-js": {
-      "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.0.tgz",
-      "integrity": "sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==",
-      "dev": true
-    },
-    "batch": {
-      "version": "0.6.1",
-      "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz",
-      "integrity": "sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=",
-      "dev": true
-    },
-    "bcrypt-pbkdf": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz",
-      "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=",
-      "requires": {
-        "tweetnacl": "^0.14.3"
-      }
-    },
-    "big.js": {
-      "version": "3.2.0",
-      "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.2.0.tgz",
-      "integrity": "sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==",
-      "dev": true
-    },
-    "binary-extensions": {
-      "version": "1.13.1",
-      "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz",
-      "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==",
-      "dev": true
-    },
-    "block-stream": {
-      "version": "0.0.9",
-      "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz",
-      "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=",
-      "requires": {
-        "inherits": "~2.0.0"
-      }
-    },
-    "bluebird": {
-      "version": "3.5.5",
-      "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.5.tgz",
-      "integrity": "sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w==",
-      "dev": true
-    },
-    "body-parser": {
-      "version": "1.19.0",
-      "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.19.0.tgz",
-      "integrity": "sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==",
-      "dev": true,
-      "requires": {
-        "bytes": "3.1.0",
-        "content-type": "~1.0.4",
-        "debug": "2.6.9",
-        "depd": "~1.1.2",
-        "http-errors": "1.7.2",
-        "iconv-lite": "0.4.24",
-        "on-finished": "~2.3.0",
-        "qs": "6.7.0",
-        "raw-body": "2.4.0",
-        "type-is": "~1.6.17"
-      },
-      "dependencies": {
-        "bytes": {
-          "version": "3.1.0",
-          "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
-          "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==",
-          "dev": true
-        },
-        "qs": {
-          "version": "6.7.0",
-          "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
-          "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==",
-          "dev": true
-        }
-      }
-    },
-    "boolbase": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
-      "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=",
-      "dev": true
-    },
-    "brace-expansion": {
-      "version": "1.1.11",
-      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
-      "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
-      "requires": {
-        "balanced-match": "^1.0.0",
-        "concat-map": "0.0.1"
-      }
-    },
-    "braces": {
-      "version": "1.8.5",
-      "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz",
-      "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=",
-      "dev": true,
-      "requires": {
-        "expand-range": "^1.8.1",
-        "preserve": "^0.2.0",
-        "repeat-element": "^1.1.2"
-      }
-    },
-    "browserify-aes": {
-      "version": "0.4.0",
-      "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-0.4.0.tgz",
-      "integrity": "sha1-BnFJtmjfMcS1hTPgLQHoBthgjiw=",
-      "dev": true,
-      "requires": {
-        "inherits": "^2.0.1"
-      }
-    },
-    "browserify-zlib": {
-      "version": "0.1.4",
-      "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.1.4.tgz",
-      "integrity": "sha1-uzX4pRn2AOD6a4SFJByXnQFB+y0=",
-      "dev": true,
-      "requires": {
-        "pako": "~0.2.0"
-      }
-    },
-    "browserslist": {
-      "version": "1.7.7",
-      "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-1.7.7.tgz",
-      "integrity": "sha1-C9dnBCWL6CmyOYu1Dkti0aFmsLk=",
-      "dev": true,
-      "requires": {
-        "caniuse-db": "^1.0.30000639",
-        "electron-to-chromium": "^1.2.7"
-      }
-    },
-    "buffer": {
-      "version": "4.9.1",
-      "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz",
-      "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=",
-      "dev": true,
-      "requires": {
-        "base64-js": "^1.0.2",
-        "ieee754": "^1.1.4",
-        "isarray": "^1.0.0"
-      }
-    },
-    "buffer-from": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz",
-      "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==",
-      "dev": true
-    },
-    "builtin-status-codes": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz",
-      "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=",
-      "dev": true
-    },
-    "bytes": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz",
-      "integrity": "sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=",
-      "dev": true
-    },
-    "cache-base": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz",
-      "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==",
-      "dev": true,
-      "requires": {
-        "collection-visit": "^1.0.0",
-        "component-emitter": "^1.2.1",
-        "get-value": "^2.0.6",
-        "has-value": "^1.0.0",
-        "isobject": "^3.0.1",
-        "set-value": "^2.0.0",
-        "to-object-path": "^0.3.0",
-        "union-value": "^1.0.0",
-        "unset-value": "^1.0.0"
-      },
-      "dependencies": {
-        "isobject": {
-          "version": "3.0.1",
-          "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
-          "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
-          "dev": true
-        }
-      }
-    },
-    "caller-path": {
-      "version": "0.1.0",
-      "resolved": "https://registry.npmjs.org/caller-path/-/caller-path-0.1.0.tgz",
-      "integrity": "sha1-lAhe9jWB7NPaqSREqP6U6CV3dR8=",
-      "dev": true,
-      "requires": {
-        "callsites": "^0.2.0"
-      }
-    },
-    "callsites": {
-      "version": "0.2.0",
-      "resolved": "https://registry.npmjs.org/callsites/-/callsites-0.2.0.tgz",
-      "integrity": "sha1-r6uWJikQp/M8GaV3WCXGnzTjUMo=",
-      "dev": true
-    },
-    "camel-case": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz",
-      "integrity": "sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=",
-      "dev": true,
-      "requires": {
-        "no-case": "^2.2.0",
-        "upper-case": "^1.1.1"
-      }
-    },
-    "camelcase": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz",
-      "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8="
-    },
-    "camelcase-keys": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz",
-      "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=",
-      "requires": {
-        "camelcase": "^2.0.0",
-        "map-obj": "^1.0.0"
-      }
-    },
-    "caniuse-api": {
-      "version": "1.6.1",
-      "resolved": "https://registry.npmjs.org/caniuse-api/-/caniuse-api-1.6.1.tgz",
-      "integrity": "sha1-tTTnxzTE+B7F++isoq0kNUuWLGw=",
-      "dev": true,
-      "requires": {
-        "browserslist": "^1.3.6",
-        "caniuse-db": "^1.0.30000529",
-        "lodash.memoize": "^4.1.2",
-        "lodash.uniq": "^4.5.0"
-      }
-    },
-    "caniuse-db": {
-      "version": "1.0.30000983",
-      "resolved": "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30000983.tgz",
-      "integrity": "sha512-LS3aD+ti+fezwo8oN01l5vfZF9/CIN/4pxV5SeakHo5leudiHjE66rVHl+XqoCGw4GpO2u5ab6LOpftTfCN9cw==",
-      "dev": true
-    },
-    "caseless": {
-      "version": "0.12.0",
-      "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
-      "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
-    },
-    "center-align": {
-      "version": "0.1.3",
-      "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz",
-      "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=",
-      "dev": true,
-      "requires": {
-        "align-text": "^0.1.3",
-        "lazy-cache": "^1.0.3"
-      }
-    },
-    "chalk": {
-      "version": "1.1.3",
-      "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
-      "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
-      "requires": {
-        "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"
-      }
-    },
-    "change-case": {
-      "version": "3.0.2",
-      "resolved": "https://registry.npmjs.org/change-case/-/change-case-3.0.2.tgz",
-      "integrity": "sha512-Mww+SLF6MZ0U6kdg11algyKd5BARbyM4TbFBepwowYSR5ClfQGCGtxNXgykpN0uF/bstWeaGDT4JWaDh8zWAHA==",
-      "dev": true,
-      "requires": {
-        "camel-case": "^3.0.0",
-        "constant-case": "^2.0.0",
-        "dot-case": "^2.1.0",
-        "header-case": "^1.0.0",
-        "is-lower-case": "^1.1.0",
-        "is-upper-case": "^1.1.0",
-        "lower-case": "^1.1.1",
-        "lower-case-first": "^1.0.0",
-        "no-case": "^2.3.2",
-        "param-case": "^2.1.0",
-        "pascal-case": "^2.0.0",
-        "path-case": "^2.1.0",
-        "sentence-case": "^2.1.0",
-        "snake-case": "^2.1.0",
-        "swap-case": "^1.1.0",
-        "title-case": "^2.1.0",
-        "upper-case": "^1.1.1",
-        "upper-case-first": "^1.1.0"
-      }
-    },
-    "charenc": {
-      "version": "0.0.2",
-      "resolved": "https://registry.npmjs.org/charenc/-/charenc-0.0.2.tgz",
-      "integrity": "sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=",
-      "dev": true
-    },
-    "chart.js": {
-      "version": "2.8.0",
-      "resolved": "https://registry.npmjs.org/chart.js/-/chart.js-2.8.0.tgz",
-      "integrity": "sha512-Di3wUL4BFvqI5FB5K26aQ+hvWh8wnP9A3DWGvXHVkO13D3DSnaSsdZx29cXlEsYKVkn1E2az+ZYFS4t0zi8x0w==",
-      "requires": {
-        "chartjs-color": "^2.1.0",
-        "moment": "^2.10.2"
-      }
-    },
-    "chartjs-color": {
-      "version": "2.3.0",
-      "resolved": "https://registry.npmjs.org/chartjs-color/-/chartjs-color-2.3.0.tgz",
-      "integrity": "sha512-hEvVheqczsoHD+fZ+tfPUE+1+RbV6b+eksp2LwAhwRTVXEjCSEavvk+Hg3H6SZfGlPh/UfmWKGIvZbtobOEm3g==",
-      "requires": {
-        "chartjs-color-string": "^0.6.0",
-        "color-convert": "^0.5.3"
-      }
-    },
-    "chartjs-color-string": {
-      "version": "0.6.0",
-      "resolved": "https://registry.npmjs.org/chartjs-color-string/-/chartjs-color-string-0.6.0.tgz",
-      "integrity": "sha512-TIB5OKn1hPJvO7JcteW4WY/63v6KwEdt6udfnDE9iCAZgy+V4SrbSxoIbTw/xkUIapjEI4ExGtD0+6D3KyFd7A==",
-      "requires": {
-        "color-name": "^1.0.0"
-      }
-    },
-    "chokidar": {
-      "version": "1.7.0",
-      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz",
-      "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=",
-      "dev": true,
-      "requires": {
-        "anymatch": "^1.3.0",
-        "async-each": "^1.0.0",
-        "fsevents": "^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"
-      }
-    },
-    "circular-json": {
-      "version": "0.3.3",
-      "resolved": "https://registry.npmjs.org/circular-json/-/circular-json-0.3.3.tgz",
-      "integrity": "sha512-UZK3NBx2Mca+b5LsG7bY183pHWt5Y1xts4P3Pz7ENTwGVnJOUWbRb3ocjvX7hx9tq/yTAdclXm9sZ38gNuem4A==",
-      "dev": true
-    },
-    "clap": {
-      "version": "1.2.3",
-      "resolved": "https://registry.npmjs.org/clap/-/clap-1.2.3.tgz",
-      "integrity": "sha512-4CoL/A3hf90V3VIEjeuhSvlGFEHKzOz+Wfc2IVZc+FaUgU0ZQafJTP49fvnULipOPcAfqhyI2duwQyns6xqjYA==",
-      "dev": true,
-      "requires": {
-        "chalk": "^1.1.3"
-      }
-    },
-    "class-utils": {
-      "version": "0.3.6",
-      "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz",
-      "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==",
-      "dev": true,
-      "requires": {
-        "arr-union": "^3.1.0",
-        "define-property": "^0.2.5",
-        "isobject": "^3.0.0",
-        "static-extend": "^0.1.1"
-      },
-      "dependencies": {
-        "define-property": {
-          "version": "0.2.5",
-          "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
-          "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
-          "dev": true,
-          "requires": {
-            "is-descriptor": "^0.1.0"
-          }
-        },
-        "isobject": {
-          "version": "3.0.1",
-          "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
-          "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
-          "dev": true
-        }
-      }
-    },
-    "clean-css": {
-      "version": "4.2.1",
-      "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.1.tgz",
-      "integrity": "sha512-4ZxI6dy4lrY6FHzfiy1aEOXgu4LIsW2MhwG0VBKdcoGoH/XLFgaHSdLTGr4O8Be6A8r3MOphEiI8Gc1n0ecf3g==",
-      "dev": true,
-      "requires": {
-        "source-map": "~0.6.0"
-      },
-      "dependencies": {
-        "source-map": {
-          "version": "0.6.1",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
-          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
-          "dev": true
-        }
-      }
-    },
-    "cli-cursor": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-1.0.2.tgz",
-      "integrity": "sha1-ZNo/fValRBLll5S9Ytw1KV6PKYc=",
-      "dev": true,
-      "requires": {
-        "restore-cursor": "^1.0.1"
-      }
-    },
-    "cli-width": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-2.2.0.tgz",
-      "integrity": "sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=",
-      "dev": true
-    },
-    "cliui": {
-      "version": "3.2.0",
-      "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz",
-      "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=",
-      "requires": {
-        "string-width": "^1.0.1",
-        "strip-ansi": "^3.0.1",
-        "wrap-ansi": "^2.0.0"
-      }
-    },
-    "clone": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
-      "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=",
-      "dev": true
-    },
-    "co": {
-      "version": "4.6.0",
-      "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
-      "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=",
-      "dev": true
-    },
-    "coa": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/coa/-/coa-1.0.4.tgz",
-      "integrity": "sha1-qe8VNmDWqGqL3sAomlxoTSF0Mv0=",
-      "dev": true,
-      "requires": {
-        "q": "^1.1.2"
-      }
-    },
-    "code-point-at": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
-      "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c="
-    },
-    "collection-visit": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz",
-      "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=",
-      "dev": true,
-      "requires": {
-        "map-visit": "^1.0.0",
-        "object-visit": "^1.0.0"
-      }
-    },
-    "color": {
-      "version": "0.11.4",
-      "resolved": "https://registry.npmjs.org/color/-/color-0.11.4.tgz",
-      "integrity": "sha1-bXtcdPtl6EHNSHkq0e1eB7kE12Q=",
-      "dev": true,
-      "requires": {
-        "clone": "^1.0.2",
-        "color-convert": "^1.3.0",
-        "color-string": "^0.3.0"
-      },
-      "dependencies": {
-        "color-convert": {
-          "version": "1.9.3",
-          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
-          "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
-          "dev": true,
-          "requires": {
-            "color-name": "1.1.3"
-          }
-        },
-        "color-name": {
-          "version": "1.1.3",
-          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-          "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
-          "dev": true
-        }
-      }
-    },
-    "color-convert": {
-      "version": "0.5.3",
-      "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-0.5.3.tgz",
-      "integrity": "sha1-vbbGnOZg+t/+CwAHzER+G59ygr0="
-    },
-    "color-name": {
-      "version": "1.1.4",
-      "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
-      "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
-    },
-    "color-string": {
-      "version": "0.3.0",
-      "resolved": "https://registry.npmjs.org/color-string/-/color-string-0.3.0.tgz",
-      "integrity": "sha1-J9RvtnAlxcL6JZk7+/V55HhBuZE=",
-      "dev": true,
-      "requires": {
-        "color-name": "^1.0.0"
-      }
-    },
-    "colormin": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/colormin/-/colormin-1.1.2.tgz",
-      "integrity": "sha1-6i90IKcrlogaOKrlnsEkpvcpgTM=",
-      "dev": true,
-      "requires": {
-        "color": "^0.11.0",
-        "css-color-names": "0.0.4",
-        "has": "^1.0.1"
-      }
-    },
-    "colors": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz",
-      "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=",
-      "dev": true
-    },
-    "combined-stream": {
-      "version": "1.0.8",
-      "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
-      "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
-      "requires": {
-        "delayed-stream": "~1.0.0"
-      }
-    },
-    "commander": {
-      "version": "2.20.0",
-      "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz",
-      "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ=="
-    },
-    "commondir": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz",
-      "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=",
-      "dev": true
-    },
-    "commoner": {
-      "version": "0.10.8",
-      "resolved": "https://registry.npmjs.org/commoner/-/commoner-0.10.8.tgz",
-      "integrity": "sha1-NPw2cs0kOT6LtH5wyqApOBH08sU=",
-      "requires": {
-        "commander": "^2.5.0",
-        "detective": "^4.3.1",
-        "glob": "^5.0.15",
-        "graceful-fs": "^4.1.2",
-        "iconv-lite": "^0.4.5",
-        "mkdirp": "^0.5.0",
-        "private": "^0.1.6",
-        "q": "^1.1.2",
-        "recast": "^0.11.17"
-      },
-      "dependencies": {
-        "glob": {
-          "version": "5.0.15",
-          "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz",
-          "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=",
-          "requires": {
-            "inflight": "^1.0.4",
-            "inherits": "2",
-            "minimatch": "2 || 3",
-            "once": "^1.3.0",
-            "path-is-absolute": "^1.0.0"
-          }
-        }
-      }
-    },
-    "component-emitter": {
-      "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz",
-      "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==",
-      "dev": true
-    },
-    "compressible": {
-      "version": "2.0.17",
-      "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.17.tgz",
-      "integrity": "sha512-BGHeLCK1GV7j1bSmQQAi26X+GgWcTjLr/0tzSvMCl3LH1w1IJ4PFSPoV5316b30cneTziC+B1a+3OjoSUcQYmw==",
-      "dev": true,
-      "requires": {
-        "mime-db": ">= 1.40.0 < 2"
-      }
-    },
-    "compression": {
-      "version": "1.7.4",
-      "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz",
-      "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==",
-      "dev": true,
-      "requires": {
-        "accepts": "~1.3.5",
-        "bytes": "3.0.0",
-        "compressible": "~2.0.16",
-        "debug": "2.6.9",
-        "on-headers": "~1.0.2",
-        "safe-buffer": "5.1.2",
-        "vary": "~1.1.2"
-      }
-    },
-    "concat-map": {
-      "version": "0.0.1",
-      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
-      "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
-    },
-    "concat-stream": {
-      "version": "1.6.2",
-      "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz",
-      "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==",
-      "dev": true,
-      "requires": {
-        "buffer-from": "^1.0.0",
-        "inherits": "^2.0.3",
-        "readable-stream": "^2.2.2",
-        "typedarray": "^0.0.6"
-      }
-    },
-    "connect-history-api-fallback": {
-      "version": "1.6.0",
-      "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz",
-      "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==",
-      "dev": true
-    },
-    "console-browserify": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz",
-      "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=",
-      "dev": true,
-      "requires": {
-        "date-now": "^0.1.4"
-      }
-    },
-    "console-control-strings": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
-      "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4="
-    },
-    "consolidate": {
-      "version": "0.14.5",
-      "resolved": "https://registry.npmjs.org/consolidate/-/consolidate-0.14.5.tgz",
-      "integrity": "sha1-WiUEe8dvcwcmZ8jLUsmJiI9JTGM=",
-      "dev": true,
-      "requires": {
-        "bluebird": "^3.1.1"
-      }
-    },
-    "constant-case": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/constant-case/-/constant-case-2.0.0.tgz",
-      "integrity": "sha1-QXV2TTidP6nI7NKRhu1gBSQ7akY=",
-      "dev": true,
-      "requires": {
-        "snake-case": "^2.1.0",
-        "upper-case": "^1.1.1"
-      }
-    },
-    "constants-browserify": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz",
-      "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=",
-      "dev": true
-    },
-    "content-disposition": {
-      "version": "0.5.3",
-      "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz",
-      "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==",
-      "dev": true,
-      "requires": {
-        "safe-buffer": "5.1.2"
-      }
-    },
-    "content-type": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz",
-      "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==",
-      "dev": true
-    },
-    "convert-source-map": {
-      "version": "1.6.0",
-      "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz",
-      "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==",
-      "dev": true,
-      "requires": {
-        "safe-buffer": "~5.1.1"
-      }
-    },
-    "cookie": {
-      "version": "0.4.0",
-      "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.0.tgz",
-      "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==",
-      "dev": true
-    },
-    "cookie-signature": {
-      "version": "1.0.6",
-      "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
-      "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=",
-      "dev": true
-    },
-    "copy-descriptor": {
-      "version": "0.1.1",
-      "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz",
-      "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=",
-      "dev": true
-    },
-    "core-js": {
-      "version": "2.6.9",
-      "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.6.9.tgz",
-      "integrity": "sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A=="
-    },
-    "core-util-is": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
-      "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
-    },
-    "cross-spawn": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-3.0.1.tgz",
-      "integrity": "sha1-ElYDfsufDF9549bvE14wdwGEuYI=",
-      "requires": {
-        "lru-cache": "^4.0.1",
-        "which": "^1.2.9"
-      }
-    },
-    "crypt": {
-      "version": "0.0.2",
-      "resolved": "https://registry.npmjs.org/crypt/-/crypt-0.0.2.tgz",
-      "integrity": "sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=",
-      "dev": true
-    },
-    "crypto-browserify": {
-      "version": "3.3.0",
-      "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.3.0.tgz",
-      "integrity": "sha1-ufx1u0oO1h3PHNXa6W6zDJw+UGw=",
-      "dev": true,
-      "requires": {
-        "browserify-aes": "0.4.0",
-        "pbkdf2-compat": "2.0.1",
-        "ripemd160": "0.2.0",
-        "sha.js": "2.2.6"
-      }
-    },
-    "css-color-names": {
-      "version": "0.0.4",
-      "resolved": "https://registry.npmjs.org/css-color-names/-/css-color-names-0.0.4.tgz",
-      "integrity": "sha1-gIrcLnnPhHOAabZGyyDsJ762KeA=",
-      "dev": true
-    },
-    "css-loader": {
-      "version": "0.25.0",
-      "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-0.25.0.tgz",
-      "integrity": "sha1-w/68jOKPTINXa2sTcH9H+Qw5AiM=",
-      "dev": true,
-      "requires": {
-        "babel-code-frame": "^6.11.0",
-        "css-selector-tokenizer": "^0.6.0",
-        "cssnano": ">=2.6.1 <4",
-        "loader-utils": "~0.2.2",
-        "lodash.camelcase": "^3.0.1",
-        "object-assign": "^4.0.1",
-        "postcss": "^5.0.6",
-        "postcss-modules-extract-imports": "^1.0.0",
-        "postcss-modules-local-by-default": "^1.0.1",
-        "postcss-modules-scope": "^1.0.0",
-        "postcss-modules-values": "^1.1.0",
-        "source-list-map": "^0.1.4"
-      }
-    },
-    "css-select": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz",
-      "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=",
-      "dev": true,
-      "requires": {
-        "boolbase": "~1.0.0",
-        "css-what": "2.1",
-        "domutils": "1.5.1",
-        "nth-check": "~1.0.1"
-      },
-      "dependencies": {
-        "domutils": {
-          "version": "1.5.1",
-          "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz",
-          "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=",
-          "dev": true,
-          "requires": {
-            "dom-serializer": "0",
-            "domelementtype": "1"
-          }
-        }
-      }
-    },
-    "css-selector-tokenizer": {
-      "version": "0.6.0",
-      "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.6.0.tgz",
-      "integrity": "sha1-ZEX1gseTDSQdzFAHpD1vy48HMVI=",
-      "dev": true,
-      "requires": {
-        "cssesc": "^0.1.0",
-        "fastparse": "^1.1.1",
-        "regexpu-core": "^1.0.0"
-      },
-      "dependencies": {
-        "regexpu-core": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-1.0.0.tgz",
-          "integrity": "sha1-hqdj9Y7k18L2sQLkdkBQ3n7ZDGs=",
-          "dev": true,
-          "requires": {
-            "regenerate": "^1.2.1",
-            "regjsgen": "^0.2.0",
-            "regjsparser": "^0.1.4"
-          }
-        }
-      }
-    },
-    "css-what": {
-      "version": "2.1.3",
-      "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.3.tgz",
-      "integrity": "sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==",
-      "dev": true
-    },
-    "cssesc": {
-      "version": "0.1.0",
-      "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-0.1.0.tgz",
-      "integrity": "sha1-yBSQPkViM3GgR3tAEJqq++6t27Q=",
-      "dev": true
-    },
-    "cssnano": {
-      "version": "3.10.0",
-      "resolved": "https://registry.npmjs.org/cssnano/-/cssnano-3.10.0.tgz",
-      "integrity": "sha1-Tzj2zqK5sX+gFJDyPx3GjqZcHDg=",
-      "dev": true,
-      "requires": {
-        "autoprefixer": "^6.3.1",
-        "decamelize": "^1.1.2",
-        "defined": "^1.0.0",
-        "has": "^1.0.1",
-        "object-assign": "^4.0.1",
-        "postcss": "^5.0.14",
-        "postcss-calc": "^5.2.0",
-        "postcss-colormin": "^2.1.8",
-        "postcss-convert-values": "^2.3.4",
-        "postcss-discard-comments": "^2.0.4",
-        "postcss-discard-duplicates": "^2.0.1",
-        "postcss-discard-empty": "^2.0.1",
-        "postcss-discard-overridden": "^0.1.1",
-        "postcss-discard-unused": "^2.2.1",
-        "postcss-filter-plugins": "^2.0.0",
-        "postcss-merge-idents": "^2.1.5",
-        "postcss-merge-longhand": "^2.0.1",
-        "postcss-merge-rules": "^2.0.3",
-        "postcss-minify-font-values": "^1.0.2",
-        "postcss-minify-gradients": "^1.0.1",
-        "postcss-minify-params": "^1.0.4",
-        "postcss-minify-selectors": "^2.0.4",
-        "postcss-normalize-charset": "^1.1.0",
-        "postcss-normalize-url": "^3.0.7",
-        "postcss-ordered-values": "^2.1.0",
-        "postcss-reduce-idents": "^2.2.2",
-        "postcss-reduce-initial": "^1.0.0",
-        "postcss-reduce-transforms": "^1.0.3",
-        "postcss-svgo": "^2.1.1",
-        "postcss-unique-selectors": "^2.0.2",
-        "postcss-value-parser": "^3.2.3",
-        "postcss-zindex": "^2.0.1"
-      }
-    },
-    "csso": {
-      "version": "2.3.2",
-      "resolved": "https://registry.npmjs.org/csso/-/csso-2.3.2.tgz",
-      "integrity": "sha1-3dUsWHAz9J6Utx/FVWnyUuj/X4U=",
-      "dev": true,
-      "requires": {
-        "clap": "^1.0.9",
-        "source-map": "^0.5.3"
-      },
-      "dependencies": {
-        "source-map": {
-          "version": "0.5.7",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
-          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
-          "dev": true
-        }
-      }
-    },
-    "currently-unhandled": {
-      "version": "0.4.1",
-      "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz",
-      "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=",
-      "requires": {
-        "array-find-index": "^1.0.1"
-      }
-    },
-    "d": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz",
-      "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==",
-      "dev": true,
-      "requires": {
-        "es5-ext": "^0.10.50",
-        "type": "^1.0.1"
-      }
-    },
-    "dashdash": {
-      "version": "1.14.1",
-      "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
-      "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
-      "requires": {
-        "assert-plus": "^1.0.0"
-      }
-    },
-    "date-now": {
-      "version": "0.1.4",
-      "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz",
-      "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=",
-      "dev": true
-    },
-    "de-indent": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz",
-      "integrity": "sha1-sgOOhG3DO6pXlhKNCAS0VbjB4h0=",
-      "dev": true
-    },
-    "debug": {
-      "version": "2.6.9",
-      "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
-      "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
-      "dev": true,
-      "requires": {
-        "ms": "2.0.0"
-      }
-    },
-    "decamelize": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
-      "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA="
-    },
-    "decode-uri-component": {
-      "version": "0.2.0",
-      "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
-      "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=",
-      "dev": true
-    },
-    "deep-is": {
-      "version": "0.1.3",
-      "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
-      "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=",
-      "dev": true
-    },
-    "define-property": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz",
-      "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==",
-      "dev": true,
-      "requires": {
-        "is-descriptor": "^1.0.2",
-        "isobject": "^3.0.1"
-      },
-      "dependencies": {
-        "is-accessor-descriptor": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
-          "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
-          "dev": true,
-          "requires": {
-            "kind-of": "^6.0.0"
-          }
-        },
-        "is-data-descriptor": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
-          "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
-          "dev": true,
-          "requires": {
-            "kind-of": "^6.0.0"
-          }
-        },
-        "is-descriptor": {
-          "version": "1.0.2",
-          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
-          "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
-          "dev": true,
-          "requires": {
-            "is-accessor-descriptor": "^1.0.0",
-            "is-data-descriptor": "^1.0.0",
-            "kind-of": "^6.0.2"
-          }
-        },
-        "isobject": {
-          "version": "3.0.1",
-          "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
-          "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
-          "dev": true
-        },
-        "kind-of": {
-          "version": "6.0.2",
-          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
-          "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
-          "dev": true
-        }
-      }
-    },
-    "defined": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz",
-      "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM="
-    },
-    "delayed-stream": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
-      "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
-    },
-    "delegates": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
-      "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o="
-    },
-    "depd": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz",
-      "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=",
-      "dev": true
-    },
-    "destroy": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
-      "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=",
-      "dev": true
-    },
-    "detect-indent": {
-      "version": "4.0.0",
-      "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz",
-      "integrity": "sha1-920GQ1LN9Docts5hnE7jqUdd4gg=",
-      "dev": true,
-      "requires": {
-        "repeating": "^2.0.0"
-      }
-    },
-    "detective": {
-      "version": "4.7.1",
-      "resolved": "https://registry.npmjs.org/detective/-/detective-4.7.1.tgz",
-      "integrity": "sha512-H6PmeeUcZloWtdt4DAkFyzFL94arpHr3NOwwmVILFiy+9Qd4JTxxXrzfyGk/lmct2qVGBwTSwSXagqu2BxmWig==",
-      "requires": {
-        "acorn": "^5.2.1",
-        "defined": "^1.0.0"
-      }
-    },
-    "doctrine": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz",
-      "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==",
-      "dev": true,
-      "requires": {
-        "esutils": "^2.0.2"
-      }
-    },
-    "dom-converter": {
-      "version": "0.2.0",
-      "resolved": "https://registry.npmjs.org/dom-converter/-/dom-converter-0.2.0.tgz",
-      "integrity": "sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==",
-      "dev": true,
-      "requires": {
-        "utila": "~0.4"
-      }
-    },
-    "dom-serializer": {
-      "version": "0.1.1",
-      "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.1.tgz",
-      "integrity": "sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==",
-      "dev": true,
-      "requires": {
-        "domelementtype": "^1.3.0",
-        "entities": "^1.1.1"
-      }
-    },
-    "domain-browser": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz",
-      "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==",
-      "dev": true
-    },
-    "domelementtype": {
-      "version": "1.3.1",
-      "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz",
-      "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==",
-      "dev": true
-    },
-    "domhandler": {
-      "version": "2.4.2",
-      "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.4.2.tgz",
-      "integrity": "sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==",
-      "dev": true,
-      "requires": {
-        "domelementtype": "1"
-      }
-    },
-    "domutils": {
-      "version": "1.7.0",
-      "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.7.0.tgz",
-      "integrity": "sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==",
-      "dev": true,
-      "requires": {
-        "dom-serializer": "0",
-        "domelementtype": "1"
-      }
-    },
-    "dot-case": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-2.1.1.tgz",
-      "integrity": "sha1-NNzzf1Co6TwrO8qLt/uRVcfaO+4=",
-      "dev": true,
-      "requires": {
-        "no-case": "^2.2.0"
-      }
-    },
-    "ecc-jsbn": {
-      "version": "0.1.2",
-      "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz",
-      "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=",
-      "requires": {
-        "jsbn": "~0.1.0",
-        "safer-buffer": "^2.1.0"
-      }
-    },
-    "ee-first": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
-      "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=",
-      "dev": true
-    },
-    "electron-to-chromium": {
-      "version": "1.3.191",
-      "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.191.tgz",
-      "integrity": "sha512-jasjtY5RUy/TOyiUYM2fb4BDaPZfm6CXRFeJDMfFsXYADGxUN49RBqtgB7EL2RmJXeIRUk9lM1U6A5yk2YJMPQ==",
-      "dev": true
-    },
-    "emojis-list": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz",
-      "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=",
-      "dev": true
-    },
-    "encodeurl": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
-      "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=",
-      "dev": true
-    },
-    "enhanced-resolve": {
-      "version": "0.9.1",
-      "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-0.9.1.tgz",
-      "integrity": "sha1-TW5omzcl+GCQknzMhs2fFjW4ni4=",
-      "dev": true,
-      "requires": {
-        "graceful-fs": "^4.1.2",
-        "memory-fs": "^0.2.0",
-        "tapable": "^0.1.8"
-      },
-      "dependencies": {
-        "memory-fs": {
-          "version": "0.2.0",
-          "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.2.0.tgz",
-          "integrity": "sha1-8rslNovBIeORwlIN6Slpyu4KApA=",
-          "dev": true
-        }
-      }
-    },
-    "entities": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz",
-      "integrity": "sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==",
-      "dev": true
-    },
-    "envify": {
-      "version": "3.4.1",
-      "resolved": "https://registry.npmjs.org/envify/-/envify-3.4.1.tgz",
-      "integrity": "sha1-1xIjKejfFoi6dxsSUBkXyc5cvOg=",
-      "requires": {
-        "jstransform": "^11.0.3",
-        "through": "~2.3.4"
-      }
-    },
-    "errno": {
-      "version": "0.1.7",
-      "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz",
-      "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==",
-      "dev": true,
-      "requires": {
-        "prr": "~1.0.1"
-      }
-    },
-    "error-ex": {
-      "version": "1.3.2",
-      "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz",
-      "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==",
-      "requires": {
-        "is-arrayish": "^0.2.1"
-      }
-    },
-    "es5-ext": {
-      "version": "0.10.50",
-      "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.50.tgz",
-      "integrity": "sha512-KMzZTPBkeQV/JcSQhI5/z6d9VWJ3EnQ194USTUwIYZ2ZbpN8+SGXQKt1h68EX44+qt+Fzr8DO17vnxrw7c3agw==",
-      "dev": true,
-      "requires": {
-        "es6-iterator": "~2.0.3",
-        "es6-symbol": "~3.1.1",
-        "next-tick": "^1.0.0"
-      }
-    },
-    "es6-iterator": {
-      "version": "2.0.3",
-      "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz",
-      "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=",
-      "dev": true,
-      "requires": {
-        "d": "1",
-        "es5-ext": "^0.10.35",
-        "es6-symbol": "^3.1.1"
-      }
-    },
-    "es6-map": {
-      "version": "0.1.5",
-      "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz",
-      "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=",
-      "dev": true,
-      "requires": {
-        "d": "1",
-        "es5-ext": "~0.10.14",
-        "es6-iterator": "~2.0.1",
-        "es6-set": "~0.1.5",
-        "es6-symbol": "~3.1.1",
-        "event-emitter": "~0.3.5"
-      }
-    },
-    "es6-set": {
-      "version": "0.1.5",
-      "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz",
-      "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=",
-      "dev": true,
-      "requires": {
-        "d": "1",
-        "es5-ext": "~0.10.14",
-        "es6-iterator": "~2.0.1",
-        "es6-symbol": "3.1.1",
-        "event-emitter": "~0.3.5"
-      }
-    },
-    "es6-symbol": {
-      "version": "3.1.1",
-      "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz",
-      "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=",
-      "dev": true,
-      "requires": {
-        "d": "1",
-        "es5-ext": "~0.10.14"
-      }
-    },
-    "es6-templates": {
-      "version": "0.2.3",
-      "resolved": "https://registry.npmjs.org/es6-templates/-/es6-templates-0.2.3.tgz",
-      "integrity": "sha1-XLmsn7He1usSOTQrgdeSu7QHjuQ=",
-      "dev": true,
-      "requires": {
-        "recast": "~0.11.12",
-        "through": "~2.3.6"
-      }
-    },
-    "es6-weak-map": {
-      "version": "2.0.3",
-      "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz",
-      "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==",
-      "dev": true,
-      "requires": {
-        "d": "1",
-        "es5-ext": "^0.10.46",
-        "es6-iterator": "^2.0.3",
-        "es6-symbol": "^3.1.1"
-      }
-    },
-    "escape-html": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
-      "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=",
-      "dev": true
-    },
-    "escape-string-regexp": {
-      "version": "1.0.5",
-      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
-      "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
-    },
-    "escope": {
-      "version": "3.6.0",
-      "resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz",
-      "integrity": "sha1-4Bl16BJ4GhY6ba392AOY3GTIicM=",
-      "dev": true,
-      "requires": {
-        "es6-map": "^0.1.3",
-        "es6-weak-map": "^2.0.1",
-        "esrecurse": "^4.1.0",
-        "estraverse": "^4.1.1"
-      }
-    },
-    "eslint": {
-      "version": "3.19.0",
-      "resolved": "https://registry.npmjs.org/eslint/-/eslint-3.19.0.tgz",
-      "integrity": "sha1-yPxiAcf0DdCJQbh8CFdnOGpnmsw=",
-      "dev": true,
-      "requires": {
-        "babel-code-frame": "^6.16.0",
-        "chalk": "^1.1.3",
-        "concat-stream": "^1.5.2",
-        "debug": "^2.1.1",
-        "doctrine": "^2.0.0",
-        "escope": "^3.6.0",
-        "espree": "^3.4.0",
-        "esquery": "^1.0.0",
-        "estraverse": "^4.2.0",
-        "esutils": "^2.0.2",
-        "file-entry-cache": "^2.0.0",
-        "glob": "^7.0.3",
-        "globals": "^9.14.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": "~2.0.1",
-        "table": "^3.7.8",
-        "text-table": "~0.2.0",
-        "user-home": "^2.0.0"
-      },
-      "dependencies": {
-        "strip-bom": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
-          "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=",
-          "dev": true
-        }
-      }
-    },
-    "eslint-loader": {
-      "version": "1.9.0",
-      "resolved": "https://registry.npmjs.org/eslint-loader/-/eslint-loader-1.9.0.tgz",
-      "integrity": "sha512-40aN976qSNPyb9ejTqjEthZITpls1SVKtwguahmH1dzGCwQU/vySE+xX33VZmD8csU0ahVNCtFlsPgKqRBiqgg==",
-      "dev": true,
-      "requires": {
-        "loader-fs-cache": "^1.0.0",
-        "loader-utils": "^1.0.2",
-        "object-assign": "^4.0.1",
-        "object-hash": "^1.1.4",
-        "rimraf": "^2.6.1"
-      },
-      "dependencies": {
-        "big.js": {
-          "version": "5.2.2",
-          "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
-          "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==",
-          "dev": true
-        },
-        "json5": {
-          "version": "1.0.1",
-          "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
-          "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
-          "dev": true,
-          "requires": {
-            "minimist": "^1.2.0"
-          }
-        },
-        "loader-utils": {
-          "version": "1.2.3",
-          "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz",
-          "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==",
-          "dev": true,
-          "requires": {
-            "big.js": "^5.2.2",
-            "emojis-list": "^2.0.0",
-            "json5": "^1.0.1"
-          }
-        }
-      }
-    },
-    "eslint-plugin-html": {
-      "version": "1.7.0",
-      "resolved": "https://registry.npmjs.org/eslint-plugin-html/-/eslint-plugin-html-1.7.0.tgz",
-      "integrity": "sha1-KlsDiE2NVq35rZhk6cA2SA+2Kck=",
-      "dev": true,
-      "requires": {
-        "htmlparser2": "^3.8.2"
-      }
-    },
-    "espree": {
-      "version": "3.5.4",
-      "resolved": "https://registry.npmjs.org/espree/-/espree-3.5.4.tgz",
-      "integrity": "sha512-yAcIQxtmMiB/jL32dzEp2enBeidsB7xWPLNiw3IIkpVds1P+h7qF9YwJq1yUNzp2OKXgAprs4F61ih66UsoD1A==",
-      "dev": true,
-      "requires": {
-        "acorn": "^5.5.0",
-        "acorn-jsx": "^3.0.0"
-      }
-    },
-    "esprima-fb": {
-      "version": "15001.1.0-dev-harmony-fb",
-      "resolved": "https://registry.npmjs.org/esprima-fb/-/esprima-fb-15001.1.0-dev-harmony-fb.tgz",
-      "integrity": "sha1-MKlHMDxrjV6VW+4rmbHSMyBqaQE="
-    },
-    "esquery": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.0.1.tgz",
-      "integrity": "sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==",
-      "dev": true,
-      "requires": {
-        "estraverse": "^4.0.0"
-      }
-    },
-    "esrecurse": {
-      "version": "4.2.1",
-      "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz",
-      "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==",
-      "dev": true,
-      "requires": {
-        "estraverse": "^4.1.0"
-      }
-    },
-    "estraverse": {
-      "version": "4.2.0",
-      "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz",
-      "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=",
-      "dev": true
-    },
-    "esutils": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
-      "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=",
-      "dev": true
-    },
-    "etag": {
-      "version": "1.8.1",
-      "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
-      "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=",
-      "dev": true
-    },
-    "event-emitter": {
-      "version": "0.3.5",
-      "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz",
-      "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=",
-      "dev": true,
-      "requires": {
-        "d": "1",
-        "es5-ext": "~0.10.14"
-      }
-    },
-    "eventemitter3": {
-      "version": "3.1.2",
-      "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-3.1.2.tgz",
-      "integrity": "sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==",
-      "dev": true
-    },
-    "events": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz",
-      "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=",
-      "dev": true
-    },
-    "eventsource": {
-      "version": "1.0.7",
-      "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-1.0.7.tgz",
-      "integrity": "sha512-4Ln17+vVT0k8aWq+t/bF5arcS3EpT9gYtW66EPacdj/mAFevznsnyoHLPy2BA8gbIQeIHoPsvwmfBftfcG//BQ==",
-      "dev": true,
-      "requires": {
-        "original": "^1.0.0"
-      }
-    },
-    "exit-hook": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-1.1.1.tgz",
-      "integrity": "sha1-8FyiM7SMBdVP/wd2XfhQfpXAL/g=",
-      "dev": true
-    },
-    "expand-brackets": {
-      "version": "0.1.5",
-      "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz",
-      "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=",
-      "dev": true,
-      "requires": {
-        "is-posix-bracket": "^0.1.0"
-      }
-    },
-    "expand-range": {
-      "version": "1.8.2",
-      "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz",
-      "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=",
-      "dev": true,
-      "requires": {
-        "fill-range": "^2.1.0"
-      }
-    },
-    "express": {
-      "version": "4.17.1",
-      "resolved": "https://registry.npmjs.org/express/-/express-4.17.1.tgz",
-      "integrity": "sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==",
-      "dev": true,
-      "requires": {
-        "accepts": "~1.3.7",
-        "array-flatten": "1.1.1",
-        "body-parser": "1.19.0",
-        "content-disposition": "0.5.3",
-        "content-type": "~1.0.4",
-        "cookie": "0.4.0",
-        "cookie-signature": "1.0.6",
-        "debug": "2.6.9",
-        "depd": "~1.1.2",
-        "encodeurl": "~1.0.2",
-        "escape-html": "~1.0.3",
-        "etag": "~1.8.1",
-        "finalhandler": "~1.1.2",
-        "fresh": "0.5.2",
-        "merge-descriptors": "1.0.1",
-        "methods": "~1.1.2",
-        "on-finished": "~2.3.0",
-        "parseurl": "~1.3.3",
-        "path-to-regexp": "0.1.7",
-        "proxy-addr": "~2.0.5",
-        "qs": "6.7.0",
-        "range-parser": "~1.2.1",
-        "safe-buffer": "5.1.2",
-        "send": "0.17.1",
-        "serve-static": "1.14.1",
-        "setprototypeof": "1.1.1",
-        "statuses": "~1.5.0",
-        "type-is": "~1.6.18",
-        "utils-merge": "1.0.1",
-        "vary": "~1.1.2"
-      },
-      "dependencies": {
-        "qs": {
-          "version": "6.7.0",
-          "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz",
-          "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==",
-          "dev": true
-        }
-      }
-    },
-    "extend": {
-      "version": "3.0.2",
-      "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
-      "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g=="
-    },
-    "extend-shallow": {
-      "version": "3.0.2",
-      "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
-      "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=",
-      "dev": true,
-      "requires": {
-        "assign-symbols": "^1.0.0",
-        "is-extendable": "^1.0.1"
-      },
-      "dependencies": {
-        "is-extendable": {
-          "version": "1.0.1",
-          "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
-          "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
-          "dev": true,
-          "requires": {
-            "is-plain-object": "^2.0.4"
-          }
-        }
-      }
-    },
-    "extglob": {
-      "version": "0.3.2",
-      "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz",
-      "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=",
-      "dev": true,
-      "requires": {
-        "is-extglob": "^1.0.0"
-      }
-    },
-    "extsprintf": {
-      "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
-      "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU="
-    },
-    "fast-deep-equal": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz",
-      "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk="
-    },
-    "fast-json-stable-stringify": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",
-      "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I="
-    },
-    "fast-levenshtein": {
-      "version": "2.0.6",
-      "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
-      "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
-      "dev": true
-    },
-    "fastparse": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz",
-      "integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==",
-      "dev": true
-    },
-    "faye-websocket": {
-      "version": "0.10.0",
-      "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz",
-      "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=",
-      "dev": true,
-      "requires": {
-        "websocket-driver": ">=0.5.1"
-      }
-    },
-    "figures": {
-      "version": "1.7.0",
-      "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz",
-      "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=",
-      "dev": true,
-      "requires": {
-        "escape-string-regexp": "^1.0.5",
-        "object-assign": "^4.1.0"
-      }
-    },
-    "file-entry-cache": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-2.0.0.tgz",
-      "integrity": "sha1-w5KZDD5oR4PYOLjISkXYoEhFg2E=",
-      "dev": true,
-      "requires": {
-        "flat-cache": "^1.2.1",
-        "object-assign": "^4.0.1"
-      }
-    },
-    "filename-regex": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz",
-      "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=",
-      "dev": true
-    },
-    "fill-range": {
-      "version": "2.2.4",
-      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz",
-      "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==",
-      "dev": true,
-      "requires": {
-        "is-number": "^2.1.0",
-        "isobject": "^2.0.0",
-        "randomatic": "^3.0.0",
-        "repeat-element": "^1.1.2",
-        "repeat-string": "^1.5.2"
-      }
-    },
-    "finalhandler": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz",
-      "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==",
-      "dev": true,
-      "requires": {
-        "debug": "2.6.9",
-        "encodeurl": "~1.0.2",
-        "escape-html": "~1.0.3",
-        "on-finished": "~2.3.0",
-        "parseurl": "~1.3.3",
-        "statuses": "~1.5.0",
-        "unpipe": "~1.0.0"
-      }
-    },
-    "find-cache-dir": {
-      "version": "0.1.1",
-      "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-0.1.1.tgz",
-      "integrity": "sha1-yN765XyKUqinhPnjHFfHQumToLk=",
-      "dev": true,
-      "requires": {
-        "commondir": "^1.0.1",
-        "mkdirp": "^0.5.1",
-        "pkg-dir": "^1.0.0"
-      }
-    },
-    "find-up": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz",
-      "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=",
-      "requires": {
-        "path-exists": "^2.0.0",
-        "pinkie-promise": "^2.0.0"
-      }
-    },
-    "flat-cache": {
-      "version": "1.3.4",
-      "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-1.3.4.tgz",
-      "integrity": "sha512-VwyB3Lkgacfik2vhqR4uv2rvebqmDvFu4jlN/C1RzWoJEo8I7z4Q404oiqYCkq41mni8EzQnm95emU9seckwtg==",
-      "dev": true,
-      "requires": {
-        "circular-json": "^0.3.1",
-        "graceful-fs": "^4.1.2",
-        "rimraf": "~2.6.2",
-        "write": "^0.2.1"
-      }
-    },
-    "flatten": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/flatten/-/flatten-1.0.2.tgz",
-      "integrity": "sha1-2uRqnXj74lKSJYzB54CkHZXAN4I=",
-      "dev": true
-    },
-    "follow-redirects": {
-      "version": "1.7.0",
-      "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.7.0.tgz",
-      "integrity": "sha512-m/pZQy4Gj287eNy94nivy5wchN3Kp+Q5WgUPNy5lJSZ3sgkVKSYV/ZChMAQVIgx1SqfZ2zBZtPA2YlXIWxxJOQ==",
-      "dev": true,
-      "requires": {
-        "debug": "^3.2.6"
-      },
-      "dependencies": {
-        "debug": {
-          "version": "3.2.6",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
-          "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
-          "dev": true,
-          "requires": {
-            "ms": "^2.1.1"
-          }
-        },
-        "ms": {
-          "version": "2.1.2",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-          "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
-          "dev": true
-        }
-      }
-    },
-    "for-in": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
-      "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=",
-      "dev": true
-    },
-    "for-own": {
-      "version": "0.1.5",
-      "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz",
-      "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=",
-      "dev": true,
-      "requires": {
-        "for-in": "^1.0.1"
-      }
-    },
-    "forever-agent": {
-      "version": "0.6.1",
-      "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
-      "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE="
-    },
-    "form-data": {
-      "version": "2.3.3",
-      "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz",
-      "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==",
-      "requires": {
-        "asynckit": "^0.4.0",
-        "combined-stream": "^1.0.6",
-        "mime-types": "^2.1.12"
-      }
-    },
-    "forwarded": {
-      "version": "0.1.2",
-      "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.2.tgz",
-      "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=",
-      "dev": true
-    },
-    "fragment-cache": {
-      "version": "0.2.1",
-      "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz",
-      "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=",
-      "dev": true,
-      "requires": {
-        "map-cache": "^0.2.2"
-      }
-    },
-    "fresh": {
-      "version": "0.5.2",
-      "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
-      "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=",
-      "dev": true
-    },
-    "fs.realpath": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
-      "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
-    },
-    "fsevents": {
-      "version": "1.2.9",
-      "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz",
-      "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==",
-      "dev": true,
-      "optional": true,
-      "requires": {
-        "nan": "^2.12.1",
-        "node-pre-gyp": "^0.12.0"
-      },
-      "dependencies": {
-        "abbrev": {
-          "version": "1.1.1",
-          "bundled": true,
-          "dev": true,
-          "optional": true
-        },
-        "ansi-regex": {
-          "version": "2.1.1",
-          "bundled": true,
-          "dev": true,
-          "optional": true
-        },
-        "aproba": {
-          "version": "1.2.0",
-          "bundled": true,
-          "dev": true,
-          "optional": true
-        },
-        "are-we-there-yet": {
-          "version": "1.1.5",
-          "bundled": true,
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "delegates": "^1.0.0",
-            "readable-stream": "^2.0.6"
-          }
-        },
-        "balanced-match": {
-          "version": "1.0.0",
-          "bundled": true,
-          "dev": true,
-          "optional": true
-        },
-        "brace-expansion": {
-          "version": "1.1.11",
-          "bundled": true,
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "balanced-match": "^1.0.0",
-            "concat-map": "0.0.1"
-          }
-        },
-        "chownr": {
-          "version": "1.1.1",
-          "bundled": true,
-          "dev": true,
-          "optional": true
-        },
-        "code-point-at": {
-          "version": "1.1.0",
-          "bundled": true,
-          "dev": true,
-          "optional": true
-        },
-        "concat-map": {
-          "version": "0.0.1",
-          "bundled": true,
-          "dev": true,
-          "optional": true
-        },
-        "console-control-strings": {
-          "version": "1.1.0",
-          "bundled": true,
-          "dev": true,
-          "optional": true
-        },
-        "core-util-is": {
-          "version": "1.0.2",
-          "bundled": true,
-          "dev": true,
-          "optional": true
-        },
-        "debug": {
-          "version": "4.1.1",
-          "bundled": true,
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "ms": "^2.1.1"
-          }
-        },
-        "deep-extend": {
-          "version": "0.6.0",
-          "bundled": true,
-          "dev": true,
-          "optional": true
-        },
-        "delegates": {
-          "version": "1.0.0",
-          "bundled": true,
-          "dev": true,
-          "optional": true
-        },
-        "detect-libc": {
-          "version": "1.0.3",
-          "bundled": true,
-          "dev": true,
-          "optional": true
-        },
-        "fs-minipass": {
-          "version": "1.2.5",
-          "bundled": true,
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "minipass": "^2.2.1"
-          }
-        },
-        "fs.realpath": {
-          "version": "1.0.0",
-          "bundled": true,
-          "dev": true,
-          "optional": true
-        },
-        "gauge": {
-          "version": "2.7.4",
-          "bundled": true,
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "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",
-            "wide-align": "^1.1.0"
-          }
-        },
-        "glob": {
-          "version": "7.1.3",
-          "bundled": true,
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "fs.realpath": "^1.0.0",
-            "inflight": "^1.0.4",
-            "inherits": "2",
-            "minimatch": "^3.0.4",
-            "once": "^1.3.0",
-            "path-is-absolute": "^1.0.0"
-          }
-        },
-        "has-unicode": {
-          "version": "2.0.1",
-          "bundled": true,
-          "dev": true,
-          "optional": true
-        },
-        "iconv-lite": {
-          "version": "0.4.24",
-          "bundled": true,
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "safer-buffer": ">= 2.1.2 < 3"
-          }
-        },
-        "ignore-walk": {
-          "version": "3.0.1",
-          "bundled": true,
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "minimatch": "^3.0.4"
-          }
-        },
-        "inflight": {
-          "version": "1.0.6",
-          "bundled": true,
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "once": "^1.3.0",
-            "wrappy": "1"
-          }
-        },
-        "inherits": {
-          "version": "2.0.3",
-          "bundled": true,
-          "dev": true,
-          "optional": true
-        },
-        "ini": {
-          "version": "1.3.5",
-          "bundled": true,
-          "dev": true,
-          "optional": true
-        },
-        "is-fullwidth-code-point": {
-          "version": "1.0.0",
-          "bundled": true,
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "number-is-nan": "^1.0.0"
-          }
-        },
-        "isarray": {
-          "version": "1.0.0",
-          "bundled": true,
-          "dev": true,
-          "optional": true
-        },
-        "minimatch": {
-          "version": "3.0.4",
-          "bundled": true,
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "brace-expansion": "^1.1.7"
-          }
-        },
-        "minimist": {
-          "version": "0.0.8",
-          "bundled": true,
-          "dev": true,
-          "optional": true
-        },
-        "minipass": {
-          "version": "2.3.5",
-          "bundled": true,
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "safe-buffer": "^5.1.2",
-            "yallist": "^3.0.0"
-          }
-        },
-        "minizlib": {
-          "version": "1.2.1",
-          "bundled": true,
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "minipass": "^2.2.1"
-          }
-        },
-        "mkdirp": {
-          "version": "0.5.1",
-          "bundled": true,
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "minimist": "0.0.8"
-          }
-        },
-        "ms": {
-          "version": "2.1.1",
-          "bundled": true,
-          "dev": true,
-          "optional": true
-        },
-        "needle": {
-          "version": "2.3.0",
-          "bundled": true,
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "debug": "^4.1.0",
-            "iconv-lite": "^0.4.4",
-            "sax": "^1.2.4"
-          }
-        },
-        "node-pre-gyp": {
-          "version": "0.12.0",
-          "bundled": true,
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "detect-libc": "^1.0.2",
-            "mkdirp": "^0.5.1",
-            "needle": "^2.2.1",
-            "nopt": "^4.0.1",
-            "npm-packlist": "^1.1.6",
-            "npmlog": "^4.0.2",
-            "rc": "^1.2.7",
-            "rimraf": "^2.6.1",
-            "semver": "^5.3.0",
-            "tar": "^4"
-          }
-        },
-        "nopt": {
-          "version": "4.0.1",
-          "bundled": true,
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "abbrev": "1",
-            "osenv": "^0.1.4"
-          }
-        },
-        "npm-bundled": {
-          "version": "1.0.6",
-          "bundled": true,
-          "dev": true,
-          "optional": true
-        },
-        "npm-packlist": {
-          "version": "1.4.1",
-          "bundled": true,
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "ignore-walk": "^3.0.1",
-            "npm-bundled": "^1.0.1"
-          }
-        },
-        "npmlog": {
-          "version": "4.1.2",
-          "bundled": true,
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "are-we-there-yet": "~1.1.2",
-            "console-control-strings": "~1.1.0",
-            "gauge": "~2.7.3",
-            "set-blocking": "~2.0.0"
-          }
-        },
-        "number-is-nan": {
-          "version": "1.0.1",
-          "bundled": true,
-          "dev": true,
-          "optional": true
-        },
-        "object-assign": {
-          "version": "4.1.1",
-          "bundled": true,
-          "dev": true,
-          "optional": true
-        },
-        "once": {
-          "version": "1.4.0",
-          "bundled": true,
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "wrappy": "1"
-          }
-        },
-        "os-homedir": {
-          "version": "1.0.2",
-          "bundled": true,
-          "dev": true,
-          "optional": true
-        },
-        "os-tmpdir": {
-          "version": "1.0.2",
-          "bundled": true,
-          "dev": true,
-          "optional": true
-        },
-        "osenv": {
-          "version": "0.1.5",
-          "bundled": true,
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "os-homedir": "^1.0.0",
-            "os-tmpdir": "^1.0.0"
-          }
-        },
-        "path-is-absolute": {
-          "version": "1.0.1",
-          "bundled": true,
-          "dev": true,
-          "optional": true
-        },
-        "process-nextick-args": {
-          "version": "2.0.0",
-          "bundled": true,
-          "dev": true,
-          "optional": true
-        },
-        "rc": {
-          "version": "1.2.8",
-          "bundled": true,
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "deep-extend": "^0.6.0",
-            "ini": "~1.3.0",
-            "minimist": "^1.2.0",
-            "strip-json-comments": "~2.0.1"
-          },
-          "dependencies": {
-            "minimist": {
-              "version": "1.2.0",
-              "bundled": true,
-              "dev": true,
-              "optional": true
-            }
-          }
-        },
-        "readable-stream": {
-          "version": "2.3.6",
-          "bundled": true,
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "core-util-is": "~1.0.0",
-            "inherits": "~2.0.3",
-            "isarray": "~1.0.0",
-            "process-nextick-args": "~2.0.0",
-            "safe-buffer": "~5.1.1",
-            "string_decoder": "~1.1.1",
-            "util-deprecate": "~1.0.1"
-          }
-        },
-        "rimraf": {
-          "version": "2.6.3",
-          "bundled": true,
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "glob": "^7.1.3"
-          }
-        },
-        "safe-buffer": {
-          "version": "5.1.2",
-          "bundled": true,
-          "dev": true,
-          "optional": true
-        },
-        "safer-buffer": {
-          "version": "2.1.2",
-          "bundled": true,
-          "dev": true,
-          "optional": true
-        },
-        "sax": {
-          "version": "1.2.4",
-          "bundled": true,
-          "dev": true,
-          "optional": true
-        },
-        "semver": {
-          "version": "5.7.0",
-          "bundled": true,
-          "dev": true,
-          "optional": true
-        },
-        "set-blocking": {
-          "version": "2.0.0",
-          "bundled": true,
-          "dev": true,
-          "optional": true
-        },
-        "signal-exit": {
-          "version": "3.0.2",
-          "bundled": true,
-          "dev": true,
-          "optional": true
-        },
-        "string-width": {
-          "version": "1.0.2",
-          "bundled": true,
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "code-point-at": "^1.0.0",
-            "is-fullwidth-code-point": "^1.0.0",
-            "strip-ansi": "^3.0.0"
-          }
-        },
-        "string_decoder": {
-          "version": "1.1.1",
-          "bundled": true,
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "safe-buffer": "~5.1.0"
-          }
-        },
-        "strip-ansi": {
-          "version": "3.0.1",
-          "bundled": true,
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "ansi-regex": "^2.0.0"
-          }
-        },
-        "strip-json-comments": {
-          "version": "2.0.1",
-          "bundled": true,
-          "dev": true,
-          "optional": true
-        },
-        "tar": {
-          "version": "4.4.8",
-          "bundled": true,
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "chownr": "^1.1.1",
-            "fs-minipass": "^1.2.5",
-            "minipass": "^2.3.4",
-            "minizlib": "^1.1.1",
-            "mkdirp": "^0.5.0",
-            "safe-buffer": "^5.1.2",
-            "yallist": "^3.0.2"
-          }
-        },
-        "util-deprecate": {
-          "version": "1.0.2",
-          "bundled": true,
-          "dev": true,
-          "optional": true
-        },
-        "wide-align": {
-          "version": "1.1.3",
-          "bundled": true,
-          "dev": true,
-          "optional": true,
-          "requires": {
-            "string-width": "^1.0.2 || 2"
-          }
-        },
-        "wrappy": {
-          "version": "1.0.2",
-          "bundled": true,
-          "dev": true,
-          "optional": true
-        },
-        "yallist": {
-          "version": "3.0.3",
-          "bundled": true,
-          "dev": true,
-          "optional": true
-        }
-      }
-    },
-    "fstream": {
-      "version": "1.0.12",
-      "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz",
-      "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==",
-      "requires": {
-        "graceful-fs": "^4.1.2",
-        "inherits": "~2.0.0",
-        "mkdirp": ">=0.5 0",
-        "rimraf": "2"
-      }
-    },
-    "function-bind": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
-      "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==",
-      "dev": true
-    },
-    "gauge": {
-      "version": "2.7.4",
-      "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
-      "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
-      "requires": {
-        "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",
-        "wide-align": "^1.1.0"
-      }
-    },
-    "gaze": {
-      "version": "1.1.3",
-      "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz",
-      "integrity": "sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==",
-      "requires": {
-        "globule": "^1.0.0"
-      }
-    },
-    "generate-function": {
-      "version": "2.3.1",
-      "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz",
-      "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==",
-      "dev": true,
-      "requires": {
-        "is-property": "^1.0.2"
-      }
-    },
-    "generate-object-property": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz",
-      "integrity": "sha1-nA4cQDCM6AT0eDYYuTf6iPmdUNA=",
-      "dev": true,
-      "requires": {
-        "is-property": "^1.0.0"
-      }
-    },
-    "get-caller-file": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz",
-      "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w=="
-    },
-    "get-stdin": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz",
-      "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4="
-    },
-    "get-value": {
-      "version": "2.0.6",
-      "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz",
-      "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=",
-      "dev": true
-    },
-    "getpass": {
-      "version": "0.1.7",
-      "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
-      "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
-      "requires": {
-        "assert-plus": "^1.0.0"
-      }
-    },
-    "glob": {
-      "version": "7.1.4",
-      "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz",
-      "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==",
-      "requires": {
-        "fs.realpath": "^1.0.0",
-        "inflight": "^1.0.4",
-        "inherits": "2",
-        "minimatch": "^3.0.4",
-        "once": "^1.3.0",
-        "path-is-absolute": "^1.0.0"
-      }
-    },
-    "glob-base": {
-      "version": "0.3.0",
-      "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz",
-      "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=",
-      "dev": true,
-      "requires": {
-        "glob-parent": "^2.0.0",
-        "is-glob": "^2.0.0"
-      }
-    },
-    "glob-parent": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz",
-      "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=",
-      "dev": true,
-      "requires": {
-        "is-glob": "^2.0.0"
-      }
-    },
-    "globals": {
-      "version": "9.18.0",
-      "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz",
-      "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==",
-      "dev": true
-    },
-    "globule": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/globule/-/globule-1.2.1.tgz",
-      "integrity": "sha512-g7QtgWF4uYSL5/dn71WxubOrS7JVGCnFPEnoeChJmBnyR9Mw8nGoEwOgJL/RC2Te0WhbsEUCejfH8SZNJ+adYQ==",
-      "requires": {
-        "glob": "~7.1.1",
-        "lodash": "~4.17.10",
-        "minimatch": "~3.0.2"
-      }
-    },
-    "graceful-fs": {
-      "version": "4.2.0",
-      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.0.tgz",
-      "integrity": "sha512-jpSvDPV4Cq/bgtpndIWbI5hmYxhQGHPC4d4cqBPb4DLniCfhJokdXhwhaDuLBGLQdvvRum/UiX6ECVIPvDXqdg=="
-    },
-    "graceful-readlink": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz",
-      "integrity": "sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=",
-      "dev": true
-    },
-    "har-schema": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
-      "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI="
-    },
-    "har-validator": {
-      "version": "5.1.3",
-      "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz",
-      "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==",
-      "requires": {
-        "ajv": "^6.5.5",
-        "har-schema": "^2.0.0"
-      }
-    },
-    "has": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz",
-      "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==",
-      "dev": true,
-      "requires": {
-        "function-bind": "^1.1.1"
-      }
-    },
-    "has-ansi": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
-      "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
-      "requires": {
-        "ansi-regex": "^2.0.0"
-      }
-    },
-    "has-flag": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
-      "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
-      "dev": true
-    },
-    "has-unicode": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
-      "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk="
-    },
-    "has-value": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz",
-      "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=",
-      "dev": true,
-      "requires": {
-        "get-value": "^2.0.6",
-        "has-values": "^1.0.0",
-        "isobject": "^3.0.0"
-      },
-      "dependencies": {
-        "isobject": {
-          "version": "3.0.1",
-          "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
-          "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
-          "dev": true
-        }
-      }
-    },
-    "has-values": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz",
-      "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=",
-      "dev": true,
-      "requires": {
-        "is-number": "^3.0.0",
-        "kind-of": "^4.0.0"
-      },
-      "dependencies": {
-        "is-number": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
-          "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
-          "dev": true,
-          "requires": {
-            "kind-of": "^3.0.2"
-          },
-          "dependencies": {
-            "kind-of": {
-              "version": "3.2.2",
-              "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
-              "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
-              "dev": true,
-              "requires": {
-                "is-buffer": "^1.1.5"
-              }
-            }
-          }
-        },
-        "kind-of": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz",
-          "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=",
-          "dev": true,
-          "requires": {
-            "is-buffer": "^1.1.5"
-          }
-        }
-      }
-    },
-    "hash-sum": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/hash-sum/-/hash-sum-1.0.2.tgz",
-      "integrity": "sha1-M7QHd3VMZDJXPBIMw4CLvRDUfwQ=",
-      "dev": true
-    },
-    "he": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
-      "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
-      "dev": true
-    },
-    "header-case": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/header-case/-/header-case-1.0.1.tgz",
-      "integrity": "sha1-lTWXMZfBRLCWE81l0xfvGZY70C0=",
-      "dev": true,
-      "requires": {
-        "no-case": "^2.2.0",
-        "upper-case": "^1.1.3"
-      }
-    },
-    "home-or-tmp": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz",
-      "integrity": "sha1-42w/LSyufXRqhX440Y1fMqeILbg=",
-      "dev": true,
-      "requires": {
-        "os-homedir": "^1.0.0",
-        "os-tmpdir": "^1.0.1"
-      }
-    },
-    "hosted-git-info": {
-      "version": "2.7.1",
-      "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz",
-      "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w=="
-    },
-    "html-comment-regex": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/html-comment-regex/-/html-comment-regex-1.1.2.tgz",
-      "integrity": "sha512-P+M65QY2JQ5Y0G9KKdlDpo0zK+/OHptU5AaBwUfAIDJZk1MYf32Frm84EcOytfJE0t5JvkAnKlmjsXDnWzCJmQ==",
-      "dev": true
-    },
-    "html-minifier": {
-      "version": "3.5.21",
-      "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-3.5.21.tgz",
-      "integrity": "sha512-LKUKwuJDhxNa3uf/LPR/KVjm/l3rBqtYeCOAekvG8F1vItxMUpueGd94i/asDDr8/1u7InxzFA5EeGjhhG5mMA==",
-      "dev": true,
-      "requires": {
-        "camel-case": "3.0.x",
-        "clean-css": "4.2.x",
-        "commander": "2.17.x",
-        "he": "1.2.x",
-        "param-case": "2.1.x",
-        "relateurl": "0.2.x",
-        "uglify-js": "3.4.x"
-      },
-      "dependencies": {
-        "commander": {
-          "version": "2.17.1",
-          "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz",
-          "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==",
-          "dev": true
-        }
-      }
-    },
-    "html-webpack-plugin": {
-      "version": "2.30.1",
-      "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-2.30.1.tgz",
-      "integrity": "sha1-f5xCG36pHsRg9WUn1430hO51N9U=",
-      "dev": true,
-      "requires": {
-        "bluebird": "^3.4.7",
-        "html-minifier": "^3.2.3",
-        "loader-utils": "^0.2.16",
-        "lodash": "^4.17.3",
-        "pretty-error": "^2.0.2",
-        "toposort": "^1.0.0"
-      }
-    },
-    "htmlparser2": {
-      "version": "3.10.1",
-      "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.10.1.tgz",
-      "integrity": "sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==",
-      "dev": true,
-      "requires": {
-        "domelementtype": "^1.3.1",
-        "domhandler": "^2.3.0",
-        "domutils": "^1.5.1",
-        "entities": "^1.1.1",
-        "inherits": "^2.0.1",
-        "readable-stream": "^3.1.1"
-      },
-      "dependencies": {
-        "readable-stream": {
-          "version": "3.4.0",
-          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.4.0.tgz",
-          "integrity": "sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==",
-          "dev": true,
-          "requires": {
-            "inherits": "^2.0.3",
-            "string_decoder": "^1.1.1",
-            "util-deprecate": "^1.0.1"
-          }
-        }
-      }
-    },
-    "http-errors": {
-      "version": "1.7.2",
-      "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.2.tgz",
-      "integrity": "sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==",
-      "dev": true,
-      "requires": {
-        "depd": "~1.1.2",
-        "inherits": "2.0.3",
-        "setprototypeof": "1.1.1",
-        "statuses": ">= 1.5.0 < 2",
-        "toidentifier": "1.0.0"
-      },
-      "dependencies": {
-        "inherits": {
-          "version": "2.0.3",
-          "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
-          "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
-          "dev": true
-        }
-      }
-    },
-    "http-parser-js": {
-      "version": "0.4.10",
-      "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.4.10.tgz",
-      "integrity": "sha1-ksnBN0w1CF912zWexWzCV8u5P6Q=",
-      "dev": true
-    },
-    "http-proxy": {
-      "version": "1.17.0",
-      "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.17.0.tgz",
-      "integrity": "sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g==",
-      "dev": true,
-      "requires": {
-        "eventemitter3": "^3.0.0",
-        "follow-redirects": "^1.0.0",
-        "requires-port": "^1.0.0"
-      }
-    },
-    "http-proxy-middleware": {
-      "version": "0.17.4",
-      "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-0.17.4.tgz",
-      "integrity": "sha1-ZC6ISIUdZvCdTxJJEoRtuutBuDM=",
-      "dev": true,
-      "requires": {
-        "http-proxy": "^1.16.2",
-        "is-glob": "^3.1.0",
-        "lodash": "^4.17.2",
-        "micromatch": "^2.3.11"
-      },
-      "dependencies": {
-        "is-extglob": {
-          "version": "2.1.1",
-          "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
-          "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=",
-          "dev": true
-        },
-        "is-glob": {
-          "version": "3.1.0",
-          "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz",
-          "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=",
-          "dev": true,
-          "requires": {
-            "is-extglob": "^2.1.0"
-          }
-        }
-      }
-    },
-    "http-signature": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
-      "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
-      "requires": {
-        "assert-plus": "^1.0.0",
-        "jsprim": "^1.2.2",
-        "sshpk": "^1.7.0"
-      }
-    },
-    "https-browserify": {
-      "version": "0.0.1",
-      "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-0.0.1.tgz",
-      "integrity": "sha1-P5E2XKvmC3ftDruiS0VOPgnZWoI=",
-      "dev": true
-    },
-    "iconv-lite": {
-      "version": "0.4.24",
-      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
-      "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
-      "requires": {
-        "safer-buffer": ">= 2.1.2 < 3"
-      }
-    },
-    "icss-replace-symbols": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz",
-      "integrity": "sha1-Bupvg2ead0njhs/h/oEq5dsiPe0=",
-      "dev": true
-    },
-    "ieee754": {
-      "version": "1.1.13",
-      "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz",
-      "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==",
-      "dev": true
-    },
-    "ignore": {
-      "version": "3.3.10",
-      "resolved": "https://registry.npmjs.org/ignore/-/ignore-3.3.10.tgz",
-      "integrity": "sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==",
-      "dev": true
-    },
-    "imurmurhash": {
-      "version": "0.1.4",
-      "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
-      "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=",
-      "dev": true
-    },
-    "in-publish": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/in-publish/-/in-publish-2.0.0.tgz",
-      "integrity": "sha1-4g/146KvwmkDILbcVSaCqcf631E="
-    },
-    "indent-string": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz",
-      "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=",
-      "requires": {
-        "repeating": "^2.0.0"
-      }
-    },
-    "indexes-of": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/indexes-of/-/indexes-of-1.0.1.tgz",
-      "integrity": "sha1-8w9xbI4r00bHtn0985FVZqfAVgc=",
-      "dev": true
-    },
-    "indexof": {
-      "version": "0.0.1",
-      "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz",
-      "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=",
-      "dev": true
-    },
-    "inflight": {
-      "version": "1.0.6",
-      "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
-      "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
-      "requires": {
-        "once": "^1.3.0",
-        "wrappy": "1"
-      }
-    },
-    "inherits": {
-      "version": "2.0.4",
-      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
-      "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
-    },
-    "inquirer": {
-      "version": "0.12.0",
-      "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.12.0.tgz",
-      "integrity": "sha1-HvK/1jUE3wvHV4X/+MLEHfEvB34=",
-      "dev": true,
-      "requires": {
-        "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"
-      }
-    },
-    "interpret": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz",
-      "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==",
-      "dev": true
-    },
-    "invariant": {
-      "version": "2.2.4",
-      "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz",
-      "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==",
-      "dev": true,
-      "requires": {
-        "loose-envify": "^1.0.0"
-      }
-    },
-    "invert-kv": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz",
-      "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY="
-    },
-    "ipaddr.js": {
-      "version": "1.9.0",
-      "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.0.tgz",
-      "integrity": "sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA==",
-      "dev": true
-    },
-    "is-absolute-url": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-2.1.0.tgz",
-      "integrity": "sha1-UFMN+4T8yap9vnhS6Do3uTufKqY=",
-      "dev": true
-    },
-    "is-accessor-descriptor": {
-      "version": "0.1.6",
-      "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
-      "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=",
-      "dev": true,
-      "requires": {
-        "kind-of": "^3.0.2"
-      }
-    },
-    "is-arrayish": {
-      "version": "0.2.1",
-      "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
-      "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0="
-    },
-    "is-binary-path": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz",
-      "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=",
-      "dev": true,
-      "requires": {
-        "binary-extensions": "^1.0.0"
-      }
-    },
-    "is-buffer": {
-      "version": "1.1.6",
-      "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
-      "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==",
-      "dev": true
-    },
-    "is-data-descriptor": {
-      "version": "0.1.4",
-      "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
-      "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=",
-      "dev": true,
-      "requires": {
-        "kind-of": "^3.0.2"
-      }
-    },
-    "is-descriptor": {
-      "version": "0.1.6",
-      "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
-      "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
-      "dev": true,
-      "requires": {
-        "is-accessor-descriptor": "^0.1.6",
-        "is-data-descriptor": "^0.1.4",
-        "kind-of": "^5.0.0"
-      },
-      "dependencies": {
-        "kind-of": {
-          "version": "5.1.0",
-          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
-          "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
-          "dev": true
-        }
-      }
-    },
-    "is-dotfile": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz",
-      "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=",
-      "dev": true
-    },
-    "is-equal-shallow": {
-      "version": "0.1.3",
-      "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz",
-      "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=",
-      "dev": true,
-      "requires": {
-        "is-primitive": "^2.0.0"
-      }
-    },
-    "is-extendable": {
-      "version": "0.1.1",
-      "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
-      "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=",
-      "dev": true
-    },
-    "is-extglob": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
-      "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
-      "dev": true
-    },
-    "is-finite": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz",
-      "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=",
-      "requires": {
-        "number-is-nan": "^1.0.0"
-      }
-    },
-    "is-fullwidth-code-point": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
-      "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
-      "requires": {
-        "number-is-nan": "^1.0.0"
-      }
-    },
-    "is-glob": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
-      "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
-      "dev": true,
-      "requires": {
-        "is-extglob": "^1.0.0"
-      }
-    },
-    "is-lower-case": {
-      "version": "1.1.3",
-      "resolved": "https://registry.npmjs.org/is-lower-case/-/is-lower-case-1.1.3.tgz",
-      "integrity": "sha1-fhR75HaNxGbbO/shzGCzHmrWk5M=",
-      "dev": true,
-      "requires": {
-        "lower-case": "^1.1.0"
-      }
-    },
-    "is-my-ip-valid": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/is-my-ip-valid/-/is-my-ip-valid-1.0.0.tgz",
-      "integrity": "sha512-gmh/eWXROncUzRnIa1Ubrt5b8ep/MGSnfAUI3aRp+sqTCs1tv1Isl8d8F6JmkN3dXKc3ehZMrtiPN9eL03NuaQ==",
-      "dev": true
-    },
-    "is-my-json-valid": {
-      "version": "2.20.0",
-      "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.20.0.tgz",
-      "integrity": "sha512-XTHBZSIIxNsIsZXg7XB5l8z/OBFosl1Wao4tXLpeC7eKU4Vm/kdop2azkPqULwnfGQjmeDIyey9g7afMMtdWAA==",
-      "dev": true,
-      "requires": {
-        "generate-function": "^2.0.0",
-        "generate-object-property": "^1.1.0",
-        "is-my-ip-valid": "^1.0.0",
-        "jsonpointer": "^4.0.0",
-        "xtend": "^4.0.0"
-      }
-    },
-    "is-number": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz",
-      "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=",
-      "dev": true,
-      "requires": {
-        "kind-of": "^3.0.2"
-      }
-    },
-    "is-plain-obj": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz",
-      "integrity": "sha1-caUMhCnfync8kqOQpKA7OfzVHT4=",
-      "dev": true
-    },
-    "is-plain-object": {
-      "version": "2.0.4",
-      "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
-      "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
-      "dev": true,
-      "requires": {
-        "isobject": "^3.0.1"
-      },
-      "dependencies": {
-        "isobject": {
-          "version": "3.0.1",
-          "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
-          "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
-          "dev": true
-        }
-      }
-    },
-    "is-posix-bracket": {
-      "version": "0.1.1",
-      "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz",
-      "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=",
-      "dev": true
-    },
-    "is-primitive": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz",
-      "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=",
-      "dev": true
-    },
-    "is-property": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz",
-      "integrity": "sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ=",
-      "dev": true
-    },
-    "is-resolvable": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz",
-      "integrity": "sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==",
-      "dev": true
-    },
-    "is-svg": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/is-svg/-/is-svg-2.1.0.tgz",
-      "integrity": "sha1-z2EJDaDZ77yrhyLeum8DIgjbsOk=",
-      "dev": true,
-      "requires": {
-        "html-comment-regex": "^1.1.0"
-      }
-    },
-    "is-typedarray": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
-      "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
-    },
-    "is-upper-case": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/is-upper-case/-/is-upper-case-1.1.2.tgz",
-      "integrity": "sha1-jQsfp+eTOh5YSDYA7H2WYcuvdW8=",
-      "dev": true,
-      "requires": {
-        "upper-case": "^1.1.0"
-      }
-    },
-    "is-utf8": {
-      "version": "0.2.1",
-      "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
-      "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI="
-    },
-    "is-windows": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
-      "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==",
-      "dev": true
-    },
-    "isarray": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
-      "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
-    },
-    "isexe": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
-      "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
-    },
-    "isobject": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
-      "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
-      "dev": true,
-      "requires": {
-        "isarray": "1.0.0"
-      }
-    },
-    "isstream": {
-      "version": "0.1.2",
-      "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
-      "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
-    },
-    "jquery": {
-      "version": "3.4.1",
-      "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.4.1.tgz",
-      "integrity": "sha512-36+AdBzCL+y6qjw5Tx7HgzeGCzC81MDDgaUP8ld2zhx58HdqXGoBd+tHdrBMiyjGQs0Hxs/MLZTu/eHNJJuWPw=="
-    },
-    "jquery-ui": {
-      "version": "1.12.1",
-      "resolved": "https://registry.npmjs.org/jquery-ui/-/jquery-ui-1.12.1.tgz",
-      "integrity": "sha1-vLQEXI3QU5wTS8FIjN0+dop6nlE="
-    },
-    "js-base64": {
-      "version": "2.5.1",
-      "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.5.1.tgz",
-      "integrity": "sha512-M7kLczedRMYX4L8Mdh4MzyAMM9O5osx+4FcOQuTvr3A9F2D9S5JXheN0ewNbrvK2UatkTRhL5ejGmGSjNMiZuw=="
-    },
-    "js-tokens": {
-      "version": "3.0.2",
-      "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
-      "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls=",
-      "dev": true
-    },
-    "js-yaml": {
-      "version": "3.7.0",
-      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.7.0.tgz",
-      "integrity": "sha1-XJZ93YN6m/3KXy3oQlOr6KHAO4A=",
-      "dev": true,
-      "requires": {
-        "argparse": "^1.0.7",
-        "esprima": "^2.6.0"
-      },
-      "dependencies": {
-        "esprima": {
-          "version": "2.7.3",
-          "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz",
-          "integrity": "sha1-luO3DVd59q1JzQMmc9HDEnZ7pYE=",
-          "dev": true
-        }
-      }
-    },
-    "jsbn": {
-      "version": "0.1.1",
-      "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
-      "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM="
-    },
-    "jsesc": {
-      "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz",
-      "integrity": "sha1-RsP+yMGJKxKwgz25vHYiF226s0s=",
-      "dev": true
-    },
-    "json-schema": {
-      "version": "0.2.3",
-      "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
-      "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM="
-    },
-    "json-schema-traverse": {
-      "version": "0.4.1",
-      "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz",
-      "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="
-    },
-    "json-stable-stringify": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz",
-      "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=",
-      "dev": true,
-      "requires": {
-        "jsonify": "~0.0.0"
-      }
-    },
-    "json-stringify-safe": {
-      "version": "5.0.1",
-      "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
-      "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
-    },
-    "json3": {
-      "version": "3.3.3",
-      "resolved": "https://registry.npmjs.org/json3/-/json3-3.3.3.tgz",
-      "integrity": "sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA==",
-      "dev": true
-    },
-    "json5": {
-      "version": "0.5.1",
-      "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz",
-      "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=",
-      "dev": true
-    },
-    "jsonify": {
-      "version": "0.0.0",
-      "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz",
-      "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=",
-      "dev": true
-    },
-    "jsonpointer": {
-      "version": "4.0.1",
-      "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz",
-      "integrity": "sha1-T9kss04OnbPInIYi7PUfm5eMbLk=",
-      "dev": true
-    },
-    "jsprim": {
-      "version": "1.4.1",
-      "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
-      "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
-      "requires": {
-        "assert-plus": "1.0.0",
-        "extsprintf": "1.3.0",
-        "json-schema": "0.2.3",
-        "verror": "1.10.0"
-      }
-    },
-    "jstransform": {
-      "version": "11.0.3",
-      "resolved": "https://registry.npmjs.org/jstransform/-/jstransform-11.0.3.tgz",
-      "integrity": "sha1-CaeJk+CuTU70SH9hVakfYZDLQiM=",
-      "requires": {
-        "base62": "^1.1.0",
-        "commoner": "^0.10.1",
-        "esprima-fb": "^15001.1.0-dev-harmony-fb",
-        "object-assign": "^2.0.0",
-        "source-map": "^0.4.2"
-      },
-      "dependencies": {
-        "object-assign": {
-          "version": "2.1.1",
-          "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz",
-          "integrity": "sha1-Q8NuXVaf+OSBbE76i+AtJpZ8GKo="
-        }
-      }
-    },
-    "kind-of": {
-      "version": "3.2.2",
-      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
-      "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
-      "dev": true,
-      "requires": {
-        "is-buffer": "^1.1.5"
-      }
-    },
-    "lazy-cache": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz",
-      "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=",
-      "dev": true
-    },
-    "lcid": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz",
-      "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=",
-      "requires": {
-        "invert-kv": "^1.0.0"
-      }
-    },
-    "levn": {
-      "version": "0.3.0",
-      "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
-      "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=",
-      "dev": true,
-      "requires": {
-        "prelude-ls": "~1.1.2",
-        "type-check": "~0.3.2"
-      }
-    },
-    "load-json-file": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
-      "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
-      "requires": {
-        "graceful-fs": "^4.1.2",
-        "parse-json": "^2.2.0",
-        "pify": "^2.0.0",
-        "pinkie-promise": "^2.0.0",
-        "strip-bom": "^2.0.0"
-      }
-    },
-    "loader-fs-cache": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/loader-fs-cache/-/loader-fs-cache-1.0.2.tgz",
-      "integrity": "sha512-70IzT/0/L+M20jUlEqZhZyArTU6VKLRTYRDAYN26g4jfzpJqjipLL3/hgYpySqI9PwsVRHHFja0LfEmsx9X2Cw==",
-      "dev": true,
-      "requires": {
-        "find-cache-dir": "^0.1.1",
-        "mkdirp": "0.5.1"
-      }
-    },
-    "loader-utils": {
-      "version": "0.2.17",
-      "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.17.tgz",
-      "integrity": "sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=",
-      "dev": true,
-      "requires": {
-        "big.js": "^3.1.3",
-        "emojis-list": "^2.0.0",
-        "json5": "^0.5.0",
-        "object-assign": "^4.0.1"
-      }
-    },
-    "lodash": {
-      "version": "4.17.14",
-      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.14.tgz",
-      "integrity": "sha512-mmKYbW3GLuJeX+iGP+Y7Gp1AiGHGbXHCOh/jZmrawMmsE7MS4znI3RL2FsjbqOyMayHInjOeykW7PEajUk1/xw=="
-    },
-    "lodash._createcompounder": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/lodash._createcompounder/-/lodash._createcompounder-3.0.0.tgz",
-      "integrity": "sha1-XdLLVTctbnDg4jkvsjBNZjEJEHU=",
-      "dev": true,
-      "requires": {
-        "lodash.deburr": "^3.0.0",
-        "lodash.words": "^3.0.0"
-      }
-    },
-    "lodash._root": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz",
-      "integrity": "sha1-+6HEUkwZ7ppfgTa0YJ8BfPTe1pI=",
-      "dev": true
-    },
-    "lodash.camelcase": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-3.0.1.tgz",
-      "integrity": "sha1-kyyLh/ikN3iXxnGXUzKC+Xrqwpg=",
-      "dev": true,
-      "requires": {
-        "lodash._createcompounder": "^3.0.0"
-      }
-    },
-    "lodash.deburr": {
-      "version": "3.2.0",
-      "resolved": "https://registry.npmjs.org/lodash.deburr/-/lodash.deburr-3.2.0.tgz",
-      "integrity": "sha1-baj1QzSjZqfPTEx2742Aqhs2XtU=",
-      "dev": true,
-      "requires": {
-        "lodash._root": "^3.0.0"
-      }
-    },
-    "lodash.memoize": {
-      "version": "4.1.2",
-      "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
-      "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=",
-      "dev": true
-    },
-    "lodash.uniq": {
-      "version": "4.5.0",
-      "resolved": "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz",
-      "integrity": "sha1-0CJTc662Uq3BvILklFM5qEJ1R3M=",
-      "dev": true
-    },
-    "lodash.words": {
-      "version": "3.2.0",
-      "resolved": "https://registry.npmjs.org/lodash.words/-/lodash.words-3.2.0.tgz",
-      "integrity": "sha1-TiqGSbwIdFsXxpWxo86P7llmI7M=",
-      "dev": true,
-      "requires": {
-        "lodash._root": "^3.0.0"
-      }
-    },
-    "longest": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz",
-      "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=",
-      "dev": true
-    },
-    "loose-envify": {
-      "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
-      "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
-      "dev": true,
-      "requires": {
-        "js-tokens": "^3.0.0 || ^4.0.0"
-      }
-    },
-    "loud-rejection": {
-      "version": "1.6.0",
-      "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz",
-      "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=",
-      "requires": {
-        "currently-unhandled": "^0.4.1",
-        "signal-exit": "^3.0.0"
-      }
-    },
-    "lower-case": {
-      "version": "1.1.4",
-      "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz",
-      "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw=",
-      "dev": true
-    },
-    "lower-case-first": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/lower-case-first/-/lower-case-first-1.0.2.tgz",
-      "integrity": "sha1-5dp8JvKacHO+AtUrrJmA5ZIq36E=",
-      "dev": true,
-      "requires": {
-        "lower-case": "^1.1.2"
-      }
-    },
-    "lru-cache": {
-      "version": "4.1.5",
-      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz",
-      "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==",
-      "requires": {
-        "pseudomap": "^1.0.2",
-        "yallist": "^2.1.2"
-      }
-    },
-    "map-cache": {
-      "version": "0.2.2",
-      "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
-      "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=",
-      "dev": true
-    },
-    "map-obj": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz",
-      "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0="
-    },
-    "map-visit": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz",
-      "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=",
-      "dev": true,
-      "requires": {
-        "object-visit": "^1.0.0"
-      }
-    },
-    "math-expression-evaluator": {
-      "version": "1.2.17",
-      "resolved": "https://registry.npmjs.org/math-expression-evaluator/-/math-expression-evaluator-1.2.17.tgz",
-      "integrity": "sha1-3oGf282E3M2PrlnGrreWFbnSZqw=",
-      "dev": true
-    },
-    "math-random": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.4.tgz",
-      "integrity": "sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==",
-      "dev": true
-    },
-    "md5": {
-      "version": "2.2.1",
-      "resolved": "https://registry.npmjs.org/md5/-/md5-2.2.1.tgz",
-      "integrity": "sha1-U6s41f48iJG6RlMp6iP6wFQBJvk=",
-      "dev": true,
-      "requires": {
-        "charenc": "~0.0.1",
-        "crypt": "~0.0.1",
-        "is-buffer": "~1.1.1"
-      }
-    },
-    "media-typer": {
-      "version": "0.3.0",
-      "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
-      "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=",
-      "dev": true
-    },
-    "memory-fs": {
-      "version": "0.3.0",
-      "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.3.0.tgz",
-      "integrity": "sha1-e8xrYp46Q+hx1+Kaymrop/FcuyA=",
-      "dev": true,
-      "requires": {
-        "errno": "^0.1.3",
-        "readable-stream": "^2.0.1"
-      }
-    },
-    "meow": {
-      "version": "3.7.0",
-      "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz",
-      "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=",
-      "requires": {
-        "camelcase-keys": "^2.0.0",
-        "decamelize": "^1.1.2",
-        "loud-rejection": "^1.0.0",
-        "map-obj": "^1.0.1",
-        "minimist": "^1.1.3",
-        "normalize-package-data": "^2.3.4",
-        "object-assign": "^4.0.1",
-        "read-pkg-up": "^1.0.1",
-        "redent": "^1.0.0",
-        "trim-newlines": "^1.0.0"
-      }
-    },
-    "merge-descriptors": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
-      "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=",
-      "dev": true
-    },
-    "methods": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
-      "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=",
-      "dev": true
-    },
-    "micromatch": {
-      "version": "2.3.11",
-      "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz",
-      "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=",
-      "dev": true,
-      "requires": {
-        "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"
-      }
-    },
-    "mime": {
-      "version": "1.6.0",
-      "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
-      "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
-      "dev": true
-    },
-    "mime-db": {
-      "version": "1.40.0",
-      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz",
-      "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA=="
-    },
-    "mime-types": {
-      "version": "2.1.24",
-      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz",
-      "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==",
-      "requires": {
-        "mime-db": "1.40.0"
-      }
-    },
-    "minimatch": {
-      "version": "3.0.4",
-      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
-      "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
-      "requires": {
-        "brace-expansion": "^1.1.7"
-      }
-    },
-    "minimist": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
-      "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
-    },
-    "mixin-deep": {
-      "version": "1.3.2",
-      "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz",
-      "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==",
-      "dev": true,
-      "requires": {
-        "for-in": "^1.0.2",
-        "is-extendable": "^1.0.1"
-      },
-      "dependencies": {
-        "is-extendable": {
-          "version": "1.0.1",
-          "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
-          "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
-          "dev": true,
-          "requires": {
-            "is-plain-object": "^2.0.4"
-          }
-        }
-      }
-    },
-    "mkdirp": {
-      "version": "0.5.1",
-      "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
-      "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
-      "requires": {
-        "minimist": "0.0.8"
-      },
-      "dependencies": {
-        "minimist": {
-          "version": "0.0.8",
-          "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
-          "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
-        }
-      }
-    },
-    "moment": {
-      "version": "2.24.0",
-      "resolved": "https://registry.npmjs.org/moment/-/moment-2.24.0.tgz",
-      "integrity": "sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg=="
-    },
-    "ms": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
-      "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
-      "dev": true
-    },
-    "mute-stream": {
-      "version": "0.0.5",
-      "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.5.tgz",
-      "integrity": "sha1-j7+rsKmKJT0xhDMfno3rc3L6xsA=",
-      "dev": true
-    },
-    "nan": {
-      "version": "2.14.0",
-      "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz",
-      "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg=="
-    },
-    "nanomatch": {
-      "version": "1.2.13",
-      "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz",
-      "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==",
-      "dev": true,
-      "requires": {
-        "arr-diff": "^4.0.0",
-        "array-unique": "^0.3.2",
-        "define-property": "^2.0.2",
-        "extend-shallow": "^3.0.2",
-        "fragment-cache": "^0.2.1",
-        "is-windows": "^1.0.2",
-        "kind-of": "^6.0.2",
-        "object.pick": "^1.3.0",
-        "regex-not": "^1.0.0",
-        "snapdragon": "^0.8.1",
-        "to-regex": "^3.0.1"
-      },
-      "dependencies": {
-        "arr-diff": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
-          "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=",
-          "dev": true
-        },
-        "array-unique": {
-          "version": "0.3.2",
-          "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
-          "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=",
-          "dev": true
-        },
-        "kind-of": {
-          "version": "6.0.2",
-          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
-          "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
-          "dev": true
-        }
-      }
-    },
-    "natural-compare": {
-      "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz",
-      "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
-      "dev": true
-    },
-    "ncname": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/ncname/-/ncname-1.0.0.tgz",
-      "integrity": "sha1-W1etGLHKCShk72Kwse2BlPODtxw=",
-      "dev": true,
-      "requires": {
-        "xml-char-classes": "^1.0.0"
-      }
-    },
-    "negotiator": {
-      "version": "0.6.2",
-      "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz",
-      "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==",
-      "dev": true
-    },
-    "next-tick": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz",
-      "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=",
-      "dev": true
-    },
-    "no-case": {
-      "version": "2.3.2",
-      "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz",
-      "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==",
-      "dev": true,
-      "requires": {
-        "lower-case": "^1.1.1"
-      }
-    },
-    "node-gyp": {
-      "version": "3.8.0",
-      "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.8.0.tgz",
-      "integrity": "sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA==",
-      "requires": {
-        "fstream": "^1.0.0",
-        "glob": "^7.0.3",
-        "graceful-fs": "^4.1.2",
-        "mkdirp": "^0.5.0",
-        "nopt": "2 || 3",
-        "npmlog": "0 || 1 || 2 || 3 || 4",
-        "osenv": "0",
-        "request": "^2.87.0",
-        "rimraf": "2",
-        "semver": "~5.3.0",
-        "tar": "^2.0.0",
-        "which": "1"
-      },
-      "dependencies": {
-        "semver": {
-          "version": "5.3.0",
-          "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz",
-          "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8="
-        }
-      }
-    },
-    "node-libs-browser": {
-      "version": "0.7.0",
-      "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-0.7.0.tgz",
-      "integrity": "sha1-PicsCBnjCJNeJmdECNevDhSRuDs=",
-      "dev": true,
-      "requires": {
-        "assert": "^1.1.1",
-        "browserify-zlib": "^0.1.4",
-        "buffer": "^4.9.0",
-        "console-browserify": "^1.1.0",
-        "constants-browserify": "^1.0.0",
-        "crypto-browserify": "3.3.0",
-        "domain-browser": "^1.1.1",
-        "events": "^1.0.0",
-        "https-browserify": "0.0.1",
-        "os-browserify": "^0.2.0",
-        "path-browserify": "0.0.0",
-        "process": "^0.11.0",
-        "punycode": "^1.2.4",
-        "querystring-es3": "^0.2.0",
-        "readable-stream": "^2.0.5",
-        "stream-browserify": "^2.0.1",
-        "stream-http": "^2.3.1",
-        "string_decoder": "^0.10.25",
-        "timers-browserify": "^2.0.2",
-        "tty-browserify": "0.0.0",
-        "url": "^0.11.0",
-        "util": "^0.10.3",
-        "vm-browserify": "0.0.4"
-      },
-      "dependencies": {
-        "punycode": {
-          "version": "1.4.1",
-          "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
-          "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=",
-          "dev": true
-        },
-        "string_decoder": {
-          "version": "0.10.31",
-          "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
-          "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
-          "dev": true
-        }
-      }
-    },
-    "node-sass": {
-      "version": "4.12.0",
-      "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.12.0.tgz",
-      "integrity": "sha512-A1Iv4oN+Iel6EPv77/HddXErL2a+gZ4uBeZUy+a8O35CFYTXhgA8MgLCWBtwpGZdCvTvQ9d+bQxX/QC36GDPpQ==",
-      "requires": {
-        "async-foreach": "^0.1.3",
-        "chalk": "^1.1.1",
-        "cross-spawn": "^3.0.0",
-        "gaze": "^1.0.0",
-        "get-stdin": "^4.0.1",
-        "glob": "^7.0.3",
-        "in-publish": "^2.0.0",
-        "lodash": "^4.17.11",
-        "meow": "^3.7.0",
-        "mkdirp": "^0.5.1",
-        "nan": "^2.13.2",
-        "node-gyp": "^3.8.0",
-        "npmlog": "^4.0.0",
-        "request": "^2.88.0",
-        "sass-graph": "^2.2.4",
-        "stdout-stream": "^1.4.0",
-        "true-case-path": "^1.0.2"
-      }
-    },
-    "nopt": {
-      "version": "3.0.6",
-      "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz",
-      "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=",
-      "requires": {
-        "abbrev": "1"
-      }
-    },
-    "normalize-package-data": {
-      "version": "2.5.0",
-      "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
-      "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==",
-      "requires": {
-        "hosted-git-info": "^2.1.4",
-        "resolve": "^1.10.0",
-        "semver": "2 || 3 || 4 || 5",
-        "validate-npm-package-license": "^3.0.1"
-      }
-    },
-    "normalize-path": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
-      "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
-      "dev": true,
-      "requires": {
-        "remove-trailing-separator": "^1.0.1"
-      }
-    },
-    "normalize-range": {
-      "version": "0.1.2",
-      "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz",
-      "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=",
-      "dev": true
-    },
-    "normalize-url": {
-      "version": "1.9.1",
-      "resolved": "https://registry.npmjs.org/normalize-url/-/normalize-url-1.9.1.tgz",
-      "integrity": "sha1-LMDWazHqIwNkWENuNiDYWVTGbDw=",
-      "dev": true,
-      "requires": {
-        "object-assign": "^4.0.1",
-        "prepend-http": "^1.0.0",
-        "query-string": "^4.1.0",
-        "sort-keys": "^1.0.0"
-      }
-    },
-    "npmlog": {
-      "version": "4.1.2",
-      "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
-      "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
-      "requires": {
-        "are-we-there-yet": "~1.1.2",
-        "console-control-strings": "~1.1.0",
-        "gauge": "~2.7.3",
-        "set-blocking": "~2.0.0"
-      }
-    },
-    "nth-check": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz",
-      "integrity": "sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==",
-      "dev": true,
-      "requires": {
-        "boolbase": "~1.0.0"
-      }
-    },
-    "num2fraction": {
-      "version": "1.2.2",
-      "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz",
-      "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=",
-      "dev": true
-    },
-    "number-is-nan": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
-      "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0="
-    },
-    "oauth-sign": {
-      "version": "0.9.0",
-      "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
-      "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ=="
-    },
-    "object-assign": {
-      "version": "4.1.1",
-      "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
-      "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
-    },
-    "object-copy": {
-      "version": "0.1.0",
-      "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz",
-      "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=",
-      "dev": true,
-      "requires": {
-        "copy-descriptor": "^0.1.0",
-        "define-property": "^0.2.5",
-        "kind-of": "^3.0.3"
-      },
-      "dependencies": {
-        "define-property": {
-          "version": "0.2.5",
-          "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
-          "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
-          "dev": true,
-          "requires": {
-            "is-descriptor": "^0.1.0"
-          }
-        }
-      }
-    },
-    "object-hash": {
-      "version": "1.3.1",
-      "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-1.3.1.tgz",
-      "integrity": "sha512-OSuu/pU4ENM9kmREg0BdNrUDIl1heYa4mBZacJc+vVWz4GtAwu7jO8s4AIt2aGRUTqxykpWzI3Oqnsm13tTMDA==",
-      "dev": true
-    },
-    "object-visit": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz",
-      "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=",
-      "dev": true,
-      "requires": {
-        "isobject": "^3.0.0"
-      },
-      "dependencies": {
-        "isobject": {
-          "version": "3.0.1",
-          "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
-          "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
-          "dev": true
-        }
-      }
-    },
-    "object.omit": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz",
-      "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=",
-      "dev": true,
-      "requires": {
-        "for-own": "^0.1.4",
-        "is-extendable": "^0.1.1"
-      }
-    },
-    "object.pick": {
-      "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz",
-      "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=",
-      "dev": true,
-      "requires": {
-        "isobject": "^3.0.1"
-      },
-      "dependencies": {
-        "isobject": {
-          "version": "3.0.1",
-          "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
-          "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
-          "dev": true
-        }
-      }
-    },
-    "on-finished": {
-      "version": "2.3.0",
-      "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
-      "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
-      "dev": true,
-      "requires": {
-        "ee-first": "1.1.1"
-      }
-    },
-    "on-headers": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz",
-      "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==",
-      "dev": true
-    },
-    "once": {
-      "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
-      "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
-      "requires": {
-        "wrappy": "1"
-      }
-    },
-    "onetime": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/onetime/-/onetime-1.1.0.tgz",
-      "integrity": "sha1-ofeDj4MUxRbwXs78vEzP4EtO14k=",
-      "dev": true
-    },
-    "open": {
-      "version": "0.0.5",
-      "resolved": "https://registry.npmjs.org/open/-/open-0.0.5.tgz",
-      "integrity": "sha1-QsPhjslUZra/DcQvOilFw/DK2Pw=",
-      "dev": true
-    },
-    "optimist": {
-      "version": "0.6.1",
-      "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
-      "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=",
-      "dev": true,
-      "requires": {
-        "minimist": "~0.0.1",
-        "wordwrap": "~0.0.2"
-      },
-      "dependencies": {
-        "minimist": {
-          "version": "0.0.10",
-          "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz",
-          "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8=",
-          "dev": true
-        },
-        "wordwrap": {
-          "version": "0.0.3",
-          "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
-          "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=",
-          "dev": true
-        }
-      }
-    },
-    "optionator": {
-      "version": "0.8.2",
-      "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz",
-      "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=",
-      "dev": true,
-      "requires": {
-        "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"
-      }
-    },
-    "original": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/original/-/original-1.0.2.tgz",
-      "integrity": "sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg==",
-      "dev": true,
-      "requires": {
-        "url-parse": "^1.4.3"
-      }
-    },
-    "os-browserify": {
-      "version": "0.2.1",
-      "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.2.1.tgz",
-      "integrity": "sha1-Y/xMzuXS13Y9Jrv4YBB45sLgBE8=",
-      "dev": true
-    },
-    "os-homedir": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
-      "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M="
-    },
-    "os-locale": {
-      "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
-      "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=",
-      "requires": {
-        "lcid": "^1.0.0"
-      }
-    },
-    "os-tmpdir": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
-      "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ="
-    },
-    "osenv": {
-      "version": "0.1.5",
-      "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz",
-      "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
-      "requires": {
-        "os-homedir": "^1.0.0",
-        "os-tmpdir": "^1.0.0"
-      }
-    },
-    "pako": {
-      "version": "0.2.9",
-      "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz",
-      "integrity": "sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=",
-      "dev": true
-    },
-    "param-case": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/param-case/-/param-case-2.1.1.tgz",
-      "integrity": "sha1-35T9jPZTHs915r75oIWPvHK+Ikc=",
-      "dev": true,
-      "requires": {
-        "no-case": "^2.2.0"
-      }
-    },
-    "parse-glob": {
-      "version": "3.0.4",
-      "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz",
-      "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=",
-      "dev": true,
-      "requires": {
-        "glob-base": "^0.3.0",
-        "is-dotfile": "^1.0.0",
-        "is-extglob": "^1.0.0",
-        "is-glob": "^2.0.0"
-      }
-    },
-    "parse-json": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
-      "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=",
-      "requires": {
-        "error-ex": "^1.2.0"
-      }
-    },
-    "parse5": {
-      "version": "2.2.3",
-      "resolved": "https://registry.npmjs.org/parse5/-/parse5-2.2.3.tgz",
-      "integrity": "sha1-DE/EHBAAxea5PUiwP4CDg3g06fY=",
-      "dev": true
-    },
-    "parseurl": {
-      "version": "1.3.3",
-      "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
-      "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
-      "dev": true
-    },
-    "pascal-case": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/pascal-case/-/pascal-case-2.0.1.tgz",
-      "integrity": "sha1-LVeNNFX2YNpl7KGO+VtODekSdh4=",
-      "dev": true,
-      "requires": {
-        "camel-case": "^3.0.0",
-        "upper-case-first": "^1.1.0"
-      }
-    },
-    "pascalcase": {
-      "version": "0.1.1",
-      "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz",
-      "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=",
-      "dev": true
-    },
-    "path-browserify": {
-      "version": "0.0.0",
-      "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz",
-      "integrity": "sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo=",
-      "dev": true
-    },
-    "path-case": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/path-case/-/path-case-2.1.1.tgz",
-      "integrity": "sha1-lLgDfDctP+KQbkZbtF4l0ibo7qU=",
-      "dev": true,
-      "requires": {
-        "no-case": "^2.2.0"
-      }
-    },
-    "path-exists": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz",
-      "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=",
-      "requires": {
-        "pinkie-promise": "^2.0.0"
-      }
-    },
-    "path-is-absolute": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
-      "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
-    },
-    "path-is-inside": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz",
-      "integrity": "sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=",
-      "dev": true
-    },
-    "path-parse": {
-      "version": "1.0.6",
-      "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
-      "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw=="
-    },
-    "path-to-regexp": {
-      "version": "0.1.7",
-      "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
-      "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=",
-      "dev": true
-    },
-    "path-type": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz",
-      "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=",
-      "requires": {
-        "graceful-fs": "^4.1.2",
-        "pify": "^2.0.0",
-        "pinkie-promise": "^2.0.0"
-      }
-    },
-    "pbkdf2-compat": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/pbkdf2-compat/-/pbkdf2-compat-2.0.1.tgz",
-      "integrity": "sha1-tuDI+plJTZTgURV1gCpZpcFC8og=",
-      "dev": true
-    },
-    "performance-now": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
-      "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
-    },
-    "pify": {
-      "version": "2.3.0",
-      "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
-      "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw="
-    },
-    "pinkie": {
-      "version": "2.0.4",
-      "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
-      "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA="
-    },
-    "pinkie-promise": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
-      "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
-      "requires": {
-        "pinkie": "^2.0.0"
-      }
-    },
-    "pkg-dir": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz",
-      "integrity": "sha1-ektQio1bstYp1EcFb/TpyTFM89Q=",
-      "dev": true,
-      "requires": {
-        "find-up": "^1.0.0"
-      }
-    },
-    "pluralize": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-1.2.1.tgz",
-      "integrity": "sha1-0aIUg/0iu0HlihL6NCGCMUCJfEU=",
-      "dev": true
-    },
-    "posix-character-classes": {
-      "version": "0.1.1",
-      "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz",
-      "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=",
-      "dev": true
-    },
-    "postcss": {
-      "version": "5.2.18",
-      "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz",
-      "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==",
-      "dev": true,
-      "requires": {
-        "chalk": "^1.1.3",
-        "js-base64": "^2.1.9",
-        "source-map": "^0.5.6",
-        "supports-color": "^3.2.3"
-      },
-      "dependencies": {
-        "source-map": {
-          "version": "0.5.7",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
-          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
-          "dev": true
-        },
-        "supports-color": {
-          "version": "3.2.3",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
-          "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
-          "dev": true,
-          "requires": {
-            "has-flag": "^1.0.0"
-          }
-        }
-      }
-    },
-    "postcss-calc": {
-      "version": "5.3.1",
-      "resolved": "https://registry.npmjs.org/postcss-calc/-/postcss-calc-5.3.1.tgz",
-      "integrity": "sha1-d7rnypKK2FcW4v2kLyYb98HWW14=",
-      "dev": true,
-      "requires": {
-        "postcss": "^5.0.2",
-        "postcss-message-helpers": "^2.0.0",
-        "reduce-css-calc": "^1.2.6"
-      }
-    },
-    "postcss-colormin": {
-      "version": "2.2.2",
-      "resolved": "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-2.2.2.tgz",
-      "integrity": "sha1-ZjFBfV8OkJo9fsJrJMio0eT5bks=",
-      "dev": true,
-      "requires": {
-        "colormin": "^1.0.5",
-        "postcss": "^5.0.13",
-        "postcss-value-parser": "^3.2.3"
-      }
-    },
-    "postcss-convert-values": {
-      "version": "2.6.1",
-      "resolved": "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-2.6.1.tgz",
-      "integrity": "sha1-u9hZPFwf0uPRwyK7kl3K6Nrk1i0=",
-      "dev": true,
-      "requires": {
-        "postcss": "^5.0.11",
-        "postcss-value-parser": "^3.1.2"
-      }
-    },
-    "postcss-discard-comments": {
-      "version": "2.0.4",
-      "resolved": "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-2.0.4.tgz",
-      "integrity": "sha1-vv6J+v1bPazlzM5Rt2uBUUvgDj0=",
-      "dev": true,
-      "requires": {
-        "postcss": "^5.0.14"
-      }
-    },
-    "postcss-discard-duplicates": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-2.1.0.tgz",
-      "integrity": "sha1-uavye4isGIFYpesSq8riAmO5GTI=",
-      "dev": true,
-      "requires": {
-        "postcss": "^5.0.4"
-      }
-    },
-    "postcss-discard-empty": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-2.1.0.tgz",
-      "integrity": "sha1-0rS9nVztXr2Nyt52QMfXzX9PkrU=",
-      "dev": true,
-      "requires": {
-        "postcss": "^5.0.14"
-      }
-    },
-    "postcss-discard-overridden": {
-      "version": "0.1.1",
-      "resolved": "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-0.1.1.tgz",
-      "integrity": "sha1-ix6vVU9ob7KIzYdMVWZ7CqNmjVg=",
-      "dev": true,
-      "requires": {
-        "postcss": "^5.0.16"
-      }
-    },
-    "postcss-discard-unused": {
-      "version": "2.2.3",
-      "resolved": "https://registry.npmjs.org/postcss-discard-unused/-/postcss-discard-unused-2.2.3.tgz",
-      "integrity": "sha1-vOMLLMWR/8Y0Mitfs0ZLbZNPRDM=",
-      "dev": true,
-      "requires": {
-        "postcss": "^5.0.14",
-        "uniqs": "^2.0.0"
-      }
-    },
-    "postcss-filter-plugins": {
-      "version": "2.0.3",
-      "resolved": "https://registry.npmjs.org/postcss-filter-plugins/-/postcss-filter-plugins-2.0.3.tgz",
-      "integrity": "sha512-T53GVFsdinJhgwm7rg1BzbeBRomOg9y5MBVhGcsV0CxurUdVj1UlPdKtn7aqYA/c/QVkzKMjq2bSV5dKG5+AwQ==",
-      "dev": true,
-      "requires": {
-        "postcss": "^5.0.4"
-      }
-    },
-    "postcss-merge-idents": {
-      "version": "2.1.7",
-      "resolved": "https://registry.npmjs.org/postcss-merge-idents/-/postcss-merge-idents-2.1.7.tgz",
-      "integrity": "sha1-TFUwMTwI4dWzu/PSu8dH4njuonA=",
-      "dev": true,
-      "requires": {
-        "has": "^1.0.1",
-        "postcss": "^5.0.10",
-        "postcss-value-parser": "^3.1.1"
-      }
-    },
-    "postcss-merge-longhand": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-2.0.2.tgz",
-      "integrity": "sha1-I9kM0Sewp3mUkVMyc5A0oaTz1lg=",
-      "dev": true,
-      "requires": {
-        "postcss": "^5.0.4"
-      }
-    },
-    "postcss-merge-rules": {
-      "version": "2.1.2",
-      "resolved": "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-2.1.2.tgz",
-      "integrity": "sha1-0d9d+qexrMO+VT8OnhDofGG19yE=",
-      "dev": true,
-      "requires": {
-        "browserslist": "^1.5.2",
-        "caniuse-api": "^1.5.2",
-        "postcss": "^5.0.4",
-        "postcss-selector-parser": "^2.2.2",
-        "vendors": "^1.0.0"
-      }
-    },
-    "postcss-message-helpers": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/postcss-message-helpers/-/postcss-message-helpers-2.0.0.tgz",
-      "integrity": "sha1-pPL0+rbk/gAvCu0ABHjN9S+bpg4=",
-      "dev": true
-    },
-    "postcss-minify-font-values": {
-      "version": "1.0.5",
-      "resolved": "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-1.0.5.tgz",
-      "integrity": "sha1-S1jttWZB66fIR0qzUmyv17vey2k=",
-      "dev": true,
-      "requires": {
-        "object-assign": "^4.0.1",
-        "postcss": "^5.0.4",
-        "postcss-value-parser": "^3.0.2"
-      }
-    },
-    "postcss-minify-gradients": {
-      "version": "1.0.5",
-      "resolved": "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-1.0.5.tgz",
-      "integrity": "sha1-Xb2hE3NwP4PPtKPqOIHY11/15uE=",
-      "dev": true,
-      "requires": {
-        "postcss": "^5.0.12",
-        "postcss-value-parser": "^3.3.0"
-      }
-    },
-    "postcss-minify-params": {
-      "version": "1.2.2",
-      "resolved": "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-1.2.2.tgz",
-      "integrity": "sha1-rSzgcTc7lDs9kwo/pZo1jCjW8fM=",
-      "dev": true,
-      "requires": {
-        "alphanum-sort": "^1.0.1",
-        "postcss": "^5.0.2",
-        "postcss-value-parser": "^3.0.2",
-        "uniqs": "^2.0.0"
-      }
-    },
-    "postcss-minify-selectors": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-2.1.1.tgz",
-      "integrity": "sha1-ssapjAByz5G5MtGkllCBFDEXNb8=",
-      "dev": true,
-      "requires": {
-        "alphanum-sort": "^1.0.2",
-        "has": "^1.0.1",
-        "postcss": "^5.0.14",
-        "postcss-selector-parser": "^2.0.0"
-      }
-    },
-    "postcss-modules-extract-imports": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.2.1.tgz",
-      "integrity": "sha512-6jt9XZwUhwmRUhb/CkyJY020PYaPJsCyt3UjbaWo6XEbH/94Hmv6MP7fG2C5NDU/BcHzyGYxNtHvM+LTf9HrYw==",
-      "dev": true,
-      "requires": {
-        "postcss": "^6.0.1"
-      },
-      "dependencies": {
-        "ansi-styles": {
-          "version": "3.2.1",
-          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
-          "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
-          "dev": true,
-          "requires": {
-            "color-convert": "^1.9.0"
-          }
-        },
-        "chalk": {
-          "version": "2.4.2",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
-          "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
-          "dev": true,
-          "requires": {
-            "ansi-styles": "^3.2.1",
-            "escape-string-regexp": "^1.0.5",
-            "supports-color": "^5.3.0"
-          }
-        },
-        "color-convert": {
-          "version": "1.9.3",
-          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
-          "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
-          "dev": true,
-          "requires": {
-            "color-name": "1.1.3"
-          }
-        },
-        "color-name": {
-          "version": "1.1.3",
-          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-          "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
-          "dev": true
-        },
-        "has-flag": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-          "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
-          "dev": true
-        },
-        "postcss": {
-          "version": "6.0.23",
-          "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz",
-          "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==",
-          "dev": true,
-          "requires": {
-            "chalk": "^2.4.1",
-            "source-map": "^0.6.1",
-            "supports-color": "^5.4.0"
-          }
-        },
-        "source-map": {
-          "version": "0.6.1",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
-          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
-          "dev": true
-        },
-        "supports-color": {
-          "version": "5.5.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
-          "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
-          "dev": true,
-          "requires": {
-            "has-flag": "^3.0.0"
-          }
-        }
-      }
-    },
-    "postcss-modules-local-by-default": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-1.2.0.tgz",
-      "integrity": "sha1-99gMOYxaOT+nlkRmvRlQCn1hwGk=",
-      "dev": true,
-      "requires": {
-        "css-selector-tokenizer": "^0.7.0",
-        "postcss": "^6.0.1"
-      },
-      "dependencies": {
-        "ansi-styles": {
-          "version": "3.2.1",
-          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
-          "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
-          "dev": true,
-          "requires": {
-            "color-convert": "^1.9.0"
-          }
-        },
-        "chalk": {
-          "version": "2.4.2",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
-          "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
-          "dev": true,
-          "requires": {
-            "ansi-styles": "^3.2.1",
-            "escape-string-regexp": "^1.0.5",
-            "supports-color": "^5.3.0"
-          }
-        },
-        "color-convert": {
-          "version": "1.9.3",
-          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
-          "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
-          "dev": true,
-          "requires": {
-            "color-name": "1.1.3"
-          }
-        },
-        "color-name": {
-          "version": "1.1.3",
-          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-          "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
-          "dev": true
-        },
-        "css-selector-tokenizer": {
-          "version": "0.7.1",
-          "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.1.tgz",
-          "integrity": "sha512-xYL0AMZJ4gFzJQsHUKa5jiWWi2vH77WVNg7JYRyewwj6oPh4yb/y6Y9ZCw9dsj/9UauMhtuxR+ogQd//EdEVNA==",
-          "dev": true,
-          "requires": {
-            "cssesc": "^0.1.0",
-            "fastparse": "^1.1.1",
-            "regexpu-core": "^1.0.0"
-          }
-        },
-        "has-flag": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-          "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
-          "dev": true
-        },
-        "postcss": {
-          "version": "6.0.23",
-          "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz",
-          "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==",
-          "dev": true,
-          "requires": {
-            "chalk": "^2.4.1",
-            "source-map": "^0.6.1",
-            "supports-color": "^5.4.0"
-          }
-        },
-        "regexpu-core": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-1.0.0.tgz",
-          "integrity": "sha1-hqdj9Y7k18L2sQLkdkBQ3n7ZDGs=",
-          "dev": true,
-          "requires": {
-            "regenerate": "^1.2.1",
-            "regjsgen": "^0.2.0",
-            "regjsparser": "^0.1.4"
-          }
-        },
-        "source-map": {
-          "version": "0.6.1",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
-          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
-          "dev": true
-        },
-        "supports-color": {
-          "version": "5.5.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
-          "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
-          "dev": true,
-          "requires": {
-            "has-flag": "^3.0.0"
-          }
-        }
-      }
-    },
-    "postcss-modules-scope": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-1.1.0.tgz",
-      "integrity": "sha1-1upkmUx5+XtipytCb75gVqGUu5A=",
-      "dev": true,
-      "requires": {
-        "css-selector-tokenizer": "^0.7.0",
-        "postcss": "^6.0.1"
-      },
-      "dependencies": {
-        "ansi-styles": {
-          "version": "3.2.1",
-          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
-          "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
-          "dev": true,
-          "requires": {
-            "color-convert": "^1.9.0"
-          }
-        },
-        "chalk": {
-          "version": "2.4.2",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
-          "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
-          "dev": true,
-          "requires": {
-            "ansi-styles": "^3.2.1",
-            "escape-string-regexp": "^1.0.5",
-            "supports-color": "^5.3.0"
-          }
-        },
-        "color-convert": {
-          "version": "1.9.3",
-          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
-          "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
-          "dev": true,
-          "requires": {
-            "color-name": "1.1.3"
-          }
-        },
-        "color-name": {
-          "version": "1.1.3",
-          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-          "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
-          "dev": true
-        },
-        "css-selector-tokenizer": {
-          "version": "0.7.1",
-          "resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.7.1.tgz",
-          "integrity": "sha512-xYL0AMZJ4gFzJQsHUKa5jiWWi2vH77WVNg7JYRyewwj6oPh4yb/y6Y9ZCw9dsj/9UauMhtuxR+ogQd//EdEVNA==",
-          "dev": true,
-          "requires": {
-            "cssesc": "^0.1.0",
-            "fastparse": "^1.1.1",
-            "regexpu-core": "^1.0.0"
-          }
-        },
-        "has-flag": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-          "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
-          "dev": true
-        },
-        "postcss": {
-          "version": "6.0.23",
-          "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz",
-          "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==",
-          "dev": true,
-          "requires": {
-            "chalk": "^2.4.1",
-            "source-map": "^0.6.1",
-            "supports-color": "^5.4.0"
-          }
-        },
-        "regexpu-core": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-1.0.0.tgz",
-          "integrity": "sha1-hqdj9Y7k18L2sQLkdkBQ3n7ZDGs=",
-          "dev": true,
-          "requires": {
-            "regenerate": "^1.2.1",
-            "regjsgen": "^0.2.0",
-            "regjsparser": "^0.1.4"
-          }
-        },
-        "source-map": {
-          "version": "0.6.1",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
-          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
-          "dev": true
-        },
-        "supports-color": {
-          "version": "5.5.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
-          "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
-          "dev": true,
-          "requires": {
-            "has-flag": "^3.0.0"
-          }
-        }
-      }
-    },
-    "postcss-modules-values": {
-      "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-1.3.0.tgz",
-      "integrity": "sha1-7P+p1+GSUYOJ9CrQ6D9yrsRW6iA=",
-      "dev": true,
-      "requires": {
-        "icss-replace-symbols": "^1.1.0",
-        "postcss": "^6.0.1"
-      },
-      "dependencies": {
-        "ansi-styles": {
-          "version": "3.2.1",
-          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
-          "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
-          "dev": true,
-          "requires": {
-            "color-convert": "^1.9.0"
-          }
-        },
-        "chalk": {
-          "version": "2.4.2",
-          "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
-          "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
-          "dev": true,
-          "requires": {
-            "ansi-styles": "^3.2.1",
-            "escape-string-regexp": "^1.0.5",
-            "supports-color": "^5.3.0"
-          }
-        },
-        "color-convert": {
-          "version": "1.9.3",
-          "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
-          "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
-          "dev": true,
-          "requires": {
-            "color-name": "1.1.3"
-          }
-        },
-        "color-name": {
-          "version": "1.1.3",
-          "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
-          "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
-          "dev": true
-        },
-        "has-flag": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
-          "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=",
-          "dev": true
-        },
-        "postcss": {
-          "version": "6.0.23",
-          "resolved": "https://registry.npmjs.org/postcss/-/postcss-6.0.23.tgz",
-          "integrity": "sha512-soOk1h6J3VMTZtVeVpv15/Hpdl2cBLX3CAw4TAbkpTJiNPk9YP/zWcD1ND+xEtvyuuvKzbxliTOIyvkSeSJ6ag==",
-          "dev": true,
-          "requires": {
-            "chalk": "^2.4.1",
-            "source-map": "^0.6.1",
-            "supports-color": "^5.4.0"
-          }
-        },
-        "source-map": {
-          "version": "0.6.1",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
-          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
-          "dev": true
-        },
-        "supports-color": {
-          "version": "5.5.0",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
-          "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
-          "dev": true,
-          "requires": {
-            "has-flag": "^3.0.0"
-          }
-        }
-      }
-    },
-    "postcss-normalize-charset": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-1.1.1.tgz",
-      "integrity": "sha1-757nEhLX/nWceO0WL2HtYrXLk/E=",
-      "dev": true,
-      "requires": {
-        "postcss": "^5.0.5"
-      }
-    },
-    "postcss-normalize-url": {
-      "version": "3.0.8",
-      "resolved": "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-3.0.8.tgz",
-      "integrity": "sha1-EI90s/L82viRov+j6kWSJ5/HgiI=",
-      "dev": true,
-      "requires": {
-        "is-absolute-url": "^2.0.0",
-        "normalize-url": "^1.4.0",
-        "postcss": "^5.0.14",
-        "postcss-value-parser": "^3.2.3"
-      }
-    },
-    "postcss-ordered-values": {
-      "version": "2.2.3",
-      "resolved": "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-2.2.3.tgz",
-      "integrity": "sha1-7sbCpntsQSqNsgQud/6NpD+VwR0=",
-      "dev": true,
-      "requires": {
-        "postcss": "^5.0.4",
-        "postcss-value-parser": "^3.0.1"
-      }
-    },
-    "postcss-reduce-idents": {
-      "version": "2.4.0",
-      "resolved": "https://registry.npmjs.org/postcss-reduce-idents/-/postcss-reduce-idents-2.4.0.tgz",
-      "integrity": "sha1-wsbSDMlYKE9qv75j92Cb9AkFmtM=",
-      "dev": true,
-      "requires": {
-        "postcss": "^5.0.4",
-        "postcss-value-parser": "^3.0.2"
-      }
-    },
-    "postcss-reduce-initial": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-1.0.1.tgz",
-      "integrity": "sha1-aPgGlfBF0IJjqHmtJA343WT2ROo=",
-      "dev": true,
-      "requires": {
-        "postcss": "^5.0.4"
-      }
-    },
-    "postcss-reduce-transforms": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-1.0.4.tgz",
-      "integrity": "sha1-/3b02CEkN7McKYpC0uFEQCV3GuE=",
-      "dev": true,
-      "requires": {
-        "has": "^1.0.1",
-        "postcss": "^5.0.8",
-        "postcss-value-parser": "^3.0.1"
-      }
-    },
-    "postcss-selector-parser": {
-      "version": "2.2.3",
-      "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-2.2.3.tgz",
-      "integrity": "sha1-+UN3iGBsPJrO4W/+jYsWKX8nu5A=",
-      "dev": true,
-      "requires": {
-        "flatten": "^1.0.2",
-        "indexes-of": "^1.0.1",
-        "uniq": "^1.0.1"
-      }
-    },
-    "postcss-svgo": {
-      "version": "2.1.6",
-      "resolved": "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-2.1.6.tgz",
-      "integrity": "sha1-tt8YqmE7Zm4TPwittSGcJoSsEI0=",
-      "dev": true,
-      "requires": {
-        "is-svg": "^2.0.0",
-        "postcss": "^5.0.14",
-        "postcss-value-parser": "^3.2.3",
-        "svgo": "^0.7.0"
-      }
-    },
-    "postcss-unique-selectors": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-2.0.2.tgz",
-      "integrity": "sha1-mB1X0p3csz57Hf4f1DuGSfkzyh0=",
-      "dev": true,
-      "requires": {
-        "alphanum-sort": "^1.0.1",
-        "postcss": "^5.0.4",
-        "uniqs": "^2.0.0"
-      }
-    },
-    "postcss-value-parser": {
-      "version": "3.3.1",
-      "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
-      "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
-      "dev": true
-    },
-    "postcss-zindex": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/postcss-zindex/-/postcss-zindex-2.2.0.tgz",
-      "integrity": "sha1-0hCd3AVbka9n/EyzsCWUZjnSryI=",
-      "dev": true,
-      "requires": {
-        "has": "^1.0.1",
-        "postcss": "^5.0.4",
-        "uniqs": "^2.0.0"
-      }
-    },
-    "prelude-ls": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
-      "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=",
-      "dev": true
-    },
-    "prepend-http": {
-      "version": "1.0.4",
-      "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz",
-      "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=",
-      "dev": true
-    },
-    "preserve": {
-      "version": "0.2.0",
-      "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz",
-      "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=",
-      "dev": true
-    },
-    "pretty-error": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/pretty-error/-/pretty-error-2.1.1.tgz",
-      "integrity": "sha1-X0+HyPkeWuPzuoerTPXgOxoX8aM=",
-      "dev": true,
-      "requires": {
-        "renderkid": "^2.0.1",
-        "utila": "~0.4"
-      }
-    },
-    "private": {
-      "version": "0.1.8",
-      "resolved": "https://registry.npmjs.org/private/-/private-0.1.8.tgz",
-      "integrity": "sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg=="
-    },
-    "process": {
-      "version": "0.11.10",
-      "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
-      "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=",
-      "dev": true
-    },
-    "process-nextick-args": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
-      "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
-    },
-    "progress": {
-      "version": "1.1.8",
-      "resolved": "https://registry.npmjs.org/progress/-/progress-1.1.8.tgz",
-      "integrity": "sha1-4mDHj2Fhzdmw5WzD4Khd4Xx6V74=",
-      "dev": true
-    },
-    "proxy-addr": {
-      "version": "2.0.5",
-      "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.5.tgz",
-      "integrity": "sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==",
-      "dev": true,
-      "requires": {
-        "forwarded": "~0.1.2",
-        "ipaddr.js": "1.9.0"
-      }
-    },
-    "prr": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz",
-      "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=",
-      "dev": true
-    },
-    "pseudomap": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
-      "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM="
-    },
-    "psl": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/psl/-/psl-1.2.0.tgz",
-      "integrity": "sha512-GEn74ZffufCmkDDLNcl3uuyF/aSD6exEyh1v/ZSdAomB82t6G9hzJVRx0jBmLDW+VfZqks3aScmMw9DszwUalA=="
-    },
-    "punycode": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz",
-      "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A=="
-    },
-    "q": {
-      "version": "1.5.1",
-      "resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz",
-      "integrity": "sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc="
-    },
-    "qs": {
-      "version": "6.5.2",
-      "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
-      "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA=="
-    },
-    "query-string": {
-      "version": "4.3.4",
-      "resolved": "https://registry.npmjs.org/query-string/-/query-string-4.3.4.tgz",
-      "integrity": "sha1-u7aTucqRXCMlFbIosaArYJBD2+s=",
-      "dev": true,
-      "requires": {
-        "object-assign": "^4.1.0",
-        "strict-uri-encode": "^1.0.0"
-      }
-    },
-    "querystring": {
-      "version": "0.2.0",
-      "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
-      "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=",
-      "dev": true
-    },
-    "querystring-es3": {
-      "version": "0.2.1",
-      "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz",
-      "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=",
-      "dev": true
-    },
-    "querystringify": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.1.1.tgz",
-      "integrity": "sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA==",
-      "dev": true
-    },
-    "randomatic": {
-      "version": "3.1.1",
-      "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.1.tgz",
-      "integrity": "sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw==",
-      "dev": true,
-      "requires": {
-        "is-number": "^4.0.0",
-        "kind-of": "^6.0.0",
-        "math-random": "^1.0.1"
-      },
-      "dependencies": {
-        "is-number": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz",
-          "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==",
-          "dev": true
-        },
-        "kind-of": {
-          "version": "6.0.2",
-          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
-          "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
-          "dev": true
-        }
-      }
-    },
-    "range-parser": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
-      "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
-      "dev": true
-    },
-    "raw-body": {
-      "version": "2.4.0",
-      "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.0.tgz",
-      "integrity": "sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==",
-      "dev": true,
-      "requires": {
-        "bytes": "3.1.0",
-        "http-errors": "1.7.2",
-        "iconv-lite": "0.4.24",
-        "unpipe": "1.0.0"
-      },
-      "dependencies": {
-        "bytes": {
-          "version": "3.1.0",
-          "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
-          "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==",
-          "dev": true
-        }
-      }
-    },
-    "read-pkg": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
-      "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=",
-      "requires": {
-        "load-json-file": "^1.0.0",
-        "normalize-package-data": "^2.3.2",
-        "path-type": "^1.0.0"
-      }
-    },
-    "read-pkg-up": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz",
-      "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=",
-      "requires": {
-        "find-up": "^1.0.0",
-        "read-pkg": "^1.0.0"
-      }
-    },
-    "readable-stream": {
-      "version": "2.3.6",
-      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz",
-      "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==",
-      "requires": {
-        "core-util-is": "~1.0.0",
-        "inherits": "~2.0.3",
-        "isarray": "~1.0.0",
-        "process-nextick-args": "~2.0.0",
-        "safe-buffer": "~5.1.1",
-        "string_decoder": "~1.1.1",
-        "util-deprecate": "~1.0.1"
-      }
-    },
-    "readdirp": {
-      "version": "2.2.1",
-      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz",
-      "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==",
-      "dev": true,
-      "requires": {
-        "graceful-fs": "^4.1.11",
-        "micromatch": "^3.1.10",
-        "readable-stream": "^2.0.2"
-      },
-      "dependencies": {
-        "arr-diff": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
-          "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=",
-          "dev": true
-        },
-        "array-unique": {
-          "version": "0.3.2",
-          "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz",
-          "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=",
-          "dev": true
-        },
-        "braces": {
-          "version": "2.3.2",
-          "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz",
-          "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==",
-          "dev": true,
-          "requires": {
-            "arr-flatten": "^1.1.0",
-            "array-unique": "^0.3.2",
-            "extend-shallow": "^2.0.1",
-            "fill-range": "^4.0.0",
-            "isobject": "^3.0.1",
-            "repeat-element": "^1.1.2",
-            "snapdragon": "^0.8.1",
-            "snapdragon-node": "^2.0.1",
-            "split-string": "^3.0.2",
-            "to-regex": "^3.0.1"
-          },
-          "dependencies": {
-            "extend-shallow": {
-              "version": "2.0.1",
-              "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
-              "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
-              "dev": true,
-              "requires": {
-                "is-extendable": "^0.1.0"
-              }
-            }
-          }
-        },
-        "expand-brackets": {
-          "version": "2.1.4",
-          "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz",
-          "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=",
-          "dev": true,
-          "requires": {
-            "debug": "^2.3.3",
-            "define-property": "^0.2.5",
-            "extend-shallow": "^2.0.1",
-            "posix-character-classes": "^0.1.0",
-            "regex-not": "^1.0.0",
-            "snapdragon": "^0.8.1",
-            "to-regex": "^3.0.1"
-          },
-          "dependencies": {
-            "define-property": {
-              "version": "0.2.5",
-              "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
-              "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
-              "dev": true,
-              "requires": {
-                "is-descriptor": "^0.1.0"
-              }
-            },
-            "extend-shallow": {
-              "version": "2.0.1",
-              "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
-              "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
-              "dev": true,
-              "requires": {
-                "is-extendable": "^0.1.0"
-              }
-            },
-            "is-accessor-descriptor": {
-              "version": "0.1.6",
-              "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz",
-              "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=",
-              "dev": true,
-              "requires": {
-                "kind-of": "^3.0.2"
-              },
-              "dependencies": {
-                "kind-of": {
-                  "version": "3.2.2",
-                  "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
-                  "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
-                  "dev": true,
-                  "requires": {
-                    "is-buffer": "^1.1.5"
-                  }
-                }
-              }
-            },
-            "is-data-descriptor": {
-              "version": "0.1.4",
-              "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz",
-              "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=",
-              "dev": true,
-              "requires": {
-                "kind-of": "^3.0.2"
-              },
-              "dependencies": {
-                "kind-of": {
-                  "version": "3.2.2",
-                  "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
-                  "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
-                  "dev": true,
-                  "requires": {
-                    "is-buffer": "^1.1.5"
-                  }
-                }
-              }
-            },
-            "is-descriptor": {
-              "version": "0.1.6",
-              "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz",
-              "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==",
-              "dev": true,
-              "requires": {
-                "is-accessor-descriptor": "^0.1.6",
-                "is-data-descriptor": "^0.1.4",
-                "kind-of": "^5.0.0"
-              }
-            },
-            "kind-of": {
-              "version": "5.1.0",
-              "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz",
-              "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==",
-              "dev": true
-            }
-          }
-        },
-        "extglob": {
-          "version": "2.0.4",
-          "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz",
-          "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==",
-          "dev": true,
-          "requires": {
-            "array-unique": "^0.3.2",
-            "define-property": "^1.0.0",
-            "expand-brackets": "^2.1.4",
-            "extend-shallow": "^2.0.1",
-            "fragment-cache": "^0.2.1",
-            "regex-not": "^1.0.0",
-            "snapdragon": "^0.8.1",
-            "to-regex": "^3.0.1"
-          },
-          "dependencies": {
-            "define-property": {
-              "version": "1.0.0",
-              "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
-              "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
-              "dev": true,
-              "requires": {
-                "is-descriptor": "^1.0.0"
-              }
-            },
-            "extend-shallow": {
-              "version": "2.0.1",
-              "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
-              "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
-              "dev": true,
-              "requires": {
-                "is-extendable": "^0.1.0"
-              }
-            }
-          }
-        },
-        "fill-range": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz",
-          "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=",
-          "dev": true,
-          "requires": {
-            "extend-shallow": "^2.0.1",
-            "is-number": "^3.0.0",
-            "repeat-string": "^1.6.1",
-            "to-regex-range": "^2.1.0"
-          },
-          "dependencies": {
-            "extend-shallow": {
-              "version": "2.0.1",
-              "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
-              "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
-              "dev": true,
-              "requires": {
-                "is-extendable": "^0.1.0"
-              }
-            }
-          }
-        },
-        "is-accessor-descriptor": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
-          "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
-          "dev": true,
-          "requires": {
-            "kind-of": "^6.0.0"
-          }
-        },
-        "is-data-descriptor": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
-          "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
-          "dev": true,
-          "requires": {
-            "kind-of": "^6.0.0"
-          }
-        },
-        "is-descriptor": {
-          "version": "1.0.2",
-          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
-          "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
-          "dev": true,
-          "requires": {
-            "is-accessor-descriptor": "^1.0.0",
-            "is-data-descriptor": "^1.0.0",
-            "kind-of": "^6.0.2"
-          }
-        },
-        "is-number": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
-          "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
-          "dev": true,
-          "requires": {
-            "kind-of": "^3.0.2"
-          },
-          "dependencies": {
-            "kind-of": {
-              "version": "3.2.2",
-              "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
-              "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
-              "dev": true,
-              "requires": {
-                "is-buffer": "^1.1.5"
-              }
-            }
-          }
-        },
-        "isobject": {
-          "version": "3.0.1",
-          "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
-          "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
-          "dev": true
-        },
-        "kind-of": {
-          "version": "6.0.2",
-          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
-          "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
-          "dev": true
-        },
-        "micromatch": {
-          "version": "3.1.10",
-          "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz",
-          "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==",
-          "dev": true,
-          "requires": {
-            "arr-diff": "^4.0.0",
-            "array-unique": "^0.3.2",
-            "braces": "^2.3.1",
-            "define-property": "^2.0.2",
-            "extend-shallow": "^3.0.2",
-            "extglob": "^2.0.4",
-            "fragment-cache": "^0.2.1",
-            "kind-of": "^6.0.2",
-            "nanomatch": "^1.2.9",
-            "object.pick": "^1.3.0",
-            "regex-not": "^1.0.0",
-            "snapdragon": "^0.8.1",
-            "to-regex": "^3.0.2"
-          }
-        }
-      }
-    },
-    "readline2": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/readline2/-/readline2-1.0.1.tgz",
-      "integrity": "sha1-QQWWCP/BVHV7cV2ZidGZ/783LjU=",
-      "dev": true,
-      "requires": {
-        "code-point-at": "^1.0.0",
-        "is-fullwidth-code-point": "^1.0.0",
-        "mute-stream": "0.0.5"
-      }
-    },
-    "recast": {
-      "version": "0.11.23",
-      "resolved": "https://registry.npmjs.org/recast/-/recast-0.11.23.tgz",
-      "integrity": "sha1-RR/TAEqx5N+bTktmN2sqIZEkYtM=",
-      "requires": {
-        "ast-types": "0.9.6",
-        "esprima": "~3.1.0",
-        "private": "~0.1.5",
-        "source-map": "~0.5.0"
-      },
-      "dependencies": {
-        "esprima": {
-          "version": "3.1.3",
-          "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz",
-          "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM="
-        },
-        "source-map": {
-          "version": "0.5.7",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
-          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w="
-        }
-      }
-    },
-    "rechoir": {
-      "version": "0.6.2",
-      "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz",
-      "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=",
-      "dev": true,
-      "requires": {
-        "resolve": "^1.1.6"
-      }
-    },
-    "redent": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz",
-      "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=",
-      "requires": {
-        "indent-string": "^2.1.0",
-        "strip-indent": "^1.0.1"
-      }
-    },
-    "reduce-css-calc": {
-      "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz",
-      "integrity": "sha1-dHyRTgSWFKTJz7umKYca0dKSdxY=",
-      "dev": true,
-      "requires": {
-        "balanced-match": "^0.4.2",
-        "math-expression-evaluator": "^1.2.14",
-        "reduce-function-call": "^1.0.1"
-      },
-      "dependencies": {
-        "balanced-match": {
-          "version": "0.4.2",
-          "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz",
-          "integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg=",
-          "dev": true
-        }
-      }
-    },
-    "reduce-function-call": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/reduce-function-call/-/reduce-function-call-1.0.2.tgz",
-      "integrity": "sha1-WiAL+S4ON3UXUv5FsKszD9S2vpk=",
-      "dev": true,
-      "requires": {
-        "balanced-match": "^0.4.2"
-      },
-      "dependencies": {
-        "balanced-match": {
-          "version": "0.4.2",
-          "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz",
-          "integrity": "sha1-yz8+PHMtwPAe5wtAPzAuYddwmDg=",
-          "dev": true
-        }
-      }
-    },
-    "regenerate": {
-      "version": "1.4.0",
-      "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.0.tgz",
-      "integrity": "sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==",
-      "dev": true
-    },
-    "regenerator-runtime": {
-      "version": "0.11.1",
-      "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz",
-      "integrity": "sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg=="
-    },
-    "regenerator-transform": {
-      "version": "0.10.1",
-      "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.10.1.tgz",
-      "integrity": "sha512-PJepbvDbuK1xgIgnau7Y90cwaAmO/LCLMI2mPvaXq2heGMR3aWW5/BQvYrhJ8jgmQjXewXvBjzfqKcVOmhjZ6Q==",
-      "dev": true,
-      "requires": {
-        "babel-runtime": "^6.18.0",
-        "babel-types": "^6.19.0",
-        "private": "^0.1.6"
-      }
-    },
-    "regex-cache": {
-      "version": "0.4.4",
-      "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz",
-      "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==",
-      "dev": true,
-      "requires": {
-        "is-equal-shallow": "^0.1.3"
-      }
-    },
-    "regex-not": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz",
-      "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==",
-      "dev": true,
-      "requires": {
-        "extend-shallow": "^3.0.2",
-        "safe-regex": "^1.1.0"
-      }
-    },
-    "regexpu-core": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz",
-      "integrity": "sha1-SdA4g3uNz4v6W5pCE5k45uoq4kA=",
-      "dev": true,
-      "requires": {
-        "regenerate": "^1.2.1",
-        "regjsgen": "^0.2.0",
-        "regjsparser": "^0.1.4"
-      }
-    },
-    "regjsgen": {
-      "version": "0.2.0",
-      "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz",
-      "integrity": "sha1-bAFq3qxVT3WCP+N6wFuS1aTtsfc=",
-      "dev": true
-    },
-    "regjsparser": {
-      "version": "0.1.5",
-      "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz",
-      "integrity": "sha1-fuj4Tcb6eS0/0K4ijSS9lJ6tIFw=",
-      "dev": true,
-      "requires": {
-        "jsesc": "~0.5.0"
-      },
-      "dependencies": {
-        "jsesc": {
-          "version": "0.5.0",
-          "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz",
-          "integrity": "sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=",
-          "dev": true
-        }
-      }
-    },
-    "relateurl": {
-      "version": "0.2.7",
-      "resolved": "https://registry.npmjs.org/relateurl/-/relateurl-0.2.7.tgz",
-      "integrity": "sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=",
-      "dev": true
-    },
-    "remove-trailing-separator": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
-      "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=",
-      "dev": true
-    },
-    "renderkid": {
-      "version": "2.0.3",
-      "resolved": "https://registry.npmjs.org/renderkid/-/renderkid-2.0.3.tgz",
-      "integrity": "sha512-z8CLQp7EZBPCwCnncgf9C4XAi3WR0dv+uWu/PjIyhhAb5d6IJ/QZqlHFprHeKT+59//V6BNUsLbvN8+2LarxGA==",
-      "dev": true,
-      "requires": {
-        "css-select": "^1.1.0",
-        "dom-converter": "^0.2",
-        "htmlparser2": "^3.3.0",
-        "strip-ansi": "^3.0.0",
-        "utila": "^0.4.0"
-      }
-    },
-    "repeat-element": {
-      "version": "1.1.3",
-      "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz",
-      "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==",
-      "dev": true
-    },
-    "repeat-string": {
-      "version": "1.6.1",
-      "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
-      "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=",
-      "dev": true
-    },
-    "repeating": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz",
-      "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=",
-      "requires": {
-        "is-finite": "^1.0.0"
-      }
-    },
-    "request": {
-      "version": "2.88.0",
-      "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz",
-      "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==",
-      "requires": {
-        "aws-sign2": "~0.7.0",
-        "aws4": "^1.8.0",
-        "caseless": "~0.12.0",
-        "combined-stream": "~1.0.6",
-        "extend": "~3.0.2",
-        "forever-agent": "~0.6.1",
-        "form-data": "~2.3.2",
-        "har-validator": "~5.1.0",
-        "http-signature": "~1.2.0",
-        "is-typedarray": "~1.0.0",
-        "isstream": "~0.1.2",
-        "json-stringify-safe": "~5.0.1",
-        "mime-types": "~2.1.19",
-        "oauth-sign": "~0.9.0",
-        "performance-now": "^2.1.0",
-        "qs": "~6.5.2",
-        "safe-buffer": "^5.1.2",
-        "tough-cookie": "~2.4.3",
-        "tunnel-agent": "^0.6.0",
-        "uuid": "^3.3.2"
-      }
-    },
-    "require-directory": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
-      "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I="
-    },
-    "require-main-filename": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz",
-      "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE="
-    },
-    "require-uncached": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/require-uncached/-/require-uncached-1.0.3.tgz",
-      "integrity": "sha1-Tg1W1slmL9MeQwEcS5WqSZVUIdM=",
-      "dev": true,
-      "requires": {
-        "caller-path": "^0.1.0",
-        "resolve-from": "^1.0.0"
-      }
-    },
-    "requires-port": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
-      "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=",
-      "dev": true
-    },
-    "resolve": {
-      "version": "1.11.1",
-      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.11.1.tgz",
-      "integrity": "sha512-vIpgF6wfuJOZI7KKKSP+HmiKggadPQAdsp5HiC1mvqnfp0gF1vdwgBWZIdrVft9pgqoMFQN+R7BSWZiBxx+BBw==",
-      "requires": {
-        "path-parse": "^1.0.6"
-      }
-    },
-    "resolve-from": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-1.0.1.tgz",
-      "integrity": "sha1-Jsv+k10a7uq7Kbw/5a6wHpPUQiY=",
-      "dev": true
-    },
-    "resolve-url": {
-      "version": "0.2.1",
-      "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
-      "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=",
-      "dev": true
-    },
-    "restore-cursor": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-1.0.1.tgz",
-      "integrity": "sha1-NGYfRohjJ/7SmRR5FSJS35LapUE=",
-      "dev": true,
-      "requires": {
-        "exit-hook": "^1.0.0",
-        "onetime": "^1.0.0"
-      }
-    },
-    "ret": {
-      "version": "0.1.15",
-      "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz",
-      "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==",
-      "dev": true
-    },
-    "right-align": {
-      "version": "0.1.3",
-      "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz",
-      "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=",
-      "dev": true,
-      "requires": {
-        "align-text": "^0.1.1"
-      }
-    },
-    "rimraf": {
-      "version": "2.6.3",
-      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz",
-      "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==",
-      "requires": {
-        "glob": "^7.1.3"
-      }
-    },
-    "ripemd160": {
-      "version": "0.2.0",
-      "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-0.2.0.tgz",
-      "integrity": "sha1-K/GYveFnys+lHAqSjoS2i74XH84=",
-      "dev": true
-    },
-    "run-async": {
-      "version": "0.1.0",
-      "resolved": "https://registry.npmjs.org/run-async/-/run-async-0.1.0.tgz",
-      "integrity": "sha1-yK1KXhEGYeQCp9IbUw4AnyX444k=",
-      "dev": true,
-      "requires": {
-        "once": "^1.3.0"
-      }
-    },
-    "rx-lite": {
-      "version": "3.1.2",
-      "resolved": "https://registry.npmjs.org/rx-lite/-/rx-lite-3.1.2.tgz",
-      "integrity": "sha1-Gc5QLKVyZl87ZHsQk5+X/RYV8QI=",
-      "dev": true
-    },
-    "safe-buffer": {
-      "version": "5.1.2",
-      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
-      "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
-    },
-    "safe-regex": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz",
-      "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=",
-      "dev": true,
-      "requires": {
-        "ret": "~0.1.10"
-      }
-    },
-    "safer-buffer": {
-      "version": "2.1.2",
-      "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
-      "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
-    },
-    "sass-graph": {
-      "version": "2.2.4",
-      "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-2.2.4.tgz",
-      "integrity": "sha1-E/vWPNHK8JCLn9k0dq1DpR0eC0k=",
-      "requires": {
-        "glob": "^7.0.0",
-        "lodash": "^4.0.0",
-        "scss-tokenizer": "^0.2.3",
-        "yargs": "^7.0.0"
-      }
-    },
-    "sass-loader": {
-      "version": "4.1.1",
-      "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-4.1.1.tgz",
-      "integrity": "sha1-ee+UaM8L9kbClSnh8sumvW5Rx7w=",
-      "dev": true,
-      "requires": {
-        "async": "^2.0.1",
-        "loader-utils": "^0.2.15",
-        "object-assign": "^4.1.0"
-      }
-    },
-    "sax": {
-      "version": "1.2.4",
-      "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
-      "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
-      "dev": true
-    },
-    "scss-tokenizer": {
-      "version": "0.2.3",
-      "resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz",
-      "integrity": "sha1-jrBtualyMzOCTT9VMGQRSYR85dE=",
-      "requires": {
-        "js-base64": "^2.1.8",
-        "source-map": "^0.4.2"
-      }
-    },
-    "semver": {
-      "version": "5.7.0",
-      "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz",
-      "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA=="
-    },
-    "send": {
-      "version": "0.17.1",
-      "resolved": "https://registry.npmjs.org/send/-/send-0.17.1.tgz",
-      "integrity": "sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==",
-      "dev": true,
-      "requires": {
-        "debug": "2.6.9",
-        "depd": "~1.1.2",
-        "destroy": "~1.0.4",
-        "encodeurl": "~1.0.2",
-        "escape-html": "~1.0.3",
-        "etag": "~1.8.1",
-        "fresh": "0.5.2",
-        "http-errors": "~1.7.2",
-        "mime": "1.6.0",
-        "ms": "2.1.1",
-        "on-finished": "~2.3.0",
-        "range-parser": "~1.2.1",
-        "statuses": "~1.5.0"
-      },
-      "dependencies": {
-        "ms": {
-          "version": "2.1.1",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
-          "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
-          "dev": true
-        }
-      }
-    },
-    "sentence-case": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/sentence-case/-/sentence-case-2.1.1.tgz",
-      "integrity": "sha1-H24t2jnBaL+S0T+G1KkYkz9mftQ=",
-      "dev": true,
-      "requires": {
-        "no-case": "^2.2.0",
-        "upper-case-first": "^1.1.2"
-      }
-    },
-    "serve-index": {
-      "version": "1.9.1",
-      "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz",
-      "integrity": "sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=",
-      "dev": true,
-      "requires": {
-        "accepts": "~1.3.4",
-        "batch": "0.6.1",
-        "debug": "2.6.9",
-        "escape-html": "~1.0.3",
-        "http-errors": "~1.6.2",
-        "mime-types": "~2.1.17",
-        "parseurl": "~1.3.2"
-      },
-      "dependencies": {
-        "http-errors": {
-          "version": "1.6.3",
-          "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz",
-          "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=",
-          "dev": true,
-          "requires": {
-            "depd": "~1.1.2",
-            "inherits": "2.0.3",
-            "setprototypeof": "1.1.0",
-            "statuses": ">= 1.4.0 < 2"
-          }
-        },
-        "inherits": {
-          "version": "2.0.3",
-          "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
-          "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
-          "dev": true
-        },
-        "setprototypeof": {
-          "version": "1.1.0",
-          "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz",
-          "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==",
-          "dev": true
-        }
-      }
-    },
-    "serve-static": {
-      "version": "1.14.1",
-      "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.14.1.tgz",
-      "integrity": "sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==",
-      "dev": true,
-      "requires": {
-        "encodeurl": "~1.0.2",
-        "escape-html": "~1.0.3",
-        "parseurl": "~1.3.3",
-        "send": "0.17.1"
-      }
-    },
-    "set-blocking": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
-      "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc="
-    },
-    "set-value": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz",
-      "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==",
-      "dev": true,
-      "requires": {
-        "extend-shallow": "^2.0.1",
-        "is-extendable": "^0.1.1",
-        "is-plain-object": "^2.0.3",
-        "split-string": "^3.0.1"
-      },
-      "dependencies": {
-        "extend-shallow": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
-          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
-          "dev": true,
-          "requires": {
-            "is-extendable": "^0.1.0"
-          }
-        }
-      }
-    },
-    "setimmediate": {
-      "version": "1.0.5",
-      "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
-      "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=",
-      "dev": true
-    },
-    "setprototypeof": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz",
-      "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==",
-      "dev": true
-    },
-    "sha.js": {
-      "version": "2.2.6",
-      "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.2.6.tgz",
-      "integrity": "sha1-F93t3F9yL7ZlAWWIlUYZd4ZzFbo=",
-      "dev": true
-    },
-    "shelljs": {
-      "version": "0.7.8",
-      "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.7.8.tgz",
-      "integrity": "sha1-3svPh0sNHl+3LhSxZKloMEjprLM=",
-      "dev": true,
-      "requires": {
-        "glob": "^7.0.0",
-        "interpret": "^1.0.0",
-        "rechoir": "^0.6.2"
-      }
-    },
-    "signal-exit": {
-      "version": "3.0.2",
-      "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
-      "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0="
-    },
-    "slash": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz",
-      "integrity": "sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU=",
-      "dev": true
-    },
-    "slice-ansi": {
-      "version": "0.0.4",
-      "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-0.0.4.tgz",
-      "integrity": "sha1-7b+JA/ZvfOL46v1s7tZeJkyDGzU=",
-      "dev": true
-    },
-    "snake-case": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-2.1.0.tgz",
-      "integrity": "sha1-Qb2xtz8w7GagTU4srRt2OH1NbZ8=",
-      "dev": true,
-      "requires": {
-        "no-case": "^2.2.0"
-      }
-    },
-    "snapdragon": {
-      "version": "0.8.2",
-      "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz",
-      "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==",
-      "dev": true,
-      "requires": {
-        "base": "^0.11.1",
-        "debug": "^2.2.0",
-        "define-property": "^0.2.5",
-        "extend-shallow": "^2.0.1",
-        "map-cache": "^0.2.2",
-        "source-map": "^0.5.6",
-        "source-map-resolve": "^0.5.0",
-        "use": "^3.1.0"
-      },
-      "dependencies": {
-        "define-property": {
-          "version": "0.2.5",
-          "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
-          "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
-          "dev": true,
-          "requires": {
-            "is-descriptor": "^0.1.0"
-          }
-        },
-        "extend-shallow": {
-          "version": "2.0.1",
-          "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz",
-          "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=",
-          "dev": true,
-          "requires": {
-            "is-extendable": "^0.1.0"
-          }
-        },
-        "source-map": {
-          "version": "0.5.7",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
-          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
-          "dev": true
-        }
-      }
-    },
-    "snapdragon-node": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz",
-      "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==",
-      "dev": true,
-      "requires": {
-        "define-property": "^1.0.0",
-        "isobject": "^3.0.0",
-        "snapdragon-util": "^3.0.1"
-      },
-      "dependencies": {
-        "define-property": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz",
-          "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=",
-          "dev": true,
-          "requires": {
-            "is-descriptor": "^1.0.0"
-          }
-        },
-        "is-accessor-descriptor": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz",
-          "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==",
-          "dev": true,
-          "requires": {
-            "kind-of": "^6.0.0"
-          }
-        },
-        "is-data-descriptor": {
-          "version": "1.0.0",
-          "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz",
-          "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==",
-          "dev": true,
-          "requires": {
-            "kind-of": "^6.0.0"
-          }
-        },
-        "is-descriptor": {
-          "version": "1.0.2",
-          "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz",
-          "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==",
-          "dev": true,
-          "requires": {
-            "is-accessor-descriptor": "^1.0.0",
-            "is-data-descriptor": "^1.0.0",
-            "kind-of": "^6.0.2"
-          }
-        },
-        "isobject": {
-          "version": "3.0.1",
-          "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
-          "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
-          "dev": true
-        },
-        "kind-of": {
-          "version": "6.0.2",
-          "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz",
-          "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==",
-          "dev": true
-        }
-      }
-    },
-    "snapdragon-util": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz",
-      "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==",
-      "dev": true,
-      "requires": {
-        "kind-of": "^3.2.0"
-      }
-    },
-    "sockjs": {
-      "version": "0.3.19",
-      "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.19.tgz",
-      "integrity": "sha512-V48klKZl8T6MzatbLlzzRNhMepEys9Y4oGFpypBFFn1gLI/QQ9HtLLyWJNbPlwGLelOVOEijUbTTJeLLI59jLw==",
-      "dev": true,
-      "requires": {
-        "faye-websocket": "^0.10.0",
-        "uuid": "^3.0.1"
-      }
-    },
-    "sockjs-client": {
-      "version": "1.3.0",
-      "resolved": "https://registry.npmjs.org/sockjs-client/-/sockjs-client-1.3.0.tgz",
-      "integrity": "sha512-R9jxEzhnnrdxLCNln0xg5uGHqMnkhPSTzUZH2eXcR03S/On9Yvoq2wyUZILRUhZCNVu2PmwWVoyuiPz8th8zbg==",
-      "dev": true,
-      "requires": {
-        "debug": "^3.2.5",
-        "eventsource": "^1.0.7",
-        "faye-websocket": "~0.11.1",
-        "inherits": "^2.0.3",
-        "json3": "^3.3.2",
-        "url-parse": "^1.4.3"
-      },
-      "dependencies": {
-        "debug": {
-          "version": "3.2.6",
-          "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
-          "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
-          "dev": true,
-          "requires": {
-            "ms": "^2.1.1"
-          }
-        },
-        "faye-websocket": {
-          "version": "0.11.3",
-          "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.3.tgz",
-          "integrity": "sha512-D2y4bovYpzziGgbHYtGCMjlJM36vAl/y+xUyn1C+FVx8szd1E+86KwVw6XvYSzOP8iMpm1X0I4xJD+QtUb36OA==",
-          "dev": true,
-          "requires": {
-            "websocket-driver": ">=0.5.1"
-          }
-        },
-        "ms": {
-          "version": "2.1.2",
-          "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
-          "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
-          "dev": true
-        }
-      }
-    },
-    "sort-keys": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-1.1.2.tgz",
-      "integrity": "sha1-RBttTTRnmPG05J6JIK37oOVD+a0=",
-      "dev": true,
-      "requires": {
-        "is-plain-obj": "^1.0.0"
-      }
-    },
-    "source-list-map": {
-      "version": "0.1.8",
-      "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-0.1.8.tgz",
-      "integrity": "sha1-xVCyq1Qn9rPyH1r+rYjE9Vh7IQY=",
-      "dev": true
-    },
-    "source-map": {
-      "version": "0.4.4",
-      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz",
-      "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=",
-      "requires": {
-        "amdefine": ">=0.0.4"
-      }
-    },
-    "source-map-resolve": {
-      "version": "0.5.2",
-      "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz",
-      "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==",
-      "dev": true,
-      "requires": {
-        "atob": "^2.1.1",
-        "decode-uri-component": "^0.2.0",
-        "resolve-url": "^0.2.1",
-        "source-map-url": "^0.4.0",
-        "urix": "^0.1.0"
-      }
-    },
-    "source-map-support": {
-      "version": "0.4.18",
-      "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz",
-      "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==",
-      "dev": true,
-      "requires": {
-        "source-map": "^0.5.6"
-      },
-      "dependencies": {
-        "source-map": {
-          "version": "0.5.7",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
-          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
-          "dev": true
-        }
-      }
-    },
-    "source-map-url": {
-      "version": "0.4.0",
-      "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz",
-      "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=",
-      "dev": true
-    },
-    "spdx-correct": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz",
-      "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==",
-      "requires": {
-        "spdx-expression-parse": "^3.0.0",
-        "spdx-license-ids": "^3.0.0"
-      }
-    },
-    "spdx-exceptions": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz",
-      "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA=="
-    },
-    "spdx-expression-parse": {
-      "version": "3.0.0",
-      "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz",
-      "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==",
-      "requires": {
-        "spdx-exceptions": "^2.1.0",
-        "spdx-license-ids": "^3.0.0"
-      }
-    },
-    "spdx-license-ids": {
-      "version": "3.0.5",
-      "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz",
-      "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q=="
-    },
-    "split-string": {
-      "version": "3.1.0",
-      "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz",
-      "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==",
-      "dev": true,
-      "requires": {
-        "extend-shallow": "^3.0.0"
-      }
-    },
-    "sprintf-js": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
-      "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=",
-      "dev": true
-    },
-    "sshpk": {
-      "version": "1.16.1",
-      "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz",
-      "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==",
-      "requires": {
-        "asn1": "~0.2.3",
-        "assert-plus": "^1.0.0",
-        "bcrypt-pbkdf": "^1.0.0",
-        "dashdash": "^1.12.0",
-        "ecc-jsbn": "~0.1.1",
-        "getpass": "^0.1.1",
-        "jsbn": "~0.1.0",
-        "safer-buffer": "^2.0.2",
-        "tweetnacl": "~0.14.0"
-      }
-    },
-    "static-extend": {
-      "version": "0.1.2",
-      "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz",
-      "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=",
-      "dev": true,
-      "requires": {
-        "define-property": "^0.2.5",
-        "object-copy": "^0.1.0"
-      },
-      "dependencies": {
-        "define-property": {
-          "version": "0.2.5",
-          "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz",
-          "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=",
-          "dev": true,
-          "requires": {
-            "is-descriptor": "^0.1.0"
-          }
-        }
-      }
-    },
-    "statuses": {
-      "version": "1.5.0",
-      "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz",
-      "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=",
-      "dev": true
-    },
-    "stdout-stream": {
-      "version": "1.4.1",
-      "resolved": "https://registry.npmjs.org/stdout-stream/-/stdout-stream-1.4.1.tgz",
-      "integrity": "sha512-j4emi03KXqJWcIeF8eIXkjMFN1Cmb8gUlDYGeBALLPo5qdyTfA9bOtl8m33lRoC+vFMkP3gl0WsDr6+gzxbbTA==",
-      "requires": {
-        "readable-stream": "^2.0.1"
-      }
-    },
-    "stream-browserify": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz",
-      "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==",
-      "dev": true,
-      "requires": {
-        "inherits": "~2.0.1",
-        "readable-stream": "^2.0.2"
-      }
-    },
-    "stream-cache": {
-      "version": "0.0.2",
-      "resolved": "https://registry.npmjs.org/stream-cache/-/stream-cache-0.0.2.tgz",
-      "integrity": "sha1-GsWtaDJCjKVWZ9ve45Xa1ObbEY8=",
-      "dev": true
-    },
-    "stream-http": {
-      "version": "2.8.3",
-      "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz",
-      "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==",
-      "dev": true,
-      "requires": {
-        "builtin-status-codes": "^3.0.0",
-        "inherits": "^2.0.1",
-        "readable-stream": "^2.3.6",
-        "to-arraybuffer": "^1.0.0",
-        "xtend": "^4.0.0"
-      }
-    },
-    "strict-uri-encode": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz",
-      "integrity": "sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=",
-      "dev": true
-    },
-    "string-width": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
-      "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
-      "requires": {
-        "code-point-at": "^1.0.0",
-        "is-fullwidth-code-point": "^1.0.0",
-        "strip-ansi": "^3.0.0"
-      }
-    },
-    "string_decoder": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
-      "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
-      "requires": {
-        "safe-buffer": "~5.1.0"
-      }
-    },
-    "strip-ansi": {
-      "version": "3.0.1",
-      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
-      "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
-      "requires": {
-        "ansi-regex": "^2.0.0"
-      }
-    },
-    "strip-bom": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
-      "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=",
-      "requires": {
-        "is-utf8": "^0.2.0"
-      }
-    },
-    "strip-indent": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz",
-      "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=",
-      "requires": {
-        "get-stdin": "^4.0.1"
-      }
-    },
-    "strip-json-comments": {
-      "version": "2.0.1",
-      "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
-      "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=",
-      "dev": true
-    },
-    "style-loader": {
-      "version": "0.13.2",
-      "resolved": "https://registry.npmjs.org/style-loader/-/style-loader-0.13.2.tgz",
-      "integrity": "sha1-dFMzhM9pjHEEx5URULSXF63C87s=",
-      "dev": true,
-      "requires": {
-        "loader-utils": "^1.0.2"
-      },
-      "dependencies": {
-        "big.js": {
-          "version": "5.2.2",
-          "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
-          "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==",
-          "dev": true
-        },
-        "json5": {
-          "version": "1.0.1",
-          "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
-          "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
-          "dev": true,
-          "requires": {
-            "minimist": "^1.2.0"
-          }
-        },
-        "loader-utils": {
-          "version": "1.2.3",
-          "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz",
-          "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==",
-          "dev": true,
-          "requires": {
-            "big.js": "^5.2.2",
-            "emojis-list": "^2.0.0",
-            "json5": "^1.0.1"
-          }
-        }
-      }
-    },
-    "supports-color": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
-      "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc="
-    },
-    "svgo": {
-      "version": "0.7.2",
-      "resolved": "https://registry.npmjs.org/svgo/-/svgo-0.7.2.tgz",
-      "integrity": "sha1-n1dyQTlSE1xv779Ar+ak+qiLS7U=",
-      "dev": true,
-      "requires": {
-        "coa": "~1.0.1",
-        "colors": "~1.1.2",
-        "csso": "~2.3.1",
-        "js-yaml": "~3.7.0",
-        "mkdirp": "~0.5.1",
-        "sax": "~1.2.1",
-        "whet.extend": "~0.9.9"
-      }
-    },
-    "swap-case": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/swap-case/-/swap-case-1.1.2.tgz",
-      "integrity": "sha1-w5IDpFhzhfrTyFCgvRvK+ggZdOM=",
-      "dev": true,
-      "requires": {
-        "lower-case": "^1.1.1",
-        "upper-case": "^1.1.1"
-      }
-    },
-    "table": {
-      "version": "3.8.3",
-      "resolved": "https://registry.npmjs.org/table/-/table-3.8.3.tgz",
-      "integrity": "sha1-K7xULw/amGGnVdOUf+/Ys/UThV8=",
-      "dev": true,
-      "requires": {
-        "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"
-      },
-      "dependencies": {
-        "ajv": {
-          "version": "4.11.8",
-          "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz",
-          "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=",
-          "dev": true,
-          "requires": {
-            "co": "^4.6.0",
-            "json-stable-stringify": "^1.0.1"
-          }
-        },
-        "ansi-regex": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
-          "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=",
-          "dev": true
-        },
-        "is-fullwidth-code-point": {
-          "version": "2.0.0",
-          "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
-          "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=",
-          "dev": true
-        },
-        "string-width": {
-          "version": "2.1.1",
-          "resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
-          "integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
-          "dev": true,
-          "requires": {
-            "is-fullwidth-code-point": "^2.0.0",
-            "strip-ansi": "^4.0.0"
-          }
-        },
-        "strip-ansi": {
-          "version": "4.0.0",
-          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
-          "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
-          "dev": true,
-          "requires": {
-            "ansi-regex": "^3.0.0"
-          }
-        }
-      }
-    },
-    "tapable": {
-      "version": "0.1.10",
-      "resolved": "https://registry.npmjs.org/tapable/-/tapable-0.1.10.tgz",
-      "integrity": "sha1-KcNXB8K3DlDQdIK10gLo7URtr9Q=",
-      "dev": true
-    },
-    "tar": {
-      "version": "2.2.2",
-      "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.2.tgz",
-      "integrity": "sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA==",
-      "requires": {
-        "block-stream": "*",
-        "fstream": "^1.0.12",
-        "inherits": "2"
-      }
-    },
-    "text-table": {
-      "version": "0.2.0",
-      "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
-      "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=",
-      "dev": true
-    },
-    "through": {
-      "version": "2.3.8",
-      "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
-      "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU="
-    },
-    "time-stamp": {
-      "version": "2.2.0",
-      "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-2.2.0.tgz",
-      "integrity": "sha512-zxke8goJQpBeEgD82CXABeMh0LSJcj7CXEd0OHOg45HgcofF7pxNwZm9+RknpxpDhwN4gFpySkApKfFYfRQnUA==",
-      "dev": true
-    },
-    "timers-browserify": {
-      "version": "2.0.10",
-      "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.10.tgz",
-      "integrity": "sha512-YvC1SV1XdOUaL6gx5CoGroT3Gu49pK9+TZ38ErPldOWW4j49GI1HKs9DV+KGq/w6y+LZ72W1c8cKz2vzY+qpzg==",
-      "dev": true,
-      "requires": {
-        "setimmediate": "^1.0.4"
-      }
-    },
-    "title-case": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/title-case/-/title-case-2.1.1.tgz",
-      "integrity": "sha1-PhJyFtpY0rxb7PE3q5Ha46fNj6o=",
-      "dev": true,
-      "requires": {
-        "no-case": "^2.2.0",
-        "upper-case": "^1.0.3"
-      }
-    },
-    "to-arraybuffer": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz",
-      "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=",
-      "dev": true
-    },
-    "to-fast-properties": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz",
-      "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc=",
-      "dev": true
-    },
-    "to-object-path": {
-      "version": "0.3.0",
-      "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz",
-      "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=",
-      "dev": true,
-      "requires": {
-        "kind-of": "^3.0.2"
-      }
-    },
-    "to-regex": {
-      "version": "3.0.2",
-      "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz",
-      "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==",
-      "dev": true,
-      "requires": {
-        "define-property": "^2.0.2",
-        "extend-shallow": "^3.0.2",
-        "regex-not": "^1.0.2",
-        "safe-regex": "^1.1.0"
-      }
-    },
-    "to-regex-range": {
-      "version": "2.1.1",
-      "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz",
-      "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=",
-      "dev": true,
-      "requires": {
-        "is-number": "^3.0.0",
-        "repeat-string": "^1.6.1"
-      },
-      "dependencies": {
-        "is-number": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
-          "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
-          "dev": true,
-          "requires": {
-            "kind-of": "^3.0.2"
-          }
-        }
-      }
-    },
-    "toidentifier": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz",
-      "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==",
-      "dev": true
-    },
-    "toposort": {
-      "version": "1.0.7",
-      "resolved": "https://registry.npmjs.org/toposort/-/toposort-1.0.7.tgz",
-      "integrity": "sha1-LmhELZ9k7HILjMieZEOsbKqVACk=",
-      "dev": true
-    },
-    "tough-cookie": {
-      "version": "2.4.3",
-      "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz",
-      "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==",
-      "requires": {
-        "psl": "^1.1.24",
-        "punycode": "^1.4.1"
-      },
-      "dependencies": {
-        "punycode": {
-          "version": "1.4.1",
-          "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
-          "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4="
-        }
-      }
-    },
-    "trim-newlines": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz",
-      "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM="
-    },
-    "trim-right": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/trim-right/-/trim-right-1.0.1.tgz",
-      "integrity": "sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=",
-      "dev": true
-    },
-    "true-case-path": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/true-case-path/-/true-case-path-1.0.3.tgz",
-      "integrity": "sha512-m6s2OdQe5wgpFMC+pAJ+q9djG82O2jcHPOI6RNg1yy9rCYR+WD6Nbpl32fDpfC56nirdRy+opFa/Vk7HYhqaew==",
-      "requires": {
-        "glob": "^7.1.2"
-      }
-    },
-    "tty-browserify": {
-      "version": "0.0.0",
-      "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz",
-      "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=",
-      "dev": true
-    },
-    "tunnel-agent": {
-      "version": "0.6.0",
-      "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
-      "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
-      "requires": {
-        "safe-buffer": "^5.0.1"
-      }
-    },
-    "tweetnacl": {
-      "version": "0.14.5",
-      "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
-      "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q="
-    },
-    "type": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/type/-/type-1.0.1.tgz",
-      "integrity": "sha512-MAM5dBMJCJNKs9E7JXo4CXRAansRfG0nlJxW7Wf6GZzSOvH31zClSaHdIMWLehe/EGMBkqeC55rrkaOr5Oo7Nw==",
-      "dev": true
-    },
-    "type-check": {
-      "version": "0.3.2",
-      "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
-      "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
-      "dev": true,
-      "requires": {
-        "prelude-ls": "~1.1.2"
-      }
-    },
-    "type-is": {
-      "version": "1.6.18",
-      "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
-      "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
-      "dev": true,
-      "requires": {
-        "media-typer": "0.3.0",
-        "mime-types": "~2.1.24"
-      }
-    },
-    "typedarray": {
-      "version": "0.0.6",
-      "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
-      "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=",
-      "dev": true
-    },
-    "uglify-js": {
-      "version": "3.4.10",
-      "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.4.10.tgz",
-      "integrity": "sha512-Y2VsbPVs0FIshJztycsO2SfPk7/KAF/T72qzv9u5EpQ4kB2hQoHlhNQTsNyy6ul7lQtqJN/AoWeS23OzEiEFxw==",
-      "dev": true,
-      "requires": {
-        "commander": "~2.19.0",
-        "source-map": "~0.6.1"
-      },
-      "dependencies": {
-        "commander": {
-          "version": "2.19.0",
-          "resolved": "https://registry.npmjs.org/commander/-/commander-2.19.0.tgz",
-          "integrity": "sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==",
-          "dev": true
-        },
-        "source-map": {
-          "version": "0.6.1",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
-          "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
-          "dev": true
-        }
-      }
-    },
-    "uglify-to-browserify": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz",
-      "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=",
-      "dev": true
-    },
-    "union-value": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz",
-      "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==",
-      "dev": true,
-      "requires": {
-        "arr-union": "^3.1.0",
-        "get-value": "^2.0.6",
-        "is-extendable": "^0.1.1",
-        "set-value": "^2.0.1"
-      }
-    },
-    "uniq": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/uniq/-/uniq-1.0.1.tgz",
-      "integrity": "sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=",
-      "dev": true
-    },
-    "uniqs": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/uniqs/-/uniqs-2.0.0.tgz",
-      "integrity": "sha1-/+3ks2slKQaW5uFl1KWe25mOawI=",
-      "dev": true
-    },
-    "unpipe": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
-      "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=",
-      "dev": true
-    },
-    "unset-value": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz",
-      "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=",
-      "dev": true,
-      "requires": {
-        "has-value": "^0.3.1",
-        "isobject": "^3.0.0"
-      },
-      "dependencies": {
-        "has-value": {
-          "version": "0.3.1",
-          "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz",
-          "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=",
-          "dev": true,
-          "requires": {
-            "get-value": "^2.0.3",
-            "has-values": "^0.1.4",
-            "isobject": "^2.0.0"
-          },
-          "dependencies": {
-            "isobject": {
-              "version": "2.1.0",
-              "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
-              "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
-              "dev": true,
-              "requires": {
-                "isarray": "1.0.0"
-              }
-            }
-          }
-        },
-        "has-values": {
-          "version": "0.1.4",
-          "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz",
-          "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=",
-          "dev": true
-        },
-        "isobject": {
-          "version": "3.0.1",
-          "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
-          "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=",
-          "dev": true
-        }
-      }
-    },
-    "upper-case": {
-      "version": "1.1.3",
-      "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz",
-      "integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=",
-      "dev": true
-    },
-    "upper-case-first": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/upper-case-first/-/upper-case-first-1.1.2.tgz",
-      "integrity": "sha1-XXm+3P8UQZUY/S7bCgUHybaFkRU=",
-      "dev": true,
-      "requires": {
-        "upper-case": "^1.1.1"
-      }
-    },
-    "uri-js": {
-      "version": "4.2.2",
-      "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz",
-      "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==",
-      "requires": {
-        "punycode": "^2.1.0"
-      }
-    },
-    "urix": {
-      "version": "0.1.0",
-      "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz",
-      "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=",
-      "dev": true
-    },
-    "url": {
-      "version": "0.11.0",
-      "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz",
-      "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=",
-      "dev": true,
-      "requires": {
-        "punycode": "1.3.2",
-        "querystring": "0.2.0"
-      },
-      "dependencies": {
-        "punycode": {
-          "version": "1.3.2",
-          "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz",
-          "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=",
-          "dev": true
-        }
-      }
-    },
-    "url-parse": {
-      "version": "1.4.7",
-      "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.4.7.tgz",
-      "integrity": "sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg==",
-      "dev": true,
-      "requires": {
-        "querystringify": "^2.1.1",
-        "requires-port": "^1.0.0"
-      }
-    },
-    "use": {
-      "version": "3.1.1",
-      "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz",
-      "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==",
-      "dev": true
-    },
-    "user-home": {
-      "version": "2.0.0",
-      "resolved": "https://registry.npmjs.org/user-home/-/user-home-2.0.0.tgz",
-      "integrity": "sha1-nHC/2Babwdy/SGBODwS4tJzenp8=",
-      "dev": true,
-      "requires": {
-        "os-homedir": "^1.0.0"
-      }
-    },
-    "util": {
-      "version": "0.10.4",
-      "resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz",
-      "integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==",
-      "dev": true,
-      "requires": {
-        "inherits": "2.0.3"
-      },
-      "dependencies": {
-        "inherits": {
-          "version": "2.0.3",
-          "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
-          "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
-          "dev": true
-        }
-      }
-    },
-    "util-deprecate": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
-      "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
-    },
-    "utila": {
-      "version": "0.4.0",
-      "resolved": "https://registry.npmjs.org/utila/-/utila-0.4.0.tgz",
-      "integrity": "sha1-ihagXURWV6Oupe7MWxKk+lN5dyw=",
-      "dev": true
-    },
-    "utils-merge": {
-      "version": "1.0.1",
-      "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
-      "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=",
-      "dev": true
-    },
-    "uuid": {
-      "version": "3.3.2",
-      "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz",
-      "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA=="
-    },
-    "validate-npm-package-license": {
-      "version": "3.0.4",
-      "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz",
-      "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==",
-      "requires": {
-        "spdx-correct": "^3.0.0",
-        "spdx-expression-parse": "^3.0.0"
-      }
-    },
-    "vary": {
-      "version": "1.1.2",
-      "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
-      "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=",
-      "dev": true
-    },
-    "vendors": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/vendors/-/vendors-1.0.3.tgz",
-      "integrity": "sha512-fOi47nsJP5Wqefa43kyWSg80qF+Q3XA6MUkgi7Hp1HQaKDQW4cQrK2D0P7mmbFtsV1N89am55Yru/nyEwRubcw==",
-      "dev": true
-    },
-    "verror": {
-      "version": "1.10.0",
-      "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
-      "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
-      "requires": {
-        "assert-plus": "^1.0.0",
-        "core-util-is": "1.0.2",
-        "extsprintf": "^1.2.0"
-      }
-    },
-    "vm-browserify": {
-      "version": "0.0.4",
-      "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz",
-      "integrity": "sha1-XX6kW7755Kb/ZflUOOCofDV9WnM=",
-      "dev": true,
-      "requires": {
-        "indexof": "0.0.1"
-      }
-    },
-    "vue": {
-      "version": "1.0.28",
-      "resolved": "https://registry.npmjs.org/vue/-/vue-1.0.28.tgz",
-      "integrity": "sha1-7S/weyAL3hXIepDvhyfO6n04Vn0=",
-      "requires": {
-        "envify": "^3.4.0"
-      }
-    },
-    "vue-hot-reload-api": {
-      "version": "1.3.3",
-      "resolved": "https://registry.npmjs.org/vue-hot-reload-api/-/vue-hot-reload-api-1.3.3.tgz",
-      "integrity": "sha1-VNItg3hqh4ST9jnMdrynmSojvkY=",
-      "dev": true
-    },
-    "vue-html-loader": {
-      "version": "1.2.4",
-      "resolved": "https://registry.npmjs.org/vue-html-loader/-/vue-html-loader-1.2.4.tgz",
-      "integrity": "sha1-VM5Im+BgZckdwqEXMSLz4ATgolM=",
-      "dev": true,
-      "requires": {
-        "es6-templates": "^0.2.2",
-        "fastparse": "^1.0.0",
-        "html-minifier": "^2.1.5",
-        "loader-utils": "^1.0.2",
-        "object-assign": "^4.1.0"
-      },
-      "dependencies": {
-        "async": {
-          "version": "0.2.10",
-          "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz",
-          "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=",
-          "dev": true
-        },
-        "big.js": {
-          "version": "5.2.2",
-          "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
-          "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==",
-          "dev": true
-        },
-        "camelcase": {
-          "version": "1.2.1",
-          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz",
-          "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=",
-          "dev": true
-        },
-        "clean-css": {
-          "version": "3.4.28",
-          "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-3.4.28.tgz",
-          "integrity": "sha1-vxlF6C/ICPVWlebd6uwBQA79A/8=",
-          "dev": true,
-          "requires": {
-            "commander": "2.8.x",
-            "source-map": "0.4.x"
-          },
-          "dependencies": {
-            "commander": {
-              "version": "2.8.1",
-              "resolved": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz",
-              "integrity": "sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=",
-              "dev": true,
-              "requires": {
-                "graceful-readlink": ">= 1.0.0"
-              }
-            }
-          }
-        },
-        "cliui": {
-          "version": "2.1.0",
-          "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz",
-          "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=",
-          "dev": true,
-          "requires": {
-            "center-align": "^0.1.1",
-            "right-align": "^0.1.1",
-            "wordwrap": "0.0.2"
-          }
-        },
-        "commander": {
-          "version": "2.9.0",
-          "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz",
-          "integrity": "sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=",
-          "dev": true,
-          "requires": {
-            "graceful-readlink": ">= 1.0.0"
-          }
-        },
-        "he": {
-          "version": "1.1.1",
-          "resolved": "https://registry.npmjs.org/he/-/he-1.1.1.tgz",
-          "integrity": "sha1-k0EP0hsAlzUVH4howvJx80J+I/0=",
-          "dev": true
-        },
-        "html-minifier": {
-          "version": "2.1.7",
-          "resolved": "https://registry.npmjs.org/html-minifier/-/html-minifier-2.1.7.tgz",
-          "integrity": "sha1-kFHW/LvPIU7TB+GtdPQyu5rWVcw=",
-          "dev": true,
-          "requires": {
-            "change-case": "3.0.x",
-            "clean-css": "3.4.x",
-            "commander": "2.9.x",
-            "he": "1.1.x",
-            "ncname": "1.0.x",
-            "relateurl": "0.2.x",
-            "uglify-js": "2.6.x"
-          }
-        },
-        "json5": {
-          "version": "1.0.1",
-          "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
-          "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
-          "dev": true,
-          "requires": {
-            "minimist": "^1.2.0"
-          }
-        },
-        "loader-utils": {
-          "version": "1.2.3",
-          "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz",
-          "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==",
-          "dev": true,
-          "requires": {
-            "big.js": "^5.2.2",
-            "emojis-list": "^2.0.0",
-            "json5": "^1.0.1"
-          }
-        },
-        "uglify-js": {
-          "version": "2.6.4",
-          "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.6.4.tgz",
-          "integrity": "sha1-ZeovswWck5RpLxX+2HwrNsFrmt8=",
-          "dev": true,
-          "requires": {
-            "async": "~0.2.6",
-            "source-map": "~0.5.1",
-            "uglify-to-browserify": "~1.0.0",
-            "yargs": "~3.10.0"
-          },
-          "dependencies": {
-            "source-map": {
-              "version": "0.5.7",
-              "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
-              "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
-              "dev": true
-            }
-          }
-        },
-        "wordwrap": {
-          "version": "0.0.2",
-          "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz",
-          "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=",
-          "dev": true
-        },
-        "yargs": {
-          "version": "3.10.0",
-          "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz",
-          "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=",
-          "dev": true,
-          "requires": {
-            "camelcase": "^1.0.2",
-            "cliui": "^2.1.0",
-            "decamelize": "^1.0.0",
-            "window-size": "0.1.0"
-          }
-        }
-      }
-    },
-    "vue-loader": {
-      "version": "8.7.1",
-      "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-8.7.1.tgz",
-      "integrity": "sha512-LBqMNnaoBHY09CFfdBy9GyUELMPFdxO190p0xxaYpjxfS7IP1gSpeKpyDDcKxoFpbmETOOMC7QGvt4JzsUSxKw==",
-      "dev": true,
-      "requires": {
-        "autoprefixer": "^6.0.3",
-        "consolidate": "^0.14.0",
-        "de-indent": "^1.0.0",
-        "hash-sum": "^1.0.2",
-        "loader-utils": "^1.0.2",
-        "lru-cache": "^2.7.0",
-        "object-assign": "^4.0.0",
-        "parse5": "^2.1.0",
-        "postcss": "^5.0.10",
-        "postcss-selector-parser": "^1.1.2",
-        "source-map": "^0.5.3",
-        "vue-template-validator": "^1.0.0"
-      },
-      "dependencies": {
-        "big.js": {
-          "version": "5.2.2",
-          "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz",
-          "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==",
-          "dev": true
-        },
-        "json5": {
-          "version": "1.0.1",
-          "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz",
-          "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==",
-          "dev": true,
-          "requires": {
-            "minimist": "^1.2.0"
-          }
-        },
-        "loader-utils": {
-          "version": "1.2.3",
-          "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz",
-          "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==",
-          "dev": true,
-          "requires": {
-            "big.js": "^5.2.2",
-            "emojis-list": "^2.0.0",
-            "json5": "^1.0.1"
-          }
-        },
-        "lru-cache": {
-          "version": "2.7.3",
-          "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz",
-          "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=",
-          "dev": true
-        },
-        "postcss-selector-parser": {
-          "version": "1.3.3",
-          "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-1.3.3.tgz",
-          "integrity": "sha1-0u4Z33pk+O8hwacchvfUg1yIwoE=",
-          "dev": true,
-          "requires": {
-            "flatten": "^1.0.2",
-            "indexes-of": "^1.0.1",
-            "uniq": "^1.0.1"
-          }
-        },
-        "source-map": {
-          "version": "0.5.7",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
-          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
-          "dev": true
-        }
-      }
-    },
-    "vue-roaster": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/vue-roaster/-/vue-roaster-1.1.1.tgz",
-      "integrity": "sha1-RxgwATeGLmIejX+RMMbay1mJyho=",
-      "requires": {
-        "babel-runtime": "^6.0.0",
-        "jquery": "^3.1.1",
-        "jquery-ui": "^1.12.1",
-        "vue": "^1.0.0"
-      }
-    },
-    "vue-router": {
-      "version": "0.7.13",
-      "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-0.7.13.tgz",
-      "integrity": "sha1-4fDwQqwlYVBLJ/Rvbc0XuDKxyNE="
-    },
-    "vue-style-loader": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/vue-style-loader/-/vue-style-loader-1.0.0.tgz",
-      "integrity": "sha1-q+t70PRjEwg3QSRNMHnU8URJ4Ek=",
-      "dev": true,
-      "requires": {
-        "loader-utils": "^0.2.7"
-      }
-    },
-    "vue-template-validator": {
-      "version": "1.1.5",
-      "resolved": "https://registry.npmjs.org/vue-template-validator/-/vue-template-validator-1.1.5.tgz",
-      "integrity": "sha1-ItHud9BkfBqxT/frAYZZQtmzxFg=",
-      "dev": true,
-      "requires": {
-        "chalk": "^1.1.1"
-      }
-    },
-    "watchpack": {
-      "version": "0.2.9",
-      "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-0.2.9.tgz",
-      "integrity": "sha1-Yuqkq15bo1/fwBgnVibjwPXj+ws=",
-      "dev": true,
-      "requires": {
-        "async": "^0.9.0",
-        "chokidar": "^1.0.0",
-        "graceful-fs": "^4.1.2"
-      },
-      "dependencies": {
-        "async": {
-          "version": "0.9.2",
-          "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz",
-          "integrity": "sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0=",
-          "dev": true
-        }
-      }
-    },
-    "webpack": {
-      "version": "1.15.0",
-      "resolved": "https://registry.npmjs.org/webpack/-/webpack-1.15.0.tgz",
-      "integrity": "sha1-T/MfU9sDM55VFkqdRo7gMklo/pg=",
-      "dev": true,
-      "requires": {
-        "acorn": "^3.0.0",
-        "async": "^1.3.0",
-        "clone": "^1.0.2",
-        "enhanced-resolve": "~0.9.0",
-        "interpret": "^0.6.4",
-        "loader-utils": "^0.2.11",
-        "memory-fs": "~0.3.0",
-        "mkdirp": "~0.5.0",
-        "node-libs-browser": "^0.7.0",
-        "optimist": "~0.6.0",
-        "supports-color": "^3.1.0",
-        "tapable": "~0.1.8",
-        "uglify-js": "~2.7.3",
-        "watchpack": "^0.2.1",
-        "webpack-core": "~0.6.9"
-      },
-      "dependencies": {
-        "acorn": {
-          "version": "3.3.0",
-          "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz",
-          "integrity": "sha1-ReN/s56No/JbruP/U2niu18iAXo=",
-          "dev": true
-        },
-        "async": {
-          "version": "1.5.2",
-          "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz",
-          "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=",
-          "dev": true
-        },
-        "camelcase": {
-          "version": "1.2.1",
-          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz",
-          "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=",
-          "dev": true
-        },
-        "cliui": {
-          "version": "2.1.0",
-          "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz",
-          "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=",
-          "dev": true,
-          "requires": {
-            "center-align": "^0.1.1",
-            "right-align": "^0.1.1",
-            "wordwrap": "0.0.2"
-          }
-        },
-        "interpret": {
-          "version": "0.6.6",
-          "resolved": "https://registry.npmjs.org/interpret/-/interpret-0.6.6.tgz",
-          "integrity": "sha1-/s16GOfOXKar+5U+H4YhOknxYls=",
-          "dev": true
-        },
-        "source-map": {
-          "version": "0.5.7",
-          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
-          "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
-          "dev": true
-        },
-        "supports-color": {
-          "version": "3.2.3",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
-          "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
-          "dev": true,
-          "requires": {
-            "has-flag": "^1.0.0"
-          }
-        },
-        "uglify-js": {
-          "version": "2.7.5",
-          "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.7.5.tgz",
-          "integrity": "sha1-RhLAx7qu4rp8SH3kkErhIgefLKg=",
-          "dev": true,
-          "requires": {
-            "async": "~0.2.6",
-            "source-map": "~0.5.1",
-            "uglify-to-browserify": "~1.0.0",
-            "yargs": "~3.10.0"
-          },
-          "dependencies": {
-            "async": {
-              "version": "0.2.10",
-              "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz",
-              "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E=",
-              "dev": true
-            }
-          }
-        },
-        "wordwrap": {
-          "version": "0.0.2",
-          "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz",
-          "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=",
-          "dev": true
-        },
-        "yargs": {
-          "version": "3.10.0",
-          "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz",
-          "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=",
-          "dev": true,
-          "requires": {
-            "camelcase": "^1.0.2",
-            "cliui": "^2.1.0",
-            "decamelize": "^1.0.0",
-            "window-size": "0.1.0"
-          }
-        }
-      }
-    },
-    "webpack-core": {
-      "version": "0.6.9",
-      "resolved": "https://registry.npmjs.org/webpack-core/-/webpack-core-0.6.9.tgz",
-      "integrity": "sha1-/FcViMhVjad76e+23r3Fo7FyvcI=",
-      "dev": true,
-      "requires": {
-        "source-list-map": "~0.1.7",
-        "source-map": "~0.4.1"
-      }
-    },
-    "webpack-dev-middleware": {
-      "version": "1.12.2",
-      "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-1.12.2.tgz",
-      "integrity": "sha512-FCrqPy1yy/sN6U/SaEZcHKRXGlqU0DUaEBL45jkUYoB8foVb6wCnbIJ1HKIx+qUFTW+3JpVcCJCxZ8VATL4e+A==",
-      "dev": true,
-      "requires": {
-        "memory-fs": "~0.4.1",
-        "mime": "^1.5.0",
-        "path-is-absolute": "^1.0.0",
-        "range-parser": "^1.0.3",
-        "time-stamp": "^2.0.0"
-      },
-      "dependencies": {
-        "memory-fs": {
-          "version": "0.4.1",
-          "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz",
-          "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=",
-          "dev": true,
-          "requires": {
-            "errno": "^0.1.3",
-            "readable-stream": "^2.0.1"
-          }
-        }
-      }
-    },
-    "webpack-dev-server": {
-      "version": "1.16.5",
-      "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-1.16.5.tgz",
-      "integrity": "sha1-DL1fLSrI1OWTqs1clwLnu9XlmJI=",
-      "dev": true,
-      "requires": {
-        "compression": "^1.5.2",
-        "connect-history-api-fallback": "^1.3.0",
-        "express": "^4.13.3",
-        "http-proxy-middleware": "~0.17.1",
-        "open": "0.0.5",
-        "optimist": "~0.6.1",
-        "serve-index": "^1.7.2",
-        "sockjs": "^0.3.15",
-        "sockjs-client": "^1.0.3",
-        "stream-cache": "~0.0.1",
-        "strip-ansi": "^3.0.0",
-        "supports-color": "^3.1.1",
-        "webpack-dev-middleware": "^1.10.2"
-      },
-      "dependencies": {
-        "supports-color": {
-          "version": "3.2.3",
-          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
-          "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
-          "dev": true,
-          "requires": {
-            "has-flag": "^1.0.0"
-          }
-        }
-      }
-    },
-    "webpack-md5-hash": {
-      "version": "0.0.5",
-      "resolved": "https://registry.npmjs.org/webpack-md5-hash/-/webpack-md5-hash-0.0.5.tgz",
-      "integrity": "sha1-2fGJnq1mRFndi2sMkmrHHPvXvHo=",
-      "dev": true,
-      "requires": {
-        "md5": "^2.0.0"
-      }
-    },
-    "websocket-driver": {
-      "version": "0.7.3",
-      "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.3.tgz",
-      "integrity": "sha512-bpxWlvbbB459Mlipc5GBzzZwhoZgGEZLuqPaR0INBGnPAY1vdBX6hPnoFXiw+3yWxDuHyQjO2oXTMyS8A5haFg==",
-      "dev": true,
-      "requires": {
-        "http-parser-js": ">=0.4.0 <0.4.11",
-        "safe-buffer": ">=5.1.0",
-        "websocket-extensions": ">=0.1.1"
-      }
-    },
-    "websocket-extensions": {
-      "version": "0.1.3",
-      "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.3.tgz",
-      "integrity": "sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg==",
-      "dev": true
-    },
-    "whatwg-fetch": {
-      "version": "0.11.1",
-      "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-0.11.1.tgz",
-      "integrity": "sha1-bT3tJF/dl81yjg4lh7VLczlJ5mM=",
-      "dev": true
-    },
-    "whet.extend": {
-      "version": "0.9.9",
-      "resolved": "https://registry.npmjs.org/whet.extend/-/whet.extend-0.9.9.tgz",
-      "integrity": "sha1-+HfVv2SMl+WqVC+twW1qJZucEaE=",
-      "dev": true
-    },
-    "which": {
-      "version": "1.3.1",
-      "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
-      "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
-      "requires": {
-        "isexe": "^2.0.0"
-      }
-    },
-    "which-module": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz",
-      "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8="
-    },
-    "wide-align": {
-      "version": "1.1.3",
-      "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
-      "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
-      "requires": {
-        "string-width": "^1.0.2 || 2"
-      }
-    },
-    "window-size": {
-      "version": "0.1.0",
-      "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz",
-      "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=",
-      "dev": true
-    },
-    "wordwrap": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
-      "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=",
-      "dev": true
-    },
-    "wrap-ansi": {
-      "version": "2.1.0",
-      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
-      "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
-      "requires": {
-        "string-width": "^1.0.1",
-        "strip-ansi": "^3.0.1"
-      }
-    },
-    "wrappy": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
-      "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
-    },
-    "write": {
-      "version": "0.2.1",
-      "resolved": "https://registry.npmjs.org/write/-/write-0.2.1.tgz",
-      "integrity": "sha1-X8A4KOJkzqP+kUVUdvejxWbLB1c=",
-      "dev": true,
-      "requires": {
-        "mkdirp": "^0.5.1"
-      }
-    },
-    "xml-char-classes": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/xml-char-classes/-/xml-char-classes-1.0.0.tgz",
-      "integrity": "sha1-ZGV4SKIP/F31g6Qq2KJ3tFErvE0=",
-      "dev": true
-    },
-    "xtend": {
-      "version": "4.0.2",
-      "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
-      "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
-      "dev": true
-    },
-    "y18n": {
-      "version": "3.2.1",
-      "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz",
-      "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE="
-    },
-    "yallist": {
-      "version": "2.1.2",
-      "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
-      "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI="
-    },
-    "yargs": {
-      "version": "7.1.0",
-      "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.0.tgz",
-      "integrity": "sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg=",
-      "requires": {
-        "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": "^5.0.0"
-      },
-      "dependencies": {
-        "camelcase": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz",
-          "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo="
-        }
-      }
-    },
-    "yargs-parser": {
-      "version": "5.0.0",
-      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0.tgz",
-      "integrity": "sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo=",
-      "requires": {
-        "camelcase": "^3.0.0"
-      },
-      "dependencies": {
-        "camelcase": {
-          "version": "3.0.0",
-          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz",
-          "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo="
-        }
-      }
-    }
-  }
-}

+ 29 - 25
frontend/package.json

@@ -6,37 +6,41 @@
   "author": "Musare Team",
   "repository": "https://github.com/Musare/MusareNode",
   "scripts": {
-    "development": "webpack",
+    "development": "webpack --mode development",
     "development-watch": "webpack --watch --watch-poll",
-    "production": "webpack -p"
+    "production": "webpack --mode production"
   },
   "devDependencies": {
-    "babel-core": "^6.14.0",
-    "babel-loader": "^6.2.5",
-    "babel-plugin-transform-runtime": "^6.15.0",
-    "babel-preset-es2015": "^6.14.0",
-    "babel-runtime": "^6.11.6",
-    "css-loader": "^0.25.0",
-    "eslint": "^3.4.0",
-    "eslint-loader": "^1.5.0",
-    "eslint-plugin-html": "^1.5.2",
-    "html-webpack-plugin": "^2.28.0",
-    "sass-loader": "^4.0.2",
-    "style-loader": "^0.13.1",
-    "vue-hot-reload-api": "^1.3.3",
-    "vue-html-loader": "^1.2.3",
-    "vue-loader": "^8.5.2",
-    "vue-style-loader": "^1.0.0",
-    "webpack": "^1.14.0",
-    "webpack-dev-server": "^1.15.1",
-    "webpack-md5-hash": "0.0.5",
-    "whatwg-fetch": "^0.11.1"
+    "@babel/core": "^7.5.4",
+    "@babel/plugin-proposal-object-rest-spread": "^7.5.4",
+    "@babel/plugin-syntax-dynamic-import": "^7.2.0",
+    "@babel/plugin-transform-runtime": "^7.5.0",
+    "@babel/preset-env": "^7.5.4",
+    "babel-loader": "^8.0.6",
+    "css-loader": "^3.0.0",
+    "eslint": "^6.0.1",
+    "eslint-loader": "^2.2.1",
+    "eslint-plugin-html": "^6.0.0",
+    "fetch": "^1.1.0",
+    "html-webpack-plugin": "^3.2.0",
+    "node-sass": "^4.12.0",
+    "sass-loader": "^7.1.0",
+    "vue-hot-reload-api": "^2.3.3",
+    "vue-html-loader": "^1.2.4",
+    "vue-loader": "^15.7.0",
+    "vue-style-loader": "^4.1.2",
+    "vue-template-compiler": "^2.6.10",
+    "webpack": "^4.35.3",
+    "webpack-cli": "^3.3.5",
+    "webpack-dev-server": "^3.7.2",
+    "webpack-md5-hash": "0.0.6"
   },
   "dependencies": {
+    "@babel/runtime": "^7.5.4",
     "chart.js": "^2.5.0",
-    "node-sass": "^4.9.2",
-    "vue": "^1.0.26",
+    "vue": "^2.6.10",
     "vue-roaster": "^1.1.1",
-    "vue-router": "^0.7.13"
+    "vue-router": "^3.0.7",
+    "vuex": "^3.1.1"
   }
 }

+ 18 - 0
frontend/store/index.js

@@ -0,0 +1,18 @@
+import Vue from "vue";
+import Vuex from "vuex";
+Vue.use(Vuex);
+
+import user from "./modules/user";
+import modals from "./modules/modals";
+import station from "./modules/station";
+import admin from "./modules/admin";
+
+export default new Vuex.Store({
+	modules: {
+		user,
+		modals,
+		station,
+		admin
+	},
+	strict: false
+});

+ 100 - 0
frontend/store/modules/admin.js

@@ -0,0 +1,100 @@
+const state = {};
+const getters = {};
+const actions = {};
+const mutations = {};
+
+const modules = {
+	songs: {
+		namespaced: true,
+		state: {
+			video: {
+				player: null,
+				paused: true,
+				playerReady: false,
+				autoPlayed: false
+			},
+			editing: {}
+		},
+		getters: {},
+		actions: {
+			editSong: ({ commit }, song) => commit("editSong", song),
+			stopVideo: ({ commit }) => commit("stopVideo"),
+			loadVideoById: ({ commit }, id, skipDuration) =>
+				commit("loadVideoById", id, skipDuration),
+			pauseVideo: ({ commit }, status) => commit("pauseVideo", status)
+		},
+		mutations: {
+			editSong(state, song) {
+				state.editing = { ...song };
+				console.log("editing", state.editing);
+			},
+			stopVideo(state) {
+				state.video.player.stopVideo();
+			},
+			loadVideoById(state, id, skipDuration) {
+				state.video.player.loadVideoById(id, skipDuration);
+			},
+			pauseVideo(state, status) {
+				if (status) state.video.player.pauseVideo();
+				else state.video.player.playVideo();
+				state.video.paused = status;
+			}
+		}
+	},
+	stations: {
+		namespaced: true,
+		state: {
+			station: {},
+			editing: {}
+		},
+		getters: {},
+		actions: {
+			editStation: ({ commit }, station) => commit("editStation", station)
+		},
+		mutations: {
+			editStation(state, station) {
+				state.editing = state.station = station;
+			}
+		}
+	},
+	punishments: {
+		namespaced: true,
+		state: {
+			punishment: {}
+		},
+		getters: {},
+		actions: {
+			viewPunishment: ({ commit }, punishment) =>
+				commit("viewPunishment", punishment)
+		},
+		mutations: {
+			viewPunishment(state, punishment) {
+				state.punishment = punishment;
+			}
+		}
+	},
+	users: {
+		namespaced: true,
+		state: {
+			editing: {}
+		},
+		getters: {},
+		actions: {
+			editUser: ({ commit }, user) => commit("editUser", user)
+		},
+		mutations: {
+			editUser(state, user) {
+				state.editing = user;
+			}
+		}
+	}
+};
+
+export default {
+	namespaced: true,
+	state,
+	getters,
+	actions,
+	mutations,
+	modules
+};

+ 59 - 0
frontend/store/modules/modals.js

@@ -0,0 +1,59 @@
+const state = {
+	modals: {
+		header: {
+			login: false,
+			register: false
+		},
+		home: {
+			createCommunityStation: false
+		},
+		station: {
+			addSongToQueue: false,
+			editPlaylist: false,
+			createPlaylist: false,
+			editPlaylist: false,
+			addSongToPlaylist: false,
+			editStation: false,
+			report: false
+		},
+		admin: {
+			editUser: false,
+			editSong: false,
+			viewPunishment: false
+		}
+	},
+	currentlyActive: {}
+};
+
+const getters = {};
+
+const actions = {
+	toggleModal: ({ commit }, data) => {
+		commit("toggleModal", data);
+	},
+	closeCurrentModal: ({ commit }) => {
+		commit("closeCurrentModal");
+	}
+};
+
+const mutations = {
+	toggleModal(state, data) {
+		const { sector, modal } = data;
+		state.modals[sector][modal] = !state.modals[sector][modal];
+		if (state.modals[sector][modal]) state.currentlyActive = { sector, modal };
+		else state.currentlyActive = {};
+	},
+	closeCurrentModal(state) {
+		const { sector, modal } = state.currentlyActive;
+		state.modals[sector][modal] = false;
+		state.currentlyActive = {};
+	}
+};
+
+export default {
+	namespaced: true,
+	state,
+	getters,
+	actions,
+	mutations
+};

+ 32 - 0
frontend/store/modules/station.js

@@ -0,0 +1,32 @@
+const state = {
+	station: {},
+	editing: {}
+};
+
+const getters = {};
+
+const actions = {
+	joinStation: ({ commit }, station) => {
+		commit("joinStation", station);
+	},
+	editStation: ({ commit }, station) => {
+		commit("editStation", station);
+	}
+};
+
+const mutations = {
+	joinStation(state, station) {
+		state.station = { ...station };
+	},
+	editStation(state, station) {
+		state.editing = { ...station };
+	}
+};
+
+export default {
+	namespaced: true,
+	state,
+	getters,
+	actions,
+	mutations
+};

+ 31 - 0
frontend/store/modules/user.js

@@ -0,0 +1,31 @@
+const state = {};
+const getters = {};
+const actions = {};
+const mutations = {};
+
+const modules = {
+	playlists: {
+		namespaced: true,
+		state: {
+			editing: ""
+		},
+		getters: {},
+		actions: {
+			editPlaylist: ({ commit }, id) => commit("editPlaylist", id)
+		},
+		mutations: {
+			editPlaylist(state, id) {
+				state.editing = id;
+			}
+		}
+	}
+};
+
+export default {
+	namespaced: true,
+	state,
+	getters,
+	actions,
+	mutations,
+	modules
+};

+ 12 - 6
frontend/webpack.config.js

@@ -1,8 +1,10 @@
 const webpack = require('webpack');
+const VueLoaderPlugin = require('vue-loader/lib/plugin');
 const WebpackMd5Hash = require('webpack-md5-hash');
 const HtmlWebpackPlugin = require("html-webpack-plugin");
 
 module.exports = {
+	mode: 'none',
 	devtool: 'eval-source-map',
 	entry: './main.js',
 	output: {
@@ -11,6 +13,7 @@ module.exports = {
 		filename: '[name].[chunkhash].js'
 	},
 	plugins: [
+		new VueLoaderPlugin(),
 		new WebpackMd5Hash(),
 		new HtmlWebpackPlugin({
 			hash: true,
@@ -20,9 +23,8 @@ module.exports = {
 		})
 	],
 	module: {
-		loaders: [
+		rules: [
 			{
-				enforce: 'pre',
 				test: /\.vue$/,
 				loader: 'vue-loader',
 				exclude: /node_modules/
@@ -35,13 +37,17 @@ module.exports = {
 			{
 				test: /\.scss$/,
 				exclude: /node_modules/,
-				loader: 'css-loader!sass-loader'
+				use: [
+					'vue-style-loader',
+					'css-loader',
+					'sass-loader'
+				]
 			}
 		]
 	},
-	vue: {
-		loaders: {
-			scss: 'style-loader!css-loader!sass-loader'
+	resolve: {
+		alias: {
+			vue: 'vue/dist/vue.js'
 		}
 	}
 };

+ 7078 - 0
frontend/yarn.lock

@@ -0,0 +1,7078 @@
+# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
+# yarn lockfile v1
+
+
+"@babel/code-frame@^7.0.0":
+  version "7.0.0"
+  resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.0.0.tgz#06e2ab19bdb535385559aabb5ba59729482800f8"
+  integrity sha512-OfC2uemaknXr87bdLUkWog7nYuliM9Ij5HUcajsVcMCpQrcLmtxRbVFTIqmcSkSeYRBFBRxs2FiUqFJDLdiebA==
+  dependencies:
+    "@babel/highlight" "^7.0.0"
+
+"@babel/core@^7.5.4":
+  version "7.5.4"
+  resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.5.4.tgz#4c32df7ad5a58e9ea27ad025c11276324e0b4ddd"
+  integrity sha512-+DaeBEpYq6b2+ZmHx3tHspC+ZRflrvLqwfv8E3hNr5LVQoyBnL8RPKSBCg+rK2W2My9PWlujBiqd0ZPsR9Q6zQ==
+  dependencies:
+    "@babel/code-frame" "^7.0.0"
+    "@babel/generator" "^7.5.0"
+    "@babel/helpers" "^7.5.4"
+    "@babel/parser" "^7.5.0"
+    "@babel/template" "^7.4.4"
+    "@babel/traverse" "^7.5.0"
+    "@babel/types" "^7.5.0"
+    convert-source-map "^1.1.0"
+    debug "^4.1.0"
+    json5 "^2.1.0"
+    lodash "^4.17.11"
+    resolve "^1.3.2"
+    semver "^5.4.1"
+    source-map "^0.5.0"
+
+"@babel/generator@^7.5.0":
+  version "7.5.0"
+  resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.5.0.tgz#f20e4b7a91750ee8b63656073d843d2a736dca4a"
+  integrity sha512-1TTVrt7J9rcG5PMjvO7VEG3FrEoEJNHxumRq66GemPmzboLWtIjjcJgk8rokuAS7IiRSpgVSu5Vb9lc99iJkOA==
+  dependencies:
+    "@babel/types" "^7.5.0"
+    jsesc "^2.5.1"
+    lodash "^4.17.11"
+    source-map "^0.5.0"
+    trim-right "^1.0.1"
+
+"@babel/helper-annotate-as-pure@^7.0.0":
+  version "7.0.0"
+  resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.0.0.tgz#323d39dd0b50e10c7c06ca7d7638e6864d8c5c32"
+  integrity sha512-3UYcJUj9kvSLbLbUIfQTqzcy5VX7GRZ/CCDrnOaZorFFM01aXp1+GJwuFGV4NDDoAS+mOUyHcO6UD/RfqOks3Q==
+  dependencies:
+    "@babel/types" "^7.0.0"
+
+"@babel/helper-builder-binary-assignment-operator-visitor@^7.1.0":
+  version "7.1.0"
+  resolved "https://registry.yarnpkg.com/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.1.0.tgz#6b69628dfe4087798e0c4ed98e3d4a6b2fbd2f5f"
+  integrity sha512-qNSR4jrmJ8M1VMM9tibvyRAHXQs2PmaksQF7c1CGJNipfe3D8p+wgNwgso/P2A2r2mdgBWAXljNWR0QRZAMW8w==
+  dependencies:
+    "@babel/helper-explode-assignable-expression" "^7.1.0"
+    "@babel/types" "^7.0.0"
+
+"@babel/helper-call-delegate@^7.4.4":
+  version "7.4.4"
+  resolved "https://registry.yarnpkg.com/@babel/helper-call-delegate/-/helper-call-delegate-7.4.4.tgz#87c1f8ca19ad552a736a7a27b1c1fcf8b1ff1f43"
+  integrity sha512-l79boDFJ8S1c5hvQvG+rc+wHw6IuH7YldmRKsYtpbawsxURu/paVy57FZMomGK22/JckepaikOkY0MoAmdyOlQ==
+  dependencies:
+    "@babel/helper-hoist-variables" "^7.4.4"
+    "@babel/traverse" "^7.4.4"
+    "@babel/types" "^7.4.4"
+
+"@babel/helper-define-map@^7.4.4":
+  version "7.4.4"
+  resolved "https://registry.yarnpkg.com/@babel/helper-define-map/-/helper-define-map-7.4.4.tgz#6969d1f570b46bdc900d1eba8e5d59c48ba2c12a"
+  integrity sha512-IX3Ln8gLhZpSuqHJSnTNBWGDE9kdkTEWl21A/K7PQ00tseBwbqCHTvNLHSBd9M0R5rER4h5Rsvj9vw0R5SieBg==
+  dependencies:
+    "@babel/helper-function-name" "^7.1.0"
+    "@babel/types" "^7.4.4"
+    lodash "^4.17.11"
+
+"@babel/helper-explode-assignable-expression@^7.1.0":
+  version "7.1.0"
+  resolved "https://registry.yarnpkg.com/@babel/helper-explode-assignable-expression/-/helper-explode-assignable-expression-7.1.0.tgz#537fa13f6f1674df745b0c00ec8fe4e99681c8f6"
+  integrity sha512-NRQpfHrJ1msCHtKjbzs9YcMmJZOg6mQMmGRB+hbamEdG5PNpaSm95275VD92DvJKuyl0s2sFiDmMZ+EnnvufqA==
+  dependencies:
+    "@babel/traverse" "^7.1.0"
+    "@babel/types" "^7.0.0"
+
+"@babel/helper-function-name@^7.1.0":
+  version "7.1.0"
+  resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz#a0ceb01685f73355d4360c1247f582bfafc8ff53"
+  integrity sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==
+  dependencies:
+    "@babel/helper-get-function-arity" "^7.0.0"
+    "@babel/template" "^7.1.0"
+    "@babel/types" "^7.0.0"
+
+"@babel/helper-get-function-arity@^7.0.0":
+  version "7.0.0"
+  resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz#83572d4320e2a4657263734113c42868b64e49c3"
+  integrity sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==
+  dependencies:
+    "@babel/types" "^7.0.0"
+
+"@babel/helper-hoist-variables@^7.4.4":
+  version "7.4.4"
+  resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.4.4.tgz#0298b5f25c8c09c53102d52ac4a98f773eb2850a"
+  integrity sha512-VYk2/H/BnYbZDDg39hr3t2kKyifAm1W6zHRfhx8jGjIHpQEBv9dry7oQ2f3+J703TLu69nYdxsovl0XYfcnK4w==
+  dependencies:
+    "@babel/types" "^7.4.4"
+
+"@babel/helper-member-expression-to-functions@^7.0.0":
+  version "7.0.0"
+  resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.0.0.tgz#8cd14b0a0df7ff00f009e7d7a436945f47c7a16f"
+  integrity sha512-avo+lm/QmZlv27Zsi0xEor2fKcqWG56D5ae9dzklpIaY7cQMK5N8VSpaNVPPagiqmy7LrEjK1IWdGMOqPu5csg==
+  dependencies:
+    "@babel/types" "^7.0.0"
+
+"@babel/helper-module-imports@^7.0.0":
+  version "7.0.0"
+  resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.0.0.tgz#96081b7111e486da4d2cd971ad1a4fe216cc2e3d"
+  integrity sha512-aP/hlLq01DWNEiDg4Jn23i+CXxW/owM4WpDLFUbpjxe4NS3BhLVZQ5i7E0ZrxuQ/vwekIeciyamgB1UIYxxM6A==
+  dependencies:
+    "@babel/types" "^7.0.0"
+
+"@babel/helper-module-transforms@^7.1.0", "@babel/helper-module-transforms@^7.4.4":
+  version "7.4.4"
+  resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.4.4.tgz#96115ea42a2f139e619e98ed46df6019b94414b8"
+  integrity sha512-3Z1yp8TVQf+B4ynN7WoHPKS8EkdTbgAEy0nU0rs/1Kw4pDgmvYH3rz3aI11KgxKCba2cn7N+tqzV1mY2HMN96w==
+  dependencies:
+    "@babel/helper-module-imports" "^7.0.0"
+    "@babel/helper-simple-access" "^7.1.0"
+    "@babel/helper-split-export-declaration" "^7.4.4"
+    "@babel/template" "^7.4.4"
+    "@babel/types" "^7.4.4"
+    lodash "^4.17.11"
+
+"@babel/helper-optimise-call-expression@^7.0.0":
+  version "7.0.0"
+  resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.0.0.tgz#a2920c5702b073c15de51106200aa8cad20497d5"
+  integrity sha512-u8nd9NQePYNQV8iPWu/pLLYBqZBa4ZaY1YWRFMuxrid94wKI1QNt67NEZ7GAe5Kc/0LLScbim05xZFWkAdrj9g==
+  dependencies:
+    "@babel/types" "^7.0.0"
+
+"@babel/helper-plugin-utils@^7.0.0":
+  version "7.0.0"
+  resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz#bbb3fbee98661c569034237cc03967ba99b4f250"
+  integrity sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA==
+
+"@babel/helper-regex@^7.0.0", "@babel/helper-regex@^7.4.4":
+  version "7.4.4"
+  resolved "https://registry.yarnpkg.com/@babel/helper-regex/-/helper-regex-7.4.4.tgz#a47e02bc91fb259d2e6727c2a30013e3ac13c4a2"
+  integrity sha512-Y5nuB/kESmR3tKjU8Nkn1wMGEx1tjJX076HBMeL3XLQCu6vA/YRzuTW0bbb+qRnXvQGn+d6Rx953yffl8vEy7Q==
+  dependencies:
+    lodash "^4.17.11"
+
+"@babel/helper-remap-async-to-generator@^7.1.0":
+  version "7.1.0"
+  resolved "https://registry.yarnpkg.com/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.1.0.tgz#361d80821b6f38da75bd3f0785ece20a88c5fe7f"
+  integrity sha512-3fOK0L+Fdlg8S5al8u/hWE6vhufGSn0bN09xm2LXMy//REAF8kDCrYoOBKYmA8m5Nom+sV9LyLCwrFynA8/slg==
+  dependencies:
+    "@babel/helper-annotate-as-pure" "^7.0.0"
+    "@babel/helper-wrap-function" "^7.1.0"
+    "@babel/template" "^7.1.0"
+    "@babel/traverse" "^7.1.0"
+    "@babel/types" "^7.0.0"
+
+"@babel/helper-replace-supers@^7.1.0", "@babel/helper-replace-supers@^7.4.4":
+  version "7.4.4"
+  resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.4.4.tgz#aee41783ebe4f2d3ab3ae775e1cc6f1a90cefa27"
+  integrity sha512-04xGEnd+s01nY1l15EuMS1rfKktNF+1CkKmHoErDppjAAZL+IUBZpzT748x262HF7fibaQPhbvWUl5HeSt1EXg==
+  dependencies:
+    "@babel/helper-member-expression-to-functions" "^7.0.0"
+    "@babel/helper-optimise-call-expression" "^7.0.0"
+    "@babel/traverse" "^7.4.4"
+    "@babel/types" "^7.4.4"
+
+"@babel/helper-simple-access@^7.1.0":
+  version "7.1.0"
+  resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.1.0.tgz#65eeb954c8c245beaa4e859da6188f39d71e585c"
+  integrity sha512-Vk+78hNjRbsiu49zAPALxTb+JUQCz1aolpd8osOF16BGnLtseD21nbHgLPGUwrXEurZgiCOUmvs3ExTu4F5x6w==
+  dependencies:
+    "@babel/template" "^7.1.0"
+    "@babel/types" "^7.0.0"
+
+"@babel/helper-split-export-declaration@^7.4.4":
+  version "7.4.4"
+  resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz#ff94894a340be78f53f06af038b205c49d993677"
+  integrity sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q==
+  dependencies:
+    "@babel/types" "^7.4.4"
+
+"@babel/helper-wrap-function@^7.1.0":
+  version "7.2.0"
+  resolved "https://registry.yarnpkg.com/@babel/helper-wrap-function/-/helper-wrap-function-7.2.0.tgz#c4e0012445769e2815b55296ead43a958549f6fa"
+  integrity sha512-o9fP1BZLLSrYlxYEYyl2aS+Flun5gtjTIG8iln+XuEzQTs0PLagAGSXUcqruJwD5fM48jzIEggCKpIfWTcR7pQ==
+  dependencies:
+    "@babel/helper-function-name" "^7.1.0"
+    "@babel/template" "^7.1.0"
+    "@babel/traverse" "^7.1.0"
+    "@babel/types" "^7.2.0"
+
+"@babel/helpers@^7.5.4":
+  version "7.5.4"
+  resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.5.4.tgz#2f00608aa10d460bde0ccf665d6dcf8477357cf0"
+  integrity sha512-6LJ6xwUEJP51w0sIgKyfvFMJvIb9mWAfohJp0+m6eHJigkFdcH8duZ1sfhn0ltJRzwUIT/yqqhdSfRpCpL7oow==
+  dependencies:
+    "@babel/template" "^7.4.4"
+    "@babel/traverse" "^7.5.0"
+    "@babel/types" "^7.5.0"
+
+"@babel/highlight@^7.0.0":
+  version "7.5.0"
+  resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.5.0.tgz#56d11312bd9248fa619591d02472be6e8cb32540"
+  integrity sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==
+  dependencies:
+    chalk "^2.0.0"
+    esutils "^2.0.2"
+    js-tokens "^4.0.0"
+
+"@babel/parser@^7.4.4", "@babel/parser@^7.5.0":
+  version "7.5.0"
+  resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.5.0.tgz#3e0713dff89ad6ae37faec3b29dcfc5c979770b7"
+  integrity sha512-I5nW8AhGpOXGCCNYGc+p7ExQIBxRFnS2fd/d862bNOKvmoEPjYPcfIjsfdy0ujagYOIYPczKgD9l3FsgTkAzKA==
+
+"@babel/plugin-proposal-async-generator-functions@^7.2.0":
+  version "7.2.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-async-generator-functions/-/plugin-proposal-async-generator-functions-7.2.0.tgz#b289b306669dce4ad20b0252889a15768c9d417e"
+  integrity sha512-+Dfo/SCQqrwx48ptLVGLdE39YtWRuKc/Y9I5Fy0P1DDBB9lsAHpjcEJQt+4IifuSOSTLBKJObJqMvaO1pIE8LQ==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.0.0"
+    "@babel/helper-remap-async-to-generator" "^7.1.0"
+    "@babel/plugin-syntax-async-generators" "^7.2.0"
+
+"@babel/plugin-proposal-dynamic-import@^7.5.0":
+  version "7.5.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-dynamic-import/-/plugin-proposal-dynamic-import-7.5.0.tgz#e532202db4838723691b10a67b8ce509e397c506"
+  integrity sha512-x/iMjggsKTFHYC6g11PL7Qy58IK8H5zqfm9e6hu4z1iH2IRyAp9u9dL80zA6R76yFovETFLKz2VJIC2iIPBuFw==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.0.0"
+    "@babel/plugin-syntax-dynamic-import" "^7.2.0"
+
+"@babel/plugin-proposal-json-strings@^7.2.0":
+  version "7.2.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-json-strings/-/plugin-proposal-json-strings-7.2.0.tgz#568ecc446c6148ae6b267f02551130891e29f317"
+  integrity sha512-MAFV1CA/YVmYwZG0fBQyXhmj0BHCB5egZHCKWIFVv/XCxAeVGIHfos3SwDck4LvCllENIAg7xMKOG5kH0dzyUg==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.0.0"
+    "@babel/plugin-syntax-json-strings" "^7.2.0"
+
+"@babel/plugin-proposal-object-rest-spread@^7.5.4":
+  version "7.5.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-object-rest-spread/-/plugin-proposal-object-rest-spread-7.5.4.tgz#250de35d867ce8260a31b1fdac6c4fc1baa99331"
+  integrity sha512-KCx0z3y7y8ipZUMAEEJOyNi11lMb/FOPUjjB113tfowgw0c16EGYos7worCKBcUAh2oG+OBnoUhsnTSoLpV9uA==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.0.0"
+    "@babel/plugin-syntax-object-rest-spread" "^7.2.0"
+
+"@babel/plugin-proposal-optional-catch-binding@^7.2.0":
+  version "7.2.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-optional-catch-binding/-/plugin-proposal-optional-catch-binding-7.2.0.tgz#135d81edb68a081e55e56ec48541ece8065c38f5"
+  integrity sha512-mgYj3jCcxug6KUcX4OBoOJz3CMrwRfQELPQ5560F70YQUBZB7uac9fqaWamKR1iWUzGiK2t0ygzjTScZnVz75g==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.0.0"
+    "@babel/plugin-syntax-optional-catch-binding" "^7.2.0"
+
+"@babel/plugin-proposal-unicode-property-regex@^7.4.4":
+  version "7.4.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-unicode-property-regex/-/plugin-proposal-unicode-property-regex-7.4.4.tgz#501ffd9826c0b91da22690720722ac7cb1ca9c78"
+  integrity sha512-j1NwnOqMG9mFUOH58JTFsA/+ZYzQLUZ/drqWUqxCYLGeu2JFZL8YrNC9hBxKmWtAuOCHPcRpgv7fhap09Fb4kA==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.0.0"
+    "@babel/helper-regex" "^7.4.4"
+    regexpu-core "^4.5.4"
+
+"@babel/plugin-syntax-async-generators@^7.2.0":
+  version "7.2.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.2.0.tgz#69e1f0db34c6f5a0cf7e2b3323bf159a76c8cb7f"
+  integrity sha512-1ZrIRBv2t0GSlcwVoQ6VgSLpLgiN/FVQUzt9znxo7v2Ov4jJrs8RY8tv0wvDmFN3qIdMKWrmMMW6yZ0G19MfGg==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.0.0"
+
+"@babel/plugin-syntax-dynamic-import@^7.2.0":
+  version "7.2.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.2.0.tgz#69c159ffaf4998122161ad8ebc5e6d1f55df8612"
+  integrity sha512-mVxuJ0YroI/h/tbFTPGZR8cv6ai+STMKNBq0f8hFxsxWjl94qqhsb+wXbpNMDPU3cfR1TIsVFzU3nXyZMqyK4w==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.0.0"
+
+"@babel/plugin-syntax-json-strings@^7.2.0":
+  version "7.2.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.2.0.tgz#72bd13f6ffe1d25938129d2a186b11fd62951470"
+  integrity sha512-5UGYnMSLRE1dqqZwug+1LISpA403HzlSfsg6P9VXU6TBjcSHeNlw4DxDx7LgpF+iKZoOG/+uzqoRHTdcUpiZNg==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.0.0"
+
+"@babel/plugin-syntax-object-rest-spread@^7.2.0":
+  version "7.2.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.2.0.tgz#3b7a3e733510c57e820b9142a6579ac8b0dfad2e"
+  integrity sha512-t0JKGgqk2We+9may3t0xDdmneaXmyxq0xieYcKHxIsrJO64n1OiMWNUtc5gQK1PA0NpdCRrtZp4z+IUaKugrSA==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.0.0"
+
+"@babel/plugin-syntax-optional-catch-binding@^7.2.0":
+  version "7.2.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.2.0.tgz#a94013d6eda8908dfe6a477e7f9eda85656ecf5c"
+  integrity sha512-bDe4xKNhb0LI7IvZHiA13kff0KEfaGX/Hv4lMA9+7TEc63hMNvfKo6ZFpXhKuEp+II/q35Gc4NoMeDZyaUbj9w==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.0.0"
+
+"@babel/plugin-transform-arrow-functions@^7.2.0":
+  version "7.2.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.2.0.tgz#9aeafbe4d6ffc6563bf8f8372091628f00779550"
+  integrity sha512-ER77Cax1+8/8jCB9fo4Ud161OZzWN5qawi4GusDuRLcDbDG+bIGYY20zb2dfAFdTRGzrfq2xZPvF0R64EHnimg==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.0.0"
+
+"@babel/plugin-transform-async-to-generator@^7.5.0":
+  version "7.5.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.5.0.tgz#89a3848a0166623b5bc481164b5936ab947e887e"
+  integrity sha512-mqvkzwIGkq0bEF1zLRRiTdjfomZJDV33AH3oQzHVGkI2VzEmXLpKKOBvEVaFZBJdN0XTyH38s9j/Kiqr68dggg==
+  dependencies:
+    "@babel/helper-module-imports" "^7.0.0"
+    "@babel/helper-plugin-utils" "^7.0.0"
+    "@babel/helper-remap-async-to-generator" "^7.1.0"
+
+"@babel/plugin-transform-block-scoped-functions@^7.2.0":
+  version "7.2.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.2.0.tgz#5d3cc11e8d5ddd752aa64c9148d0db6cb79fd190"
+  integrity sha512-ntQPR6q1/NKuphly49+QiQiTN0O63uOwjdD6dhIjSWBI5xlrbUFh720TIpzBhpnrLfv2tNH/BXvLIab1+BAI0w==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.0.0"
+
+"@babel/plugin-transform-block-scoping@^7.4.4":
+  version "7.4.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.4.4.tgz#c13279fabf6b916661531841a23c4b7dae29646d"
+  integrity sha512-jkTUyWZcTrwxu5DD4rWz6rDB5Cjdmgz6z7M7RLXOJyCUkFBawssDGcGh8M/0FTSB87avyJI1HsTwUXp9nKA1PA==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.0.0"
+    lodash "^4.17.11"
+
+"@babel/plugin-transform-classes@^7.4.4":
+  version "7.4.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-classes/-/plugin-transform-classes-7.4.4.tgz#0ce4094cdafd709721076d3b9c38ad31ca715eb6"
+  integrity sha512-/e44eFLImEGIpL9qPxSRat13I5QNRgBLu2hOQJCF7VLy/otSM/sypV1+XaIw5+502RX/+6YaSAPmldk+nhHDPw==
+  dependencies:
+    "@babel/helper-annotate-as-pure" "^7.0.0"
+    "@babel/helper-define-map" "^7.4.4"
+    "@babel/helper-function-name" "^7.1.0"
+    "@babel/helper-optimise-call-expression" "^7.0.0"
+    "@babel/helper-plugin-utils" "^7.0.0"
+    "@babel/helper-replace-supers" "^7.4.4"
+    "@babel/helper-split-export-declaration" "^7.4.4"
+    globals "^11.1.0"
+
+"@babel/plugin-transform-computed-properties@^7.2.0":
+  version "7.2.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.2.0.tgz#83a7df6a658865b1c8f641d510c6f3af220216da"
+  integrity sha512-kP/drqTxY6Xt3NNpKiMomfgkNn4o7+vKxK2DDKcBG9sHj51vHqMBGy8wbDS/J4lMxnqs153/T3+DmCEAkC5cpA==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.0.0"
+
+"@babel/plugin-transform-destructuring@^7.5.0":
+  version "7.5.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.5.0.tgz#f6c09fdfe3f94516ff074fe877db7bc9ef05855a"
+  integrity sha512-YbYgbd3TryYYLGyC7ZR+Tq8H/+bCmwoaxHfJHupom5ECstzbRLTch6gOQbhEY9Z4hiCNHEURgq06ykFv9JZ/QQ==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.0.0"
+
+"@babel/plugin-transform-dotall-regex@^7.4.4":
+  version "7.4.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.4.4.tgz#361a148bc951444312c69446d76ed1ea8e4450c3"
+  integrity sha512-P05YEhRc2h53lZDjRPk/OektxCVevFzZs2Gfjd545Wde3k+yFDbXORgl2e0xpbq8mLcKJ7Idss4fAg0zORN/zg==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.0.0"
+    "@babel/helper-regex" "^7.4.4"
+    regexpu-core "^4.5.4"
+
+"@babel/plugin-transform-duplicate-keys@^7.5.0":
+  version "7.5.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.5.0.tgz#c5dbf5106bf84cdf691222c0974c12b1df931853"
+  integrity sha512-igcziksHizyQPlX9gfSjHkE2wmoCH3evvD2qR5w29/Dk0SMKE/eOI7f1HhBdNhR/zxJDqrgpoDTq5YSLH/XMsQ==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.0.0"
+
+"@babel/plugin-transform-exponentiation-operator@^7.2.0":
+  version "7.2.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.2.0.tgz#a63868289e5b4007f7054d46491af51435766008"
+  integrity sha512-umh4hR6N7mu4Elq9GG8TOu9M0bakvlsREEC+ialrQN6ABS4oDQ69qJv1VtR3uxlKMCQMCvzk7vr17RHKcjx68A==
+  dependencies:
+    "@babel/helper-builder-binary-assignment-operator-visitor" "^7.1.0"
+    "@babel/helper-plugin-utils" "^7.0.0"
+
+"@babel/plugin-transform-for-of@^7.4.4":
+  version "7.4.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.4.4.tgz#0267fc735e24c808ba173866c6c4d1440fc3c556"
+  integrity sha512-9T/5Dlr14Z9TIEXLXkt8T1DU7F24cbhwhMNUziN3hB1AXoZcdzPcTiKGRn/6iOymDqtTKWnr/BtRKN9JwbKtdQ==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.0.0"
+
+"@babel/plugin-transform-function-name@^7.4.4":
+  version "7.4.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.4.4.tgz#e1436116abb0610c2259094848754ac5230922ad"
+  integrity sha512-iU9pv7U+2jC9ANQkKeNF6DrPy4GBa4NWQtl6dHB4Pb3izX2JOEvDTFarlNsBj/63ZEzNNIAMs3Qw4fNCcSOXJA==
+  dependencies:
+    "@babel/helper-function-name" "^7.1.0"
+    "@babel/helper-plugin-utils" "^7.0.0"
+
+"@babel/plugin-transform-literals@^7.2.0":
+  version "7.2.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-literals/-/plugin-transform-literals-7.2.0.tgz#690353e81f9267dad4fd8cfd77eafa86aba53ea1"
+  integrity sha512-2ThDhm4lI4oV7fVQ6pNNK+sx+c/GM5/SaML0w/r4ZB7sAneD/piDJtwdKlNckXeyGK7wlwg2E2w33C/Hh+VFCg==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.0.0"
+
+"@babel/plugin-transform-member-expression-literals@^7.2.0":
+  version "7.2.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.2.0.tgz#fa10aa5c58a2cb6afcf2c9ffa8cb4d8b3d489a2d"
+  integrity sha512-HiU3zKkSU6scTidmnFJ0bMX8hz5ixC93b4MHMiYebmk2lUVNGOboPsqQvx5LzooihijUoLR/v7Nc1rbBtnc7FA==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.0.0"
+
+"@babel/plugin-transform-modules-amd@^7.5.0":
+  version "7.5.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.5.0.tgz#ef00435d46da0a5961aa728a1d2ecff063e4fb91"
+  integrity sha512-n20UsQMKnWrltocZZm24cRURxQnWIvsABPJlw/fvoy9c6AgHZzoelAIzajDHAQrDpuKFFPPcFGd7ChsYuIUMpg==
+  dependencies:
+    "@babel/helper-module-transforms" "^7.1.0"
+    "@babel/helper-plugin-utils" "^7.0.0"
+    babel-plugin-dynamic-import-node "^2.3.0"
+
+"@babel/plugin-transform-modules-commonjs@^7.5.0":
+  version "7.5.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.5.0.tgz#425127e6045231360858eeaa47a71d75eded7a74"
+  integrity sha512-xmHq0B+ytyrWJvQTc5OWAC4ii6Dhr0s22STOoydokG51JjWhyYo5mRPXoi+ZmtHQhZZwuXNN+GG5jy5UZZJxIQ==
+  dependencies:
+    "@babel/helper-module-transforms" "^7.4.4"
+    "@babel/helper-plugin-utils" "^7.0.0"
+    "@babel/helper-simple-access" "^7.1.0"
+    babel-plugin-dynamic-import-node "^2.3.0"
+
+"@babel/plugin-transform-modules-systemjs@^7.5.0":
+  version "7.5.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.5.0.tgz#e75266a13ef94202db2a0620977756f51d52d249"
+  integrity sha512-Q2m56tyoQWmuNGxEtUyeEkm6qJYFqs4c+XyXH5RAuYxObRNz9Zgj/1g2GMnjYp2EUyEy7YTrxliGCXzecl/vJg==
+  dependencies:
+    "@babel/helper-hoist-variables" "^7.4.4"
+    "@babel/helper-plugin-utils" "^7.0.0"
+    babel-plugin-dynamic-import-node "^2.3.0"
+
+"@babel/plugin-transform-modules-umd@^7.2.0":
+  version "7.2.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.2.0.tgz#7678ce75169f0877b8eb2235538c074268dd01ae"
+  integrity sha512-BV3bw6MyUH1iIsGhXlOK6sXhmSarZjtJ/vMiD9dNmpY8QXFFQTj+6v92pcfy1iqa8DeAfJFwoxcrS/TUZda6sw==
+  dependencies:
+    "@babel/helper-module-transforms" "^7.1.0"
+    "@babel/helper-plugin-utils" "^7.0.0"
+
+"@babel/plugin-transform-named-capturing-groups-regex@^7.4.5":
+  version "7.4.5"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.4.5.tgz#9d269fd28a370258199b4294736813a60bbdd106"
+  integrity sha512-z7+2IsWafTBbjNsOxU/Iv5CvTJlr5w4+HGu1HovKYTtgJ362f7kBcQglkfmlspKKZ3bgrbSGvLfNx++ZJgCWsg==
+  dependencies:
+    regexp-tree "^0.1.6"
+
+"@babel/plugin-transform-new-target@^7.4.4":
+  version "7.4.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.4.4.tgz#18d120438b0cc9ee95a47f2c72bc9768fbed60a5"
+  integrity sha512-r1z3T2DNGQwwe2vPGZMBNjioT2scgWzK9BCnDEh+46z8EEwXBq24uRzd65I7pjtugzPSj921aM15RpESgzsSuA==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.0.0"
+
+"@babel/plugin-transform-object-super@^7.2.0":
+  version "7.2.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.2.0.tgz#b35d4c10f56bab5d650047dad0f1d8e8814b6598"
+  integrity sha512-VMyhPYZISFZAqAPVkiYb7dUe2AsVi2/wCT5+wZdsNO31FojQJa9ns40hzZ6U9f50Jlq4w6qwzdBB2uwqZ00ebg==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.0.0"
+    "@babel/helper-replace-supers" "^7.1.0"
+
+"@babel/plugin-transform-parameters@^7.4.4":
+  version "7.4.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.4.4.tgz#7556cf03f318bd2719fe4c922d2d808be5571e16"
+  integrity sha512-oMh5DUO1V63nZcu/ZVLQFqiihBGo4OpxJxR1otF50GMeCLiRx5nUdtokd+u9SuVJrvvuIh9OosRFPP4pIPnwmw==
+  dependencies:
+    "@babel/helper-call-delegate" "^7.4.4"
+    "@babel/helper-get-function-arity" "^7.0.0"
+    "@babel/helper-plugin-utils" "^7.0.0"
+
+"@babel/plugin-transform-property-literals@^7.2.0":
+  version "7.2.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.2.0.tgz#03e33f653f5b25c4eb572c98b9485055b389e905"
+  integrity sha512-9q7Dbk4RhgcLp8ebduOpCbtjh7C0itoLYHXd9ueASKAG/is5PQtMR5VJGka9NKqGhYEGn5ITahd4h9QeBMylWQ==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.0.0"
+
+"@babel/plugin-transform-regenerator@^7.4.5":
+  version "7.4.5"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.4.5.tgz#629dc82512c55cee01341fb27bdfcb210354680f"
+  integrity sha512-gBKRh5qAaCWntnd09S8QC7r3auLCqq5DI6O0DlfoyDjslSBVqBibrMdsqO+Uhmx3+BlOmE/Kw1HFxmGbv0N9dA==
+  dependencies:
+    regenerator-transform "^0.14.0"
+
+"@babel/plugin-transform-reserved-words@^7.2.0":
+  version "7.2.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.2.0.tgz#4792af87c998a49367597d07fedf02636d2e1634"
+  integrity sha512-fz43fqW8E1tAB3DKF19/vxbpib1fuyCwSPE418ge5ZxILnBhWyhtPgz8eh1RCGGJlwvksHkyxMxh0eenFi+kFw==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.0.0"
+
+"@babel/plugin-transform-runtime@^7.5.0":
+  version "7.5.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.5.0.tgz#45242c2c9281158c5f06d25beebac63e498a284e"
+  integrity sha512-LmPIZOAgTLl+86gR9KjLXex6P/lRz1fWEjTz6V6QZMmKie51ja3tvzdwORqhHc4RWR8TcZ5pClpRWs0mlaA2ng==
+  dependencies:
+    "@babel/helper-module-imports" "^7.0.0"
+    "@babel/helper-plugin-utils" "^7.0.0"
+    resolve "^1.8.1"
+    semver "^5.5.1"
+
+"@babel/plugin-transform-shorthand-properties@^7.2.0":
+  version "7.2.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.2.0.tgz#6333aee2f8d6ee7e28615457298934a3b46198f0"
+  integrity sha512-QP4eUM83ha9zmYtpbnyjTLAGKQritA5XW/iG9cjtuOI8s1RuL/3V6a3DeSHfKutJQ+ayUfeZJPcnCYEQzaPQqg==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.0.0"
+
+"@babel/plugin-transform-spread@^7.2.0":
+  version "7.2.2"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-spread/-/plugin-transform-spread-7.2.2.tgz#3103a9abe22f742b6d406ecd3cd49b774919b406"
+  integrity sha512-KWfky/58vubwtS0hLqEnrWJjsMGaOeSBn90Ezn5Jeg9Z8KKHmELbP1yGylMlm5N6TPKeY9A2+UaSYLdxahg01w==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.0.0"
+
+"@babel/plugin-transform-sticky-regex@^7.2.0":
+  version "7.2.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.2.0.tgz#a1e454b5995560a9c1e0d537dfc15061fd2687e1"
+  integrity sha512-KKYCoGaRAf+ckH8gEL3JHUaFVyNHKe3ASNsZ+AlktgHevvxGigoIttrEJb8iKN03Q7Eazlv1s6cx2B2cQ3Jabw==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.0.0"
+    "@babel/helper-regex" "^7.0.0"
+
+"@babel/plugin-transform-template-literals@^7.4.4":
+  version "7.4.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.4.4.tgz#9d28fea7bbce637fb7612a0750989d8321d4bcb0"
+  integrity sha512-mQrEC4TWkhLN0z8ygIvEL9ZEToPhG5K7KDW3pzGqOfIGZ28Jb0POUkeWcoz8HnHvhFy6dwAT1j8OzqN8s804+g==
+  dependencies:
+    "@babel/helper-annotate-as-pure" "^7.0.0"
+    "@babel/helper-plugin-utils" "^7.0.0"
+
+"@babel/plugin-transform-typeof-symbol@^7.2.0":
+  version "7.2.0"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.2.0.tgz#117d2bcec2fbf64b4b59d1f9819894682d29f2b2"
+  integrity sha512-2LNhETWYxiYysBtrBTqL8+La0jIoQQnIScUJc74OYvUGRmkskNY4EzLCnjHBzdmb38wqtTaixpo1NctEcvMDZw==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.0.0"
+
+"@babel/plugin-transform-unicode-regex@^7.4.4":
+  version "7.4.4"
+  resolved "https://registry.yarnpkg.com/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.4.4.tgz#ab4634bb4f14d36728bf5978322b35587787970f"
+  integrity sha512-il+/XdNw01i93+M9J9u4T7/e/Ue/vWfNZE4IRUQjplu2Mqb/AFTDimkw2tdEdSH50wuQXZAbXSql0UphQke+vA==
+  dependencies:
+    "@babel/helper-plugin-utils" "^7.0.0"
+    "@babel/helper-regex" "^7.4.4"
+    regexpu-core "^4.5.4"
+
+"@babel/preset-env@^7.5.4":
+  version "7.5.4"
+  resolved "https://registry.yarnpkg.com/@babel/preset-env/-/preset-env-7.5.4.tgz#64bc15041a3cbb0798930319917e70fcca57713d"
+  integrity sha512-hFnFnouyRNiH1rL8YkX1ANCNAUVC8Djwdqfev8i1415tnAG+7hlA5zhZ0Q/3Q5gkop4HioIPbCEWAalqcbxRoQ==
+  dependencies:
+    "@babel/helper-module-imports" "^7.0.0"
+    "@babel/helper-plugin-utils" "^7.0.0"
+    "@babel/plugin-proposal-async-generator-functions" "^7.2.0"
+    "@babel/plugin-proposal-dynamic-import" "^7.5.0"
+    "@babel/plugin-proposal-json-strings" "^7.2.0"
+    "@babel/plugin-proposal-object-rest-spread" "^7.5.4"
+    "@babel/plugin-proposal-optional-catch-binding" "^7.2.0"
+    "@babel/plugin-proposal-unicode-property-regex" "^7.4.4"
+    "@babel/plugin-syntax-async-generators" "^7.2.0"
+    "@babel/plugin-syntax-dynamic-import" "^7.2.0"
+    "@babel/plugin-syntax-json-strings" "^7.2.0"
+    "@babel/plugin-syntax-object-rest-spread" "^7.2.0"
+    "@babel/plugin-syntax-optional-catch-binding" "^7.2.0"
+    "@babel/plugin-transform-arrow-functions" "^7.2.0"
+    "@babel/plugin-transform-async-to-generator" "^7.5.0"
+    "@babel/plugin-transform-block-scoped-functions" "^7.2.0"
+    "@babel/plugin-transform-block-scoping" "^7.4.4"
+    "@babel/plugin-transform-classes" "^7.4.4"
+    "@babel/plugin-transform-computed-properties" "^7.2.0"
+    "@babel/plugin-transform-destructuring" "^7.5.0"
+    "@babel/plugin-transform-dotall-regex" "^7.4.4"
+    "@babel/plugin-transform-duplicate-keys" "^7.5.0"
+    "@babel/plugin-transform-exponentiation-operator" "^7.2.0"
+    "@babel/plugin-transform-for-of" "^7.4.4"
+    "@babel/plugin-transform-function-name" "^7.4.4"
+    "@babel/plugin-transform-literals" "^7.2.0"
+    "@babel/plugin-transform-member-expression-literals" "^7.2.0"
+    "@babel/plugin-transform-modules-amd" "^7.5.0"
+    "@babel/plugin-transform-modules-commonjs" "^7.5.0"
+    "@babel/plugin-transform-modules-systemjs" "^7.5.0"
+    "@babel/plugin-transform-modules-umd" "^7.2.0"
+    "@babel/plugin-transform-named-capturing-groups-regex" "^7.4.5"
+    "@babel/plugin-transform-new-target" "^7.4.4"
+    "@babel/plugin-transform-object-super" "^7.2.0"
+    "@babel/plugin-transform-parameters" "^7.4.4"
+    "@babel/plugin-transform-property-literals" "^7.2.0"
+    "@babel/plugin-transform-regenerator" "^7.4.5"
+    "@babel/plugin-transform-reserved-words" "^7.2.0"
+    "@babel/plugin-transform-shorthand-properties" "^7.2.0"
+    "@babel/plugin-transform-spread" "^7.2.0"
+    "@babel/plugin-transform-sticky-regex" "^7.2.0"
+    "@babel/plugin-transform-template-literals" "^7.4.4"
+    "@babel/plugin-transform-typeof-symbol" "^7.2.0"
+    "@babel/plugin-transform-unicode-regex" "^7.4.4"
+    "@babel/types" "^7.5.0"
+    browserslist "^4.6.0"
+    core-js-compat "^3.1.1"
+    invariant "^2.2.2"
+    js-levenshtein "^1.1.3"
+    semver "^5.5.0"
+
+"@babel/runtime@^7.5.4":
+  version "7.5.4"
+  resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.5.4.tgz#cb7d1ad7c6d65676e66b47186577930465b5271b"
+  integrity sha512-Na84uwyImZZc3FKf4aUF1tysApzwf3p2yuFBIyBfbzT5glzKTdvYI4KVW4kcgjrzoGUjC7w3YyCHcJKaRxsr2Q==
+  dependencies:
+    regenerator-runtime "^0.13.2"
+
+"@babel/template@^7.1.0", "@babel/template@^7.4.4":
+  version "7.4.4"
+  resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.4.4.tgz#f4b88d1225689a08f5bc3a17483545be9e4ed237"
+  integrity sha512-CiGzLN9KgAvgZsnivND7rkA+AeJ9JB0ciPOD4U59GKbQP2iQl+olF1l76kJOupqidozfZ32ghwBEJDhnk9MEcw==
+  dependencies:
+    "@babel/code-frame" "^7.0.0"
+    "@babel/parser" "^7.4.4"
+    "@babel/types" "^7.4.4"
+
+"@babel/traverse@^7.1.0", "@babel/traverse@^7.4.4", "@babel/traverse@^7.5.0":
+  version "7.5.0"
+  resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.5.0.tgz#4216d6586854ef5c3c4592dab56ec7eb78485485"
+  integrity sha512-SnA9aLbyOCcnnbQEGwdfBggnc142h/rbqqsXcaATj2hZcegCl903pUD/lfpsNBlBSuWow/YDfRyJuWi2EPR5cg==
+  dependencies:
+    "@babel/code-frame" "^7.0.0"
+    "@babel/generator" "^7.5.0"
+    "@babel/helper-function-name" "^7.1.0"
+    "@babel/helper-split-export-declaration" "^7.4.4"
+    "@babel/parser" "^7.5.0"
+    "@babel/types" "^7.5.0"
+    debug "^4.1.0"
+    globals "^11.1.0"
+    lodash "^4.17.11"
+
+"@babel/types@^7.0.0", "@babel/types@^7.2.0", "@babel/types@^7.4.4", "@babel/types@^7.5.0":
+  version "7.5.0"
+  resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.5.0.tgz#e47d43840c2e7f9105bc4d3a2c371b4d0c7832ab"
+  integrity sha512-UFpDVqRABKsW01bvw7/wSUe56uy6RXM5+VJibVVAybDGxEW25jdwiFJEf7ASvSaC7sN7rbE/l3cLp2izav+CtQ==
+  dependencies:
+    esutils "^2.0.2"
+    lodash "^4.17.11"
+    to-fast-properties "^2.0.0"
+
+"@types/events@*":
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7"
+  integrity sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g==
+
+"@types/glob@^7.1.1":
+  version "7.1.1"
+  resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.1.tgz#aa59a1c6e3fbc421e07ccd31a944c30eba521575"
+  integrity sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w==
+  dependencies:
+    "@types/events" "*"
+    "@types/minimatch" "*"
+    "@types/node" "*"
+
+"@types/minimatch@*":
+  version "3.0.3"
+  resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
+  integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==
+
+"@types/node@*":
+  version "12.6.2"
+  resolved "https://registry.yarnpkg.com/@types/node/-/node-12.6.2.tgz#a5ccec6abb6060d5f20d256fb03ed743e9774999"
+  integrity sha512-gojym4tX0FWeV2gsW4Xmzo5wxGjXGm550oVUII7f7G5o4BV6c7DBdiG1RRQd+y1bvqRyYtPfMK85UM95vsapqQ==
+
+"@vue/component-compiler-utils@^2.5.1":
+  version "2.6.0"
+  resolved "https://registry.yarnpkg.com/@vue/component-compiler-utils/-/component-compiler-utils-2.6.0.tgz#aa46d2a6f7647440b0b8932434d22f12371e543b"
+  integrity sha512-IHjxt7LsOFYc0DkTncB7OXJL7UzwOLPPQCfEUNyxL2qt+tF12THV+EO33O1G2Uk4feMSWua3iD39Itszx0f0bw==
+  dependencies:
+    consolidate "^0.15.1"
+    hash-sum "^1.0.2"
+    lru-cache "^4.1.2"
+    merge-source-map "^1.1.0"
+    postcss "^7.0.14"
+    postcss-selector-parser "^5.0.0"
+    prettier "1.16.3"
+    source-map "~0.6.1"
+    vue-template-es2015-compiler "^1.9.0"
+
+"@webassemblyjs/ast@1.8.5":
+  version "1.8.5"
+  resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.8.5.tgz#51b1c5fe6576a34953bf4b253df9f0d490d9e359"
+  integrity sha512-aJMfngIZ65+t71C3y2nBBg5FFG0Okt9m0XEgWZ7Ywgn1oMAT8cNwx00Uv1cQyHtidq0Xn94R4TAywO+LCQ+ZAQ==
+  dependencies:
+    "@webassemblyjs/helper-module-context" "1.8.5"
+    "@webassemblyjs/helper-wasm-bytecode" "1.8.5"
+    "@webassemblyjs/wast-parser" "1.8.5"
+
+"@webassemblyjs/floating-point-hex-parser@1.8.5":
+  version "1.8.5"
+  resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.8.5.tgz#1ba926a2923613edce496fd5b02e8ce8a5f49721"
+  integrity sha512-9p+79WHru1oqBh9ewP9zW95E3XAo+90oth7S5Re3eQnECGq59ly1Ri5tsIipKGpiStHsUYmY3zMLqtk3gTcOtQ==
+
+"@webassemblyjs/helper-api-error@1.8.5":
+  version "1.8.5"
+  resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.8.5.tgz#c49dad22f645227c5edb610bdb9697f1aab721f7"
+  integrity sha512-Za/tnzsvnqdaSPOUXHyKJ2XI7PDX64kWtURyGiJJZKVEdFOsdKUCPTNEVFZq3zJ2R0G5wc2PZ5gvdTRFgm81zA==
+
+"@webassemblyjs/helper-buffer@1.8.5":
+  version "1.8.5"
+  resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.8.5.tgz#fea93e429863dd5e4338555f42292385a653f204"
+  integrity sha512-Ri2R8nOS0U6G49Q86goFIPNgjyl6+oE1abW1pS84BuhP1Qcr5JqMwRFT3Ah3ADDDYGEgGs1iyb1DGX+kAi/c/Q==
+
+"@webassemblyjs/helper-code-frame@1.8.5":
+  version "1.8.5"
+  resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.8.5.tgz#9a740ff48e3faa3022b1dff54423df9aa293c25e"
+  integrity sha512-VQAadSubZIhNpH46IR3yWO4kZZjMxN1opDrzePLdVKAZ+DFjkGD/rf4v1jap744uPVU6yjL/smZbRIIJTOUnKQ==
+  dependencies:
+    "@webassemblyjs/wast-printer" "1.8.5"
+
+"@webassemblyjs/helper-fsm@1.8.5":
+  version "1.8.5"
+  resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-fsm/-/helper-fsm-1.8.5.tgz#ba0b7d3b3f7e4733da6059c9332275d860702452"
+  integrity sha512-kRuX/saORcg8se/ft6Q2UbRpZwP4y7YrWsLXPbbmtepKr22i8Z4O3V5QE9DbZK908dh5Xya4Un57SDIKwB9eow==
+
+"@webassemblyjs/helper-module-context@1.8.5":
+  version "1.8.5"
+  resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-module-context/-/helper-module-context-1.8.5.tgz#def4b9927b0101dc8cbbd8d1edb5b7b9c82eb245"
+  integrity sha512-/O1B236mN7UNEU4t9X7Pj38i4VoU8CcMHyy3l2cV/kIF4U5KoHXDVqcDuOs1ltkac90IM4vZdHc52t1x8Yfs3g==
+  dependencies:
+    "@webassemblyjs/ast" "1.8.5"
+    mamacro "^0.0.3"
+
+"@webassemblyjs/helper-wasm-bytecode@1.8.5":
+  version "1.8.5"
+  resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.8.5.tgz#537a750eddf5c1e932f3744206551c91c1b93e61"
+  integrity sha512-Cu4YMYG3Ddl72CbmpjU/wbP6SACcOPVbHN1dI4VJNJVgFwaKf1ppeFJrwydOG3NDHxVGuCfPlLZNyEdIYlQ6QQ==
+
+"@webassemblyjs/helper-wasm-section@1.8.5":
+  version "1.8.5"
+  resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.8.5.tgz#74ca6a6bcbe19e50a3b6b462847e69503e6bfcbf"
+  integrity sha512-VV083zwR+VTrIWWtgIUpqfvVdK4ff38loRmrdDBgBT8ADXYsEZ5mPQ4Nde90N3UYatHdYoDIFb7oHzMncI02tA==
+  dependencies:
+    "@webassemblyjs/ast" "1.8.5"
+    "@webassemblyjs/helper-buffer" "1.8.5"
+    "@webassemblyjs/helper-wasm-bytecode" "1.8.5"
+    "@webassemblyjs/wasm-gen" "1.8.5"
+
+"@webassemblyjs/ieee754@1.8.5":
+  version "1.8.5"
+  resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.8.5.tgz#712329dbef240f36bf57bd2f7b8fb9bf4154421e"
+  integrity sha512-aaCvQYrvKbY/n6wKHb/ylAJr27GglahUO89CcGXMItrOBqRarUMxWLJgxm9PJNuKULwN5n1csT9bYoMeZOGF3g==
+  dependencies:
+    "@xtuc/ieee754" "^1.2.0"
+
+"@webassemblyjs/leb128@1.8.5":
+  version "1.8.5"
+  resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.8.5.tgz#044edeb34ea679f3e04cd4fd9824d5e35767ae10"
+  integrity sha512-plYUuUwleLIziknvlP8VpTgO4kqNaH57Y3JnNa6DLpu/sGcP6hbVdfdX5aHAV716pQBKrfuU26BJK29qY37J7A==
+  dependencies:
+    "@xtuc/long" "4.2.2"
+
+"@webassemblyjs/utf8@1.8.5":
+  version "1.8.5"
+  resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.8.5.tgz#a8bf3b5d8ffe986c7c1e373ccbdc2a0915f0cedc"
+  integrity sha512-U7zgftmQriw37tfD934UNInokz6yTmn29inT2cAetAsaU9YeVCveWEwhKL1Mg4yS7q//NGdzy79nlXh3bT8Kjw==
+
+"@webassemblyjs/wasm-edit@1.8.5":
+  version "1.8.5"
+  resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.8.5.tgz#962da12aa5acc1c131c81c4232991c82ce56e01a"
+  integrity sha512-A41EMy8MWw5yvqj7MQzkDjU29K7UJq1VrX2vWLzfpRHt3ISftOXqrtojn7nlPsZ9Ijhp5NwuODuycSvfAO/26Q==
+  dependencies:
+    "@webassemblyjs/ast" "1.8.5"
+    "@webassemblyjs/helper-buffer" "1.8.5"
+    "@webassemblyjs/helper-wasm-bytecode" "1.8.5"
+    "@webassemblyjs/helper-wasm-section" "1.8.5"
+    "@webassemblyjs/wasm-gen" "1.8.5"
+    "@webassemblyjs/wasm-opt" "1.8.5"
+    "@webassemblyjs/wasm-parser" "1.8.5"
+    "@webassemblyjs/wast-printer" "1.8.5"
+
+"@webassemblyjs/wasm-gen@1.8.5":
+  version "1.8.5"
+  resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.8.5.tgz#54840766c2c1002eb64ed1abe720aded714f98bc"
+  integrity sha512-BCZBT0LURC0CXDzj5FXSc2FPTsxwp3nWcqXQdOZE4U7h7i8FqtFK5Egia6f9raQLpEKT1VL7zr4r3+QX6zArWg==
+  dependencies:
+    "@webassemblyjs/ast" "1.8.5"
+    "@webassemblyjs/helper-wasm-bytecode" "1.8.5"
+    "@webassemblyjs/ieee754" "1.8.5"
+    "@webassemblyjs/leb128" "1.8.5"
+    "@webassemblyjs/utf8" "1.8.5"
+
+"@webassemblyjs/wasm-opt@1.8.5":
+  version "1.8.5"
+  resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.8.5.tgz#b24d9f6ba50394af1349f510afa8ffcb8a63d264"
+  integrity sha512-HKo2mO/Uh9A6ojzu7cjslGaHaUU14LdLbGEKqTR7PBKwT6LdPtLLh9fPY33rmr5wcOMrsWDbbdCHq4hQUdd37Q==
+  dependencies:
+    "@webassemblyjs/ast" "1.8.5"
+    "@webassemblyjs/helper-buffer" "1.8.5"
+    "@webassemblyjs/wasm-gen" "1.8.5"
+    "@webassemblyjs/wasm-parser" "1.8.5"
+
+"@webassemblyjs/wasm-parser@1.8.5":
+  version "1.8.5"
+  resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.8.5.tgz#21576f0ec88b91427357b8536383668ef7c66b8d"
+  integrity sha512-pi0SYE9T6tfcMkthwcgCpL0cM9nRYr6/6fjgDtL6q/ZqKHdMWvxitRi5JcZ7RI4SNJJYnYNaWy5UUrHQy998lw==
+  dependencies:
+    "@webassemblyjs/ast" "1.8.5"
+    "@webassemblyjs/helper-api-error" "1.8.5"
+    "@webassemblyjs/helper-wasm-bytecode" "1.8.5"
+    "@webassemblyjs/ieee754" "1.8.5"
+    "@webassemblyjs/leb128" "1.8.5"
+    "@webassemblyjs/utf8" "1.8.5"
+
+"@webassemblyjs/wast-parser@1.8.5":
+  version "1.8.5"
+  resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-parser/-/wast-parser-1.8.5.tgz#e10eecd542d0e7bd394f6827c49f3df6d4eefb8c"
+  integrity sha512-daXC1FyKWHF1i11obK086QRlsMsY4+tIOKgBqI1lxAnkp9xe9YMcgOxm9kLe+ttjs5aWV2KKE1TWJCN57/Btsg==
+  dependencies:
+    "@webassemblyjs/ast" "1.8.5"
+    "@webassemblyjs/floating-point-hex-parser" "1.8.5"
+    "@webassemblyjs/helper-api-error" "1.8.5"
+    "@webassemblyjs/helper-code-frame" "1.8.5"
+    "@webassemblyjs/helper-fsm" "1.8.5"
+    "@xtuc/long" "4.2.2"
+
+"@webassemblyjs/wast-printer@1.8.5":
+  version "1.8.5"
+  resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.8.5.tgz#114bbc481fd10ca0e23b3560fa812748b0bae5bc"
+  integrity sha512-w0U0pD4EhlnvRyeJzBqaVSJAo9w/ce7/WPogeXLzGkO6hzhr4GnQIZ4W4uUt5b9ooAaXPtnXlj0gzsXEOUNYMg==
+  dependencies:
+    "@webassemblyjs/ast" "1.8.5"
+    "@webassemblyjs/wast-parser" "1.8.5"
+    "@xtuc/long" "4.2.2"
+
+"@xtuc/ieee754@^1.2.0":
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790"
+  integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==
+
+"@xtuc/long@4.2.2":
+  version "4.2.2"
+  resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d"
+  integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==
+
+abbrev@1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8"
+  integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==
+
+accepts@~1.3.4, accepts@~1.3.5, accepts@~1.3.7:
+  version "1.3.7"
+  resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd"
+  integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==
+  dependencies:
+    mime-types "~2.1.24"
+    negotiator "0.6.2"
+
+acorn-jsx@^5.0.0:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.0.1.tgz#32a064fd925429216a09b141102bfdd185fae40e"
+  integrity sha512-HJ7CfNHrfJLlNTzIEUTj43LNWGkqpRLxm3YjAlcD0ACydk9XynzYsCBHxut+iqt+1aBXkx9UP/w/ZqMr13XIzg==
+
+acorn@^5.2.1:
+  version "5.7.3"
+  resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.3.tgz#67aa231bf8812974b85235a96771eb6bd07ea279"
+  integrity sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==
+
+acorn@^6.0.7, acorn@^6.2.0:
+  version "6.2.0"
+  resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.2.0.tgz#67f0da2fc339d6cfb5d6fb244fd449f33cd8bbe3"
+  integrity sha512-8oe72N3WPMjA+2zVG71Ia0nXZ8DpQH+QyyHO+p06jT8eg8FGG3FbcUIi8KziHlAfheJQZeoqbvq1mQSQHXKYLw==
+
+ajv-errors@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.1.tgz#f35986aceb91afadec4102fbd85014950cefa64d"
+  integrity sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==
+
+ajv-keywords@^3.1.0:
+  version "3.4.1"
+  resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.4.1.tgz#ef916e271c64ac12171fd8384eaae6b2345854da"
+  integrity sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ==
+
+ajv@^6.1.0, ajv@^6.5.5:
+  version "6.10.1"
+  resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.1.tgz#ebf8d3af22552df9dd049bfbe50cc2390e823593"
+  integrity sha512-w1YQaVGNC6t2UCPjEawK/vo/dG8OOrVtUmhBT1uJJYxbl5kU2Tj3v6LGqBcsysN1yhuCStJCCA3GqdvKY8sqXQ==
+  dependencies:
+    fast-deep-equal "^2.0.1"
+    fast-json-stable-stringify "^2.0.0"
+    json-schema-traverse "^0.4.1"
+    uri-js "^4.2.2"
+
+ajv@^6.10.0, ajv@^6.10.2:
+  version "6.10.2"
+  resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.2.tgz#d3cea04d6b017b2894ad69040fec8b623eb4bd52"
+  integrity sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==
+  dependencies:
+    fast-deep-equal "^2.0.1"
+    fast-json-stable-stringify "^2.0.0"
+    json-schema-traverse "^0.4.1"
+    uri-js "^4.2.2"
+
+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"
+  integrity sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=
+  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"
+  integrity sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=
+
+ansi-colors@^3.0.0:
+  version "3.2.4"
+  resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-3.2.4.tgz#e3a3da4bfbae6c86a9c285625de124a234026fbf"
+  integrity sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==
+
+ansi-escapes@^3.2.0:
+  version "3.2.0"
+  resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b"
+  integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==
+
+ansi-html@0.0.7:
+  version "0.0.7"
+  resolved "https://registry.yarnpkg.com/ansi-html/-/ansi-html-0.0.7.tgz#813584021962a9e9e6fd039f940d12f56ca7859e"
+  integrity sha1-gTWEAhliqenm/QOflA0S9WynhZ4=
+
+ansi-regex@^2.0.0:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df"
+  integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8=
+
+ansi-regex@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998"
+  integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=
+
+ansi-regex@^4.1.0:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997"
+  integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==
+
+ansi-styles@^2.2.1:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe"
+  integrity sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=
+
+ansi-styles@^3.2.0, ansi-styles@^3.2.1:
+  version "3.2.1"
+  resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d"
+  integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==
+  dependencies:
+    color-convert "^1.9.0"
+
+anymatch@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb"
+  integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==
+  dependencies:
+    micromatch "^3.1.4"
+    normalize-path "^2.1.1"
+
+aproba@^1.0.3, aproba@^1.1.1:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a"
+  integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==
+
+are-we-there-yet@~1.1.2:
+  version "1.1.5"
+  resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21"
+  integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==
+  dependencies:
+    delegates "^1.0.0"
+    readable-stream "^2.0.6"
+
+argparse@^1.0.7:
+  version "1.0.10"
+  resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
+  integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==
+  dependencies:
+    sprintf-js "~1.0.2"
+
+arr-diff@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520"
+  integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=
+
+arr-flatten@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1"
+  integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==
+
+arr-union@^3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4"
+  integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=
+
+array-find-index@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1"
+  integrity sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=
+
+array-flatten@1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
+  integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=
+
+array-flatten@^2.1.0:
+  version "2.1.2"
+  resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-2.1.2.tgz#24ef80a28c1a893617e2149b0c6d0d788293b099"
+  integrity sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==
+
+array-union@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39"
+  integrity sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=
+  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"
+  integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY=
+
+array-unique@^0.3.2:
+  version "0.3.2"
+  resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428"
+  integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=
+
+asn1.js@^4.0.0:
+  version "4.10.1"
+  resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0"
+  integrity sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==
+  dependencies:
+    bn.js "^4.0.0"
+    inherits "^2.0.1"
+    minimalistic-assert "^1.0.0"
+
+asn1@~0.2.3:
+  version "0.2.4"
+  resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136"
+  integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==
+  dependencies:
+    safer-buffer "~2.1.0"
+
+assert-plus@1.0.0, assert-plus@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525"
+  integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=
+
+assert@^1.1.1:
+  version "1.5.0"
+  resolved "https://registry.yarnpkg.com/assert/-/assert-1.5.0.tgz#55c109aaf6e0aefdb3dc4b71240c70bf574b18eb"
+  integrity sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==
+  dependencies:
+    object-assign "^4.1.1"
+    util "0.10.3"
+
+assign-symbols@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367"
+  integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=
+
+ast-types@0.9.6:
+  version "0.9.6"
+  resolved "https://registry.yarnpkg.com/ast-types/-/ast-types-0.9.6.tgz#102c9e9e9005d3e7e3829bf0c4fa24ee862ee9b9"
+  integrity sha1-ECyenpAF0+fjgpvwxPok7oYu6bk=
+
+astral-regex@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-1.0.0.tgz#6c8c3fb827dd43ee3918f27b82782ab7658a6fd9"
+  integrity sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==
+
+async-each@^1.0.1:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf"
+  integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==
+
+async-foreach@^0.1.3:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/async-foreach/-/async-foreach-0.1.3.tgz#36121f845c0578172de419a97dbeb1d16ec34542"
+  integrity sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI=
+
+async@^1.5.2:
+  version "1.5.2"
+  resolved "https://registry.yarnpkg.com/async/-/async-1.5.2.tgz#ec6a61ae56480c0c3cb241c95618e20892f9672a"
+  integrity sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=
+
+async@~0.2.6:
+  version "0.2.10"
+  resolved "https://registry.yarnpkg.com/async/-/async-0.2.10.tgz#b6bbe0b0674b9d719708ca38de8c237cb526c3d1"
+  integrity sha1-trvgsGdLnXGXCMo43owjfLUmw9E=
+
+asynckit@^0.4.0:
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79"
+  integrity sha1-x57Zf380y48robyXkLzDZkdLS3k=
+
+atob@^2.1.1:
+  version "2.1.2"
+  resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9"
+  integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==
+
+aws-sign2@~0.7.0:
+  version "0.7.0"
+  resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8"
+  integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=
+
+aws4@^1.8.0:
+  version "1.8.0"
+  resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.8.0.tgz#f0e003d9ca9e7f59c7a508945d7b2ef9a04a542f"
+  integrity sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==
+
+babel-loader@^8.0.6:
+  version "8.0.6"
+  resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.0.6.tgz#e33bdb6f362b03f4bb141a0c21ab87c501b70dfb"
+  integrity sha512-4BmWKtBOBm13uoUwd08UwjZlaw3O9GWf456R9j+5YykFZ6LUIjIKLc0zEZf+hauxPOJs96C8k6FvYD09vWzhYw==
+  dependencies:
+    find-cache-dir "^2.0.0"
+    loader-utils "^1.0.2"
+    mkdirp "^0.5.1"
+    pify "^4.0.1"
+
+babel-plugin-dynamic-import-node@^2.3.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.3.0.tgz#f00f507bdaa3c3e3ff6e7e5e98d90a7acab96f7f"
+  integrity sha512-o6qFkpeQEBxcqt0XYlWzAVxNCSCZdUgcR8IRlhD/8DylxjjO4foPcvTW0GGKa/cVt3rvxZ7o5ippJ+/0nvLhlQ==
+  dependencies:
+    object.assign "^4.1.0"
+
+babel-runtime@^6.0.0:
+  version "6.26.0"
+  resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.26.0.tgz#965c7058668e82b55d7bfe04ff2337bc8b5647fe"
+  integrity sha1-llxwWGaOgrVde/4E/yM3vItWR/4=
+  dependencies:
+    core-js "^2.4.0"
+    regenerator-runtime "^0.11.0"
+
+balanced-match@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
+  integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c=
+
+base62@^1.1.0:
+  version "1.2.8"
+  resolved "https://registry.yarnpkg.com/base62/-/base62-1.2.8.tgz#1264cb0fb848d875792877479dbe8bae6bae3428"
+  integrity sha512-V6YHUbjLxN1ymqNLb1DPHoU1CpfdL7d2YTIp5W3U4hhoG4hhxNmsFDs66M9EXxBiSEke5Bt5dwdfMwwZF70iLA==
+
+base64-js@^1.0.2:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.3.0.tgz#cab1e6118f051095e58b5281aea8c1cd22bfc0e3"
+  integrity sha512-ccav/yGvoa80BQDljCxsmmQ3Xvx60/UpBIij5QN21W3wBi/hhIC9OoO+KLpu9IJTS9j4DRVJ3aDDF9cMSoa2lw==
+
+base@^0.11.1:
+  version "0.11.2"
+  resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f"
+  integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==
+  dependencies:
+    cache-base "^1.0.1"
+    class-utils "^0.3.5"
+    component-emitter "^1.2.1"
+    define-property "^1.0.0"
+    isobject "^3.0.1"
+    mixin-deep "^1.2.0"
+    pascalcase "^0.1.1"
+
+batch@0.6.1:
+  version "0.6.1"
+  resolved "https://registry.yarnpkg.com/batch/-/batch-0.6.1.tgz#dc34314f4e679318093fc760272525f94bf25c16"
+  integrity sha1-3DQxT05nkxgJP8dgJyUl+UvyXBY=
+
+bcrypt-pbkdf@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e"
+  integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=
+  dependencies:
+    tweetnacl "^0.14.3"
+
+big.js@^3.1.3:
+  version "3.2.0"
+  resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.2.0.tgz#a5fc298b81b9e0dca2e458824784b65c52ba588e"
+  integrity sha512-+hN/Zh2D08Mx65pZ/4g5bsmNiZUuChDiQfTUQ7qJr4/kuopCr88xZsAXv6mBoZEsUI4OuGHlX59qE94K2mMW8Q==
+
+big.js@^5.2.2:
+  version "5.2.2"
+  resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328"
+  integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==
+
+binary-extensions@^1.0.0:
+  version "1.13.1"
+  resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65"
+  integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==
+
+biskviit@1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/biskviit/-/biskviit-1.0.1.tgz#037a0cd4b71b9e331fd90a1122de17dc49e420a7"
+  integrity sha1-A3oM1LcbnjMf2QoRIt4X3EnkIKc=
+  dependencies:
+    psl "^1.1.7"
+
+block-stream@*:
+  version "0.0.9"
+  resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a"
+  integrity sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=
+  dependencies:
+    inherits "~2.0.0"
+
+bluebird@^3.1.1, bluebird@^3.5.5:
+  version "3.5.5"
+  resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.5.tgz#a8d0afd73251effbbd5fe384a77d73003c17a71f"
+  integrity sha512-5am6HnnfN+urzt4yfg7IgTbotDjIT/u8AJpEt0sIU9FtXfVeezXAPKswrG+xKUCOYAINpSdgZVDU6QFh+cuH3w==
+
+bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0:
+  version "4.11.8"
+  resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.8.tgz#2cde09eb5ee341f484746bb0309b3253b1b1442f"
+  integrity sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==
+
+body-parser@1.19.0:
+  version "1.19.0"
+  resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a"
+  integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw==
+  dependencies:
+    bytes "3.1.0"
+    content-type "~1.0.4"
+    debug "2.6.9"
+    depd "~1.1.2"
+    http-errors "1.7.2"
+    iconv-lite "0.4.24"
+    on-finished "~2.3.0"
+    qs "6.7.0"
+    raw-body "2.4.0"
+    type-is "~1.6.17"
+
+bonjour@^3.5.0:
+  version "3.5.0"
+  resolved "https://registry.yarnpkg.com/bonjour/-/bonjour-3.5.0.tgz#8e890a183d8ee9a2393b3844c691a42bcf7bc9f5"
+  integrity sha1-jokKGD2O6aI5OzhExpGkK897yfU=
+  dependencies:
+    array-flatten "^2.1.0"
+    deep-equal "^1.0.1"
+    dns-equal "^1.0.0"
+    dns-txt "^2.0.2"
+    multicast-dns "^6.0.1"
+    multicast-dns-service-types "^1.1.0"
+
+boolbase@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"
+  integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24=
+
+brace-expansion@^1.1.7:
+  version "1.1.11"
+  resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd"
+  integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==
+  dependencies:
+    balanced-match "^1.0.0"
+    concat-map "0.0.1"
+
+braces@^2.3.1, braces@^2.3.2:
+  version "2.3.2"
+  resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729"
+  integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==
+  dependencies:
+    arr-flatten "^1.1.0"
+    array-unique "^0.3.2"
+    extend-shallow "^2.0.1"
+    fill-range "^4.0.0"
+    isobject "^3.0.1"
+    repeat-element "^1.1.2"
+    snapdragon "^0.8.1"
+    snapdragon-node "^2.0.1"
+    split-string "^3.0.2"
+    to-regex "^3.0.1"
+
+brorand@^1.0.1:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f"
+  integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=
+
+browserify-aes@^1.0.0, browserify-aes@^1.0.4:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48"
+  integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==
+  dependencies:
+    buffer-xor "^1.0.3"
+    cipher-base "^1.0.0"
+    create-hash "^1.1.0"
+    evp_bytestokey "^1.0.3"
+    inherits "^2.0.1"
+    safe-buffer "^5.0.1"
+
+browserify-cipher@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0"
+  integrity sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==
+  dependencies:
+    browserify-aes "^1.0.4"
+    browserify-des "^1.0.0"
+    evp_bytestokey "^1.0.0"
+
+browserify-des@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c"
+  integrity sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==
+  dependencies:
+    cipher-base "^1.0.1"
+    des.js "^1.0.0"
+    inherits "^2.0.1"
+    safe-buffer "^5.1.2"
+
+browserify-rsa@^4.0.0:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524"
+  integrity sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=
+  dependencies:
+    bn.js "^4.1.0"
+    randombytes "^2.0.1"
+
+browserify-sign@^4.0.0:
+  version "4.0.4"
+  resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.0.4.tgz#aa4eb68e5d7b658baa6bf6a57e630cbd7a93d298"
+  integrity sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=
+  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.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f"
+  integrity sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==
+  dependencies:
+    pako "~1.0.5"
+
+browserslist@^4.6.0, browserslist@^4.6.2:
+  version "4.6.4"
+  resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.6.4.tgz#fd0638b3f8867fec2c604ed0ed9300379f8ec7c2"
+  integrity sha512-ErJT8qGfRt/VWHSr1HeqZzz50DvxHtr1fVL1m5wf20aGrG8e1ce8fpZ2EjZEfs09DDZYSvtRaDlMpWslBf8Low==
+  dependencies:
+    caniuse-lite "^1.0.30000981"
+    electron-to-chromium "^1.3.188"
+    node-releases "^1.1.25"
+
+buffer-from@^1.0.0:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef"
+  integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==
+
+buffer-indexof@^1.0.0:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/buffer-indexof/-/buffer-indexof-1.1.1.tgz#52fabcc6a606d1a00302802648ef68f639da268c"
+  integrity sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g==
+
+buffer-xor@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9"
+  integrity sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=
+
+buffer@^4.3.0:
+  version "4.9.1"
+  resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298"
+  integrity sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=
+  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"
+  integrity sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=
+
+bytes@3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048"
+  integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg=
+
+bytes@3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6"
+  integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==
+
+cacache@^11.3.2:
+  version "11.3.3"
+  resolved "https://registry.yarnpkg.com/cacache/-/cacache-11.3.3.tgz#8bd29df8c6a718a6ebd2d010da4d7972ae3bbadc"
+  integrity sha512-p8WcneCytvzPxhDvYp31PD039vi77I12W+/KfR9S8AZbaiARFBCpsPJS+9uhWfeBfeAtW7o/4vt3MUqLkbY6nA==
+  dependencies:
+    bluebird "^3.5.5"
+    chownr "^1.1.1"
+    figgy-pudding "^3.5.1"
+    glob "^7.1.4"
+    graceful-fs "^4.1.15"
+    lru-cache "^5.1.1"
+    mississippi "^3.0.0"
+    mkdirp "^0.5.1"
+    move-concurrently "^1.0.1"
+    promise-inflight "^1.0.1"
+    rimraf "^2.6.3"
+    ssri "^6.0.1"
+    unique-filename "^1.1.1"
+    y18n "^4.0.0"
+
+cache-base@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2"
+  integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==
+  dependencies:
+    collection-visit "^1.0.0"
+    component-emitter "^1.2.1"
+    get-value "^2.0.6"
+    has-value "^1.0.0"
+    isobject "^3.0.1"
+    set-value "^2.0.0"
+    to-object-path "^0.3.0"
+    union-value "^1.0.0"
+    unset-value "^1.0.0"
+
+callsites@^3.0.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
+  integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
+
+camel-case@3.0.x, camel-case@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-3.0.0.tgz#ca3c3688a4e9cf3a4cda777dc4dcbc713249cf73"
+  integrity sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=
+  dependencies:
+    no-case "^2.2.0"
+    upper-case "^1.1.1"
+
+camelcase-keys@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7"
+  integrity sha1-MIvur/3ygRkFHvodkyITyRuPkuc=
+  dependencies:
+    camelcase "^2.0.0"
+    map-obj "^1.0.0"
+
+camelcase@^1.0.2:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39"
+  integrity sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=
+
+camelcase@^2.0.0:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f"
+  integrity sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=
+
+camelcase@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a"
+  integrity sha1-MvxLn82vhF/N9+c7uXysImHwqwo=
+
+camelcase@^5.0.0, camelcase@^5.3.1:
+  version "5.3.1"
+  resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320"
+  integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==
+
+caniuse-lite@^1.0.30000981:
+  version "1.0.30000984"
+  resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000984.tgz#dc96c3c469e9bcfc6ad5bdd24c77ec918ea76fe0"
+  integrity sha512-n5tKOjMaZ1fksIpQbjERuqCyfgec/m9pferkFQbLmWtqLUdmt12hNhjSwsmPdqeiG2NkITOQhr1VYIwWSAceiA==
+
+caseless@~0.12.0:
+  version "0.12.0"
+  resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc"
+  integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=
+
+center-align@^0.1.1:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad"
+  integrity sha1-qg0yYptu6XIgBBHL1EYckHvCt60=
+  dependencies:
+    align-text "^0.1.3"
+    lazy-cache "^1.0.3"
+
+chalk@2.4.2, chalk@^2.0.0, chalk@^2.1.0, chalk@^2.4.2:
+  version "2.4.2"
+  resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
+  integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
+  dependencies:
+    ansi-styles "^3.2.1"
+    escape-string-regexp "^1.0.5"
+    supports-color "^5.3.0"
+
+chalk@^1.1.1:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98"
+  integrity sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=
+  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"
+
+change-case@3.0.x:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/change-case/-/change-case-3.0.2.tgz#fd48746cce02f03f0a672577d1d3a8dc2eceb037"
+  integrity sha512-Mww+SLF6MZ0U6kdg11algyKd5BARbyM4TbFBepwowYSR5ClfQGCGtxNXgykpN0uF/bstWeaGDT4JWaDh8zWAHA==
+  dependencies:
+    camel-case "^3.0.0"
+    constant-case "^2.0.0"
+    dot-case "^2.1.0"
+    header-case "^1.0.0"
+    is-lower-case "^1.1.0"
+    is-upper-case "^1.1.0"
+    lower-case "^1.1.1"
+    lower-case-first "^1.0.0"
+    no-case "^2.3.2"
+    param-case "^2.1.0"
+    pascal-case "^2.0.0"
+    path-case "^2.1.0"
+    sentence-case "^2.1.0"
+    snake-case "^2.1.0"
+    swap-case "^1.1.0"
+    title-case "^2.1.0"
+    upper-case "^1.1.1"
+    upper-case-first "^1.1.0"
+
+chardet@^0.7.0:
+  version "0.7.0"
+  resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e"
+  integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==
+
+charenc@~0.0.1:
+  version "0.0.2"
+  resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667"
+  integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=
+
+chart.js@^2.5.0:
+  version "2.8.0"
+  resolved "https://registry.yarnpkg.com/chart.js/-/chart.js-2.8.0.tgz#b703b10d0f4ec5079eaefdcd6ca32dc8f826e0e9"
+  integrity sha512-Di3wUL4BFvqI5FB5K26aQ+hvWh8wnP9A3DWGvXHVkO13D3DSnaSsdZx29cXlEsYKVkn1E2az+ZYFS4t0zi8x0w==
+  dependencies:
+    chartjs-color "^2.1.0"
+    moment "^2.10.2"
+
+chartjs-color-string@^0.6.0:
+  version "0.6.0"
+  resolved "https://registry.yarnpkg.com/chartjs-color-string/-/chartjs-color-string-0.6.0.tgz#1df096621c0e70720a64f4135ea171d051402f71"
+  integrity sha512-TIB5OKn1hPJvO7JcteW4WY/63v6KwEdt6udfnDE9iCAZgy+V4SrbSxoIbTw/xkUIapjEI4ExGtD0+6D3KyFd7A==
+  dependencies:
+    color-name "^1.0.0"
+
+chartjs-color@^2.1.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/chartjs-color/-/chartjs-color-2.3.0.tgz#0e7e1e8dba37eae8415fd3db38bf572007dd958f"
+  integrity sha512-hEvVheqczsoHD+fZ+tfPUE+1+RbV6b+eksp2LwAhwRTVXEjCSEavvk+Hg3H6SZfGlPh/UfmWKGIvZbtobOEm3g==
+  dependencies:
+    chartjs-color-string "^0.6.0"
+    color-convert "^0.5.3"
+
+chokidar@^2.0.2, chokidar@^2.1.6:
+  version "2.1.6"
+  resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.6.tgz#b6cad653a929e244ce8a834244164d241fa954c5"
+  integrity sha512-V2jUo67OKkc6ySiRpJrjlpJKl9kDuG+Xb8VgsGzb+aEouhgS1D0weyPU4lEzdAcsCAvrih2J2BqyXqHWvVLw5g==
+  dependencies:
+    anymatch "^2.0.0"
+    async-each "^1.0.1"
+    braces "^2.3.2"
+    glob-parent "^3.1.0"
+    inherits "^2.0.3"
+    is-binary-path "^1.0.0"
+    is-glob "^4.0.0"
+    normalize-path "^3.0.0"
+    path-is-absolute "^1.0.0"
+    readdirp "^2.2.1"
+    upath "^1.1.1"
+  optionalDependencies:
+    fsevents "^1.2.7"
+
+chownr@^1.1.1:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.2.tgz#a18f1e0b269c8a6a5d3c86eb298beb14c3dd7bf6"
+  integrity sha512-GkfeAQh+QNy3wquu9oIZr6SS5x7wGdSgNQvD10X3r+AZr1Oys22HW8kAmDMvNg2+Dm0TeGaEuO8gFwdBXxwO8A==
+
+chrome-trace-event@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz#234090ee97c7d4ad1a2c4beae27505deffc608a4"
+  integrity sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ==
+  dependencies:
+    tslib "^1.9.0"
+
+cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de"
+  integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==
+  dependencies:
+    inherits "^2.0.1"
+    safe-buffer "^5.0.1"
+
+class-utils@^0.3.5:
+  version "0.3.6"
+  resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463"
+  integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==
+  dependencies:
+    arr-union "^3.1.0"
+    define-property "^0.2.5"
+    isobject "^3.0.0"
+    static-extend "^0.1.1"
+
+clean-css@3.4.x:
+  version "3.4.28"
+  resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-3.4.28.tgz#bf1945e82fc808f55695e6ddeaec01400efd03ff"
+  integrity sha1-vxlF6C/ICPVWlebd6uwBQA79A/8=
+  dependencies:
+    commander "2.8.x"
+    source-map "0.4.x"
+
+clean-css@4.2.x:
+  version "4.2.1"
+  resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.2.1.tgz#2d411ef76b8569b6d0c84068dabe85b0aa5e5c17"
+  integrity sha512-4ZxI6dy4lrY6FHzfiy1aEOXgu4LIsW2MhwG0VBKdcoGoH/XLFgaHSdLTGr4O8Be6A8r3MOphEiI8Gc1n0ecf3g==
+  dependencies:
+    source-map "~0.6.0"
+
+cli-cursor@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5"
+  integrity sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU=
+  dependencies:
+    restore-cursor "^2.0.0"
+
+cli-width@^2.0.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.0.tgz#ff19ede8a9a5e579324147b0c11f0fbcbabed639"
+  integrity sha1-/xnt6Kml5XkyQUewwR8PvLq+1jk=
+
+cliui@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1"
+  integrity sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=
+  dependencies:
+    center-align "^0.1.1"
+    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"
+  integrity sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=
+  dependencies:
+    string-width "^1.0.1"
+    strip-ansi "^3.0.1"
+    wrap-ansi "^2.0.0"
+
+cliui@^4.0.0:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/cliui/-/cliui-4.1.0.tgz#348422dbe82d800b3022eef4f6ac10bf2e4d1b49"
+  integrity sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==
+  dependencies:
+    string-width "^2.1.1"
+    strip-ansi "^4.0.0"
+    wrap-ansi "^2.0.0"
+
+cliui@^5.0.0:
+  version "5.0.0"
+  resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5"
+  integrity sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==
+  dependencies:
+    string-width "^3.1.0"
+    strip-ansi "^5.2.0"
+    wrap-ansi "^5.1.0"
+
+clone-deep@^2.0.1:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-2.0.2.tgz#00db3a1e173656730d1188c3d6aced6d7ea97713"
+  integrity sha512-SZegPTKjCgpQH63E+eN6mVEEPdQBOUzjyJm5Pora4lrwWRFS8I0QAxV/KD6vV/i0WuijHZWQC1fMsPEdxfdVCQ==
+  dependencies:
+    for-own "^1.0.0"
+    is-plain-object "^2.0.4"
+    kind-of "^6.0.0"
+    shallow-clone "^1.0.0"
+
+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"
+  integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=
+
+collection-visit@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0"
+  integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=
+  dependencies:
+    map-visit "^1.0.0"
+    object-visit "^1.0.0"
+
+color-convert@^0.5.3:
+  version "0.5.3"
+  resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-0.5.3.tgz#bdb6c69ce660fadffe0b0007cc447e1b9f7282bd"
+  integrity sha1-vbbGnOZg+t/+CwAHzER+G59ygr0=
+
+color-convert@^1.9.0:
+  version "1.9.3"
+  resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8"
+  integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==
+  dependencies:
+    color-name "1.1.3"
+
+color-name@1.1.3:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25"
+  integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=
+
+color-name@^1.0.0:
+  version "1.1.4"
+  resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2"
+  integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==
+
+combined-stream@^1.0.6, combined-stream@~1.0.6:
+  version "1.0.8"
+  resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
+  integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
+  dependencies:
+    delayed-stream "~1.0.0"
+
+commander@2.17.x:
+  version "2.17.1"
+  resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf"
+  integrity sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==
+
+commander@2.8.x:
+  version "2.8.1"
+  resolved "https://registry.yarnpkg.com/commander/-/commander-2.8.1.tgz#06be367febfda0c330aa1e2a072d3dc9762425d4"
+  integrity sha1-Br42f+v9oMMwqh4qBy09yXYkJdQ=
+  dependencies:
+    graceful-readlink ">= 1.0.0"
+
+commander@2.9.x:
+  version "2.9.0"
+  resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4"
+  integrity sha1-nJkJQXbhIkDLItbFFGCYQA/g99Q=
+  dependencies:
+    graceful-readlink ">= 1.0.0"
+
+commander@^2.20.0, commander@^2.5.0:
+  version "2.20.0"
+  resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422"
+  integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==
+
+commander@~2.19.0:
+  version "2.19.0"
+  resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a"
+  integrity sha512-6tvAOO+D6OENvRAh524Dh9jcfKTYDQAqvqezbCW82xj5X0pSrcpxtvRKHLG0yBY6SD7PSDrJaj+0AiOcKVd1Xg==
+
+commondir@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b"
+  integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=
+
+commoner@^0.10.1:
+  version "0.10.8"
+  resolved "https://registry.yarnpkg.com/commoner/-/commoner-0.10.8.tgz#34fc3672cd24393e8bb47e70caa0293811f4f2c5"
+  integrity sha1-NPw2cs0kOT6LtH5wyqApOBH08sU=
+  dependencies:
+    commander "^2.5.0"
+    detective "^4.3.1"
+    glob "^5.0.15"
+    graceful-fs "^4.1.2"
+    iconv-lite "^0.4.5"
+    mkdirp "^0.5.0"
+    private "^0.1.6"
+    q "^1.1.2"
+    recast "^0.11.17"
+
+component-emitter@^1.2.1:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0"
+  integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==
+
+compressible@~2.0.16:
+  version "2.0.17"
+  resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.17.tgz#6e8c108a16ad58384a977f3a482ca20bff2f38c1"
+  integrity sha512-BGHeLCK1GV7j1bSmQQAi26X+GgWcTjLr/0tzSvMCl3LH1w1IJ4PFSPoV5316b30cneTziC+B1a+3OjoSUcQYmw==
+  dependencies:
+    mime-db ">= 1.40.0 < 2"
+
+compression@^1.7.4:
+  version "1.7.4"
+  resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f"
+  integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==
+  dependencies:
+    accepts "~1.3.5"
+    bytes "3.0.0"
+    compressible "~2.0.16"
+    debug "2.6.9"
+    on-headers "~1.0.2"
+    safe-buffer "5.1.2"
+    vary "~1.1.2"
+
+concat-map@0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
+  integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
+
+concat-stream@^1.5.0:
+  version "1.6.2"
+  resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34"
+  integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==
+  dependencies:
+    buffer-from "^1.0.0"
+    inherits "^2.0.3"
+    readable-stream "^2.2.2"
+    typedarray "^0.0.6"
+
+connect-history-api-fallback@^1.6.0:
+  version "1.6.0"
+  resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz#8b32089359308d111115d81cad3fceab888f97bc"
+  integrity sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==
+
+console-browserify@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10"
+  integrity sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=
+  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"
+  integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=
+
+consolidate@^0.15.1:
+  version "0.15.1"
+  resolved "https://registry.yarnpkg.com/consolidate/-/consolidate-0.15.1.tgz#21ab043235c71a07d45d9aad98593b0dba56bab7"
+  integrity sha512-DW46nrsMJgy9kqAbPt5rKaCr7uFtpo4mSUvLHIUbJEjm0vo+aY5QLwBUq3FK4tRnJr/X0Psc0C4jf/h+HtXSMw==
+  dependencies:
+    bluebird "^3.1.1"
+
+constant-case@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/constant-case/-/constant-case-2.0.0.tgz#4175764d389d3fa9c8ecd29186ed6005243b6a46"
+  integrity sha1-QXV2TTidP6nI7NKRhu1gBSQ7akY=
+  dependencies:
+    snake-case "^2.1.0"
+    upper-case "^1.1.1"
+
+constants-browserify@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75"
+  integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=
+
+content-disposition@0.5.3:
+  version "0.5.3"
+  resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd"
+  integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==
+  dependencies:
+    safe-buffer "5.1.2"
+
+content-type@~1.0.4:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b"
+  integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==
+
+convert-source-map@^1.1.0:
+  version "1.6.0"
+  resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.6.0.tgz#51b537a8c43e0f04dec1993bffcdd504e758ac20"
+  integrity sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==
+  dependencies:
+    safe-buffer "~5.1.1"
+
+cookie-signature@1.0.6:
+  version "1.0.6"
+  resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c"
+  integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw=
+
+cookie@0.4.0:
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba"
+  integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==
+
+copy-concurrently@^1.0.0:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0"
+  integrity sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==
+  dependencies:
+    aproba "^1.1.1"
+    fs-write-stream-atomic "^1.0.8"
+    iferr "^0.1.5"
+    mkdirp "^0.5.1"
+    rimraf "^2.5.4"
+    run-queue "^1.0.0"
+
+copy-descriptor@^0.1.0:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d"
+  integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=
+
+core-js-compat@^3.1.1:
+  version "3.1.4"
+  resolved "https://registry.yarnpkg.com/core-js-compat/-/core-js-compat-3.1.4.tgz#e4d0c40fbd01e65b1d457980fe4112d4358a7408"
+  integrity sha512-Z5zbO9f1d0YrJdoaQhphVAnKPimX92D6z8lCGphH89MNRxlL1prI9ExJPqVwP0/kgkQCv8c4GJGT8X16yUncOg==
+  dependencies:
+    browserslist "^4.6.2"
+    core-js-pure "3.1.4"
+    semver "^6.1.1"
+
+core-js-pure@3.1.4:
+  version "3.1.4"
+  resolved "https://registry.yarnpkg.com/core-js-pure/-/core-js-pure-3.1.4.tgz#5fa17dc77002a169a3566cc48dc774d2e13e3769"
+  integrity sha512-uJ4Z7iPNwiu1foygbcZYJsJs1jiXrTTCvxfLDXNhI/I+NHbSIEyr548y4fcsCEyWY0XgfAG/qqaunJ1SThHenA==
+
+core-js@^2.4.0:
+  version "2.6.9"
+  resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.9.tgz#6b4b214620c834152e179323727fc19741b084f2"
+  integrity sha512-HOpZf6eXmnl7la+cUdMnLvUxKNqLUzJvgIziQ0DiF3JwSImNphIqdGqzj6hIKyX04MmV0poclQ7+wjWvxQyR2A==
+
+core-util-is@1.0.2, 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"
+  integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=
+
+create-ecdh@^4.0.0:
+  version "4.0.3"
+  resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.3.tgz#c9111b6f33045c4697f144787f9254cdc77c45ff"
+  integrity sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==
+  dependencies:
+    bn.js "^4.1.0"
+    elliptic "^6.0.0"
+
+create-hash@^1.1.0, create-hash@^1.1.2:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196"
+  integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==
+  dependencies:
+    cipher-base "^1.0.1"
+    inherits "^2.0.1"
+    md5.js "^1.3.4"
+    ripemd160 "^2.0.1"
+    sha.js "^2.4.0"
+
+create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4:
+  version "1.1.7"
+  resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff"
+  integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==
+  dependencies:
+    cipher-base "^1.0.3"
+    create-hash "^1.1.0"
+    inherits "^2.0.1"
+    ripemd160 "^2.0.0"
+    safe-buffer "^5.0.1"
+    sha.js "^2.4.8"
+
+cross-spawn@6.0.5, cross-spawn@^6.0.0, cross-spawn@^6.0.5:
+  version "6.0.5"
+  resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4"
+  integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==
+  dependencies:
+    nice-try "^1.0.4"
+    path-key "^2.0.1"
+    semver "^5.5.0"
+    shebang-command "^1.2.0"
+    which "^1.2.9"
+
+cross-spawn@^3.0.0:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-3.0.1.tgz#1256037ecb9f0c5f79e3d6ef135e30770184b982"
+  integrity sha1-ElYDfsufDF9549bvE14wdwGEuYI=
+  dependencies:
+    lru-cache "^4.0.1"
+    which "^1.2.9"
+
+crypt@~0.0.1:
+  version "0.0.2"
+  resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b"
+  integrity sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=
+
+crypto-browserify@^3.11.0:
+  version "3.12.0"
+  resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec"
+  integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==
+  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"
+    randomfill "^1.0.3"
+
+css-loader@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-3.0.0.tgz#bdd48a4921eefedf1f0a55266585944d4e5efc63"
+  integrity sha512-WR6KZuCkFbnMhRrGPlkwAA7SSCtwqPwpyXJAPhotYkYsc0mKU9n/fu5wufy4jl2WhBw9Ia8gUQMIp/1w98DuPw==
+  dependencies:
+    camelcase "^5.3.1"
+    cssesc "^3.0.0"
+    icss-utils "^4.1.1"
+    loader-utils "^1.2.3"
+    normalize-path "^3.0.0"
+    postcss "^7.0.17"
+    postcss-modules-extract-imports "^2.0.0"
+    postcss-modules-local-by-default "^3.0.2"
+    postcss-modules-scope "^2.1.0"
+    postcss-modules-values "^3.0.0"
+    postcss-value-parser "^4.0.0"
+    schema-utils "^1.0.0"
+
+css-select@^1.1.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/css-select/-/css-select-1.2.0.tgz#2b3a110539c5355f1cd8d314623e870b121ec858"
+  integrity sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=
+  dependencies:
+    boolbase "~1.0.0"
+    css-what "2.1"
+    domutils "1.5.1"
+    nth-check "~1.0.1"
+
+css-what@2.1:
+  version "2.1.3"
+  resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.3.tgz#a6d7604573365fe74686c3f311c56513d88285f2"
+  integrity sha512-a+EPoD+uZiNfh+5fxw2nO9QwFa6nJe2Or35fGY6Ipw1R3R4AGz1d1TEZrCegvw2YTmZ0jXirGYlzxxpYSHwpEg==
+
+cssesc@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-2.0.0.tgz#3b13bd1bb1cb36e1bcb5a4dcd27f54c5dcb35703"
+  integrity sha512-MsCAG1z9lPdoO/IUMLSBWBSVxVtJ1395VGIQ+Fc2gNdkQ1hNDnQdw3YhA71WJCBW1vdwA0cAnk/DnW6bqoEUYg==
+
+cssesc@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee"
+  integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==
+
+currently-unhandled@^0.4.1:
+  version "0.4.1"
+  resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea"
+  integrity sha1-mI3zP+qxke95mmE2nddsF635V+o=
+  dependencies:
+    array-find-index "^1.0.1"
+
+cyclist@~0.2.2:
+  version "0.2.2"
+  resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-0.2.2.tgz#1b33792e11e914a2fd6d6ed6447464444e5fa640"
+  integrity sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA=
+
+dashdash@^1.12.0:
+  version "1.14.1"
+  resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
+  integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=
+  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"
+  integrity sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=
+
+de-indent@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/de-indent/-/de-indent-1.0.2.tgz#b2038e846dc33baa5796128d0804b455b8c1e21d"
+  integrity sha1-sgOOhG3DO6pXlhKNCAS0VbjB4h0=
+
+debug@2.6.9, debug@^2.2.0, debug@^2.3.3:
+  version "2.6.9"
+  resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
+  integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==
+  dependencies:
+    ms "2.0.0"
+
+debug@^3.2.5, debug@^3.2.6:
+  version "3.2.6"
+  resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.6.tgz#e83d17de16d8a7efb7717edbe5fb10135eee629b"
+  integrity sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==
+  dependencies:
+    ms "^2.1.1"
+
+debug@^4.0.1, debug@^4.1.0, debug@^4.1.1:
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/debug/-/debug-4.1.1.tgz#3b72260255109c6b589cee050f1d516139664791"
+  integrity sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==
+  dependencies:
+    ms "^2.1.1"
+
+decamelize@^1.0.0, decamelize@^1.1.1, decamelize@^1.1.2, decamelize@^1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
+  integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=
+
+decode-uri-component@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545"
+  integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=
+
+deep-equal@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/deep-equal/-/deep-equal-1.0.1.tgz#f5d260292b660e084eff4cdbc9f08ad3247448b5"
+  integrity sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=
+
+deep-extend@^0.6.0:
+  version "0.6.0"
+  resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac"
+  integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==
+
+deep-is@~0.1.3:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34"
+  integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=
+
+default-gateway@^4.2.0:
+  version "4.2.0"
+  resolved "https://registry.yarnpkg.com/default-gateway/-/default-gateway-4.2.0.tgz#167104c7500c2115f6dd69b0a536bb8ed720552b"
+  integrity sha512-h6sMrVB1VMWVrW13mSc6ia/DwYYw5MN6+exNu1OaJeFac5aSAvwM7lZ0NVfTABuSkQelr4h5oebg3KB1XPdjgA==
+  dependencies:
+    execa "^1.0.0"
+    ip-regex "^2.1.0"
+
+define-properties@^1.1.2:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1"
+  integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==
+  dependencies:
+    object-keys "^1.0.12"
+
+define-property@^0.2.5:
+  version "0.2.5"
+  resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116"
+  integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=
+  dependencies:
+    is-descriptor "^0.1.0"
+
+define-property@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6"
+  integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY=
+  dependencies:
+    is-descriptor "^1.0.0"
+
+define-property@^2.0.2:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d"
+  integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==
+  dependencies:
+    is-descriptor "^1.0.2"
+    isobject "^3.0.1"
+
+defined@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693"
+  integrity sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=
+
+del@^4.1.1:
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/del/-/del-4.1.1.tgz#9e8f117222ea44a31ff3a156c049b99052a9f0b4"
+  integrity sha512-QwGuEUouP2kVwQenAsOof5Fv8K9t3D8Ca8NxcXKrIpEHjTXK5J2nXLdP+ALI1cgv8wj7KuwBhTwBkOZSJKM5XQ==
+  dependencies:
+    "@types/glob" "^7.1.1"
+    globby "^6.1.0"
+    is-path-cwd "^2.0.0"
+    is-path-in-cwd "^2.0.0"
+    p-map "^2.0.0"
+    pify "^4.0.1"
+    rimraf "^2.6.3"
+
+delayed-stream@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619"
+  integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk=
+
+delegates@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a"
+  integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=
+
+depd@~1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
+  integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=
+
+des.js@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.0.tgz#c074d2e2aa6a8a9a07dbd61f9a15c2cd83ec8ecc"
+  integrity sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=
+  dependencies:
+    inherits "^2.0.1"
+    minimalistic-assert "^1.0.0"
+
+destroy@~1.0.4:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80"
+  integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=
+
+detect-file@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/detect-file/-/detect-file-1.0.0.tgz#f0d66d03672a825cb1b73bdb3fe62310c8e552b7"
+  integrity sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=
+
+detect-libc@^1.0.2:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b"
+  integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=
+
+detect-node@^2.0.4:
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/detect-node/-/detect-node-2.0.4.tgz#014ee8f8f669c5c58023da64b8179c083a28c46c"
+  integrity sha512-ZIzRpLJrOj7jjP2miAtgqIfmzbxa4ZOr5jJc601zklsfEx9oTzmmj2nVpIPRpNlRTIh8lc1kyViIY7BWSGNmKw==
+
+detective@^4.3.1:
+  version "4.7.1"
+  resolved "https://registry.yarnpkg.com/detective/-/detective-4.7.1.tgz#0eca7314338442febb6d65da54c10bb1c82b246e"
+  integrity sha512-H6PmeeUcZloWtdt4DAkFyzFL94arpHr3NOwwmVILFiy+9Qd4JTxxXrzfyGk/lmct2qVGBwTSwSXagqu2BxmWig==
+  dependencies:
+    acorn "^5.2.1"
+    defined "^1.0.0"
+
+diffie-hellman@^5.0.0:
+  version "5.0.3"
+  resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875"
+  integrity sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==
+  dependencies:
+    bn.js "^4.1.0"
+    miller-rabin "^4.0.0"
+    randombytes "^2.0.0"
+
+dns-equal@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/dns-equal/-/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d"
+  integrity sha1-s55/HabrCnW6nBcySzR1PEfgZU0=
+
+dns-packet@^1.3.1:
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-1.3.1.tgz#12aa426981075be500b910eedcd0b47dd7deda5a"
+  integrity sha512-0UxfQkMhYAUaZI+xrNZOz/as5KgDU0M/fQ9b6SpkyLbk3GEswDi6PADJVaYJradtRVsRIlF1zLyOodbcTCDzUg==
+  dependencies:
+    ip "^1.1.0"
+    safe-buffer "^5.0.1"
+
+dns-txt@^2.0.2:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/dns-txt/-/dns-txt-2.0.2.tgz#b91d806f5d27188e4ab3e7d107d881a1cc4642b6"
+  integrity sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY=
+  dependencies:
+    buffer-indexof "^1.0.0"
+
+doctrine@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-3.0.0.tgz#addebead72a6574db783639dc87a121773973961"
+  integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==
+  dependencies:
+    esutils "^2.0.2"
+
+dom-converter@^0.2:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/dom-converter/-/dom-converter-0.2.0.tgz#6721a9daee2e293682955b6afe416771627bb768"
+  integrity sha512-gd3ypIPfOMr9h5jIKq8E3sHOTCjeirnl0WK5ZdS1AW0Odt0b1PaWaHdJ4Qk4klv+YB9aJBS7mESXjFoDQPu6DA==
+  dependencies:
+    utila "~0.4"
+
+dom-serializer@0:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.1.tgz#1ec4059e284babed36eec2941d4a970a189ce7c0"
+  integrity sha512-l0IU0pPzLWSHBcieZbpOKgkIn3ts3vAh7ZuFyXNwJxJXk/c4Gwj9xaTJwIDVQCXawWD0qb3IzMGH5rglQaO0XA==
+  dependencies:
+    domelementtype "^1.3.0"
+    entities "^1.1.1"
+
+domain-browser@^1.1.1:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda"
+  integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==
+
+domelementtype@1, domelementtype@^1.3.0, domelementtype@^1.3.1:
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.1.tgz#d048c44b37b0d10a7f2a3d5fee3f4333d790481f"
+  integrity sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==
+
+domhandler@^2.3.0:
+  version "2.4.2"
+  resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.4.2.tgz#8805097e933d65e85546f726d60f5eb88b44f803"
+  integrity sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==
+  dependencies:
+    domelementtype "1"
+
+domutils@1.5.1:
+  version "1.5.1"
+  resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf"
+  integrity sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=
+  dependencies:
+    dom-serializer "0"
+    domelementtype "1"
+
+domutils@^1.5.1:
+  version "1.7.0"
+  resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.7.0.tgz#56ea341e834e06e6748af7a1cb25da67ea9f8c2a"
+  integrity sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==
+  dependencies:
+    dom-serializer "0"
+    domelementtype "1"
+
+dot-case@^2.1.0:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-2.1.1.tgz#34dcf37f50a8e93c2b3bca8bb7fb9155c7da3bee"
+  integrity sha1-NNzzf1Co6TwrO8qLt/uRVcfaO+4=
+  dependencies:
+    no-case "^2.2.0"
+
+duplexify@^3.4.2, duplexify@^3.6.0:
+  version "3.7.1"
+  resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309"
+  integrity sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==
+  dependencies:
+    end-of-stream "^1.0.0"
+    inherits "^2.0.1"
+    readable-stream "^2.0.0"
+    stream-shift "^1.0.0"
+
+ecc-jsbn@~0.1.1:
+  version "0.1.2"
+  resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9"
+  integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=
+  dependencies:
+    jsbn "~0.1.0"
+    safer-buffer "^2.1.0"
+
+ee-first@1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
+  integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=
+
+electron-to-chromium@^1.3.188:
+  version "1.3.191"
+  resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.191.tgz#c451b422cd8b2eab84dedabab5abcae1eaefb6f0"
+  integrity sha512-jasjtY5RUy/TOyiUYM2fb4BDaPZfm6CXRFeJDMfFsXYADGxUN49RBqtgB7EL2RmJXeIRUk9lM1U6A5yk2YJMPQ==
+
+elliptic@^6.0.0:
+  version "6.5.0"
+  resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.0.tgz#2b8ed4c891b7de3200e14412a5b8248c7af505ca"
+  integrity sha512-eFOJTMyCYb7xtE/caJ6JJu+bhi67WCYNbkGSknu20pmM8Ke/bqOfdnZWxyoGN26JgfxTbXrsCkEw4KheCT/KGg==
+  dependencies:
+    bn.js "^4.4.0"
+    brorand "^1.0.1"
+    hash.js "^1.0.0"
+    hmac-drbg "^1.0.0"
+    inherits "^2.0.1"
+    minimalistic-assert "^1.0.0"
+    minimalistic-crypto-utils "^1.0.0"
+
+emoji-regex@^7.0.1:
+  version "7.0.3"
+  resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156"
+  integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==
+
+emojis-list@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389"
+  integrity sha1-TapNnbAPmBmIDHn6RXrlsJof04k=
+
+encodeurl@~1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59"
+  integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=
+
+encoding@0.1.12:
+  version "0.1.12"
+  resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb"
+  integrity sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=
+  dependencies:
+    iconv-lite "~0.4.13"
+
+end-of-stream@^1.0.0, end-of-stream@^1.1.0:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43"
+  integrity sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==
+  dependencies:
+    once "^1.4.0"
+
+enhanced-resolve@4.1.0, enhanced-resolve@^4.1.0:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.1.0.tgz#41c7e0bfdfe74ac1ffe1e57ad6a5c6c9f3742a7f"
+  integrity sha512-F/7vkyTtyc/llOIn8oWclcB25KdRaiPBpZYDgJHgh/UHtpgT2p2eldQgtQnLtUvfMKPKxbRaQM/hHkvLHt1Vng==
+  dependencies:
+    graceful-fs "^4.1.2"
+    memory-fs "^0.4.0"
+    tapable "^1.0.0"
+
+entities@^1.1.1:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.2.tgz#bdfa735299664dfafd34529ed4f8522a275fea56"
+  integrity sha512-f2LZMYl1Fzu7YSBKg+RoROelpOaNrcGmE9AZubeDfrCEia483oW4MI4VyFd5VNHIgQ/7qm1I0wUHK1eJnn2y2w==
+
+envify@^3.4.0:
+  version "3.4.1"
+  resolved "https://registry.yarnpkg.com/envify/-/envify-3.4.1.tgz#d7122329e8df1688ba771b12501917c9ce5cbce8"
+  integrity sha1-1xIjKejfFoi6dxsSUBkXyc5cvOg=
+  dependencies:
+    jstransform "^11.0.3"
+    through "~2.3.4"
+
+errno@^0.1.3, errno@~0.1.7:
+  version "0.1.7"
+  resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618"
+  integrity sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==
+  dependencies:
+    prr "~1.0.1"
+
+error-ex@^1.2.0:
+  version "1.3.2"
+  resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf"
+  integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==
+  dependencies:
+    is-arrayish "^0.2.1"
+
+es-abstract@^1.5.1:
+  version "1.13.0"
+  resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.13.0.tgz#ac86145fdd5099d8dd49558ccba2eaf9b88e24e9"
+  integrity sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==
+  dependencies:
+    es-to-primitive "^1.2.0"
+    function-bind "^1.1.1"
+    has "^1.0.3"
+    is-callable "^1.1.4"
+    is-regex "^1.0.4"
+    object-keys "^1.0.12"
+
+es-to-primitive@^1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.0.tgz#edf72478033456e8dda8ef09e00ad9650707f377"
+  integrity sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==
+  dependencies:
+    is-callable "^1.1.4"
+    is-date-object "^1.0.1"
+    is-symbol "^1.0.2"
+
+es6-templates@^0.2.2:
+  version "0.2.3"
+  resolved "https://registry.yarnpkg.com/es6-templates/-/es6-templates-0.2.3.tgz#5cb9ac9fb1ded6eb1239342b81d792bbb4078ee4"
+  integrity sha1-XLmsn7He1usSOTQrgdeSu7QHjuQ=
+  dependencies:
+    recast "~0.11.12"
+    through "~2.3.6"
+
+escape-html@~1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988"
+  integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=
+
+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"
+  integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
+
+eslint-loader@^2.2.1:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/eslint-loader/-/eslint-loader-2.2.1.tgz#28b9c12da54057af0845e2a6112701a2f6bf8337"
+  integrity sha512-RLgV9hoCVsMLvOxCuNjdqOrUqIj9oJg8hF44vzJaYqsAHuY9G2YAeN3joQ9nxP0p5Th9iFSIpKo+SD8KISxXRg==
+  dependencies:
+    loader-fs-cache "^1.0.0"
+    loader-utils "^1.0.2"
+    object-assign "^4.0.1"
+    object-hash "^1.1.4"
+    rimraf "^2.6.1"
+
+eslint-plugin-html@^6.0.0:
+  version "6.0.0"
+  resolved "https://registry.yarnpkg.com/eslint-plugin-html/-/eslint-plugin-html-6.0.0.tgz#28e5c3e71e6f612e07e73d7c215e469766628c13"
+  integrity sha512-PQcGippOHS+HTbQCStmH5MY1BF2MaU8qW/+Mvo/8xTa/ioeMXdSP+IiaBw2+nh0KEMfYQKuTz1Zo+vHynjwhbg==
+  dependencies:
+    htmlparser2 "^3.10.1"
+
+eslint-scope@^4.0.0, eslint-scope@^4.0.3:
+  version "4.0.3"
+  resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848"
+  integrity sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==
+  dependencies:
+    esrecurse "^4.1.0"
+    estraverse "^4.1.1"
+
+eslint-utils@^1.3.1:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-1.4.0.tgz#e2c3c8dba768425f897cf0f9e51fe2e241485d4c"
+  integrity sha512-7ehnzPaP5IIEh1r1tkjuIrxqhNkzUJa9z3R92tLJdZIVdWaczEhr3EbhGtsMrVxi1KeR8qA7Off6SWc5WNQqyQ==
+  dependencies:
+    eslint-visitor-keys "^1.0.0"
+
+eslint-visitor-keys@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-1.0.0.tgz#3f3180fb2e291017716acb4c9d6d5b5c34a6a81d"
+  integrity sha512-qzm/XxIbxm/FHyH341ZrbnMUpe+5Bocte9xkmFMzPMjRaZMcXww+MpBptFvtU+79L362nqiLhekCxCxDPaUMBQ==
+
+eslint@^6.0.1:
+  version "6.0.1"
+  resolved "https://registry.yarnpkg.com/eslint/-/eslint-6.0.1.tgz#4a32181d72cb999d6f54151df7d337131f81cda7"
+  integrity sha512-DyQRaMmORQ+JsWShYsSg4OPTjY56u1nCjAmICrE8vLWqyLKxhFXOthwMj1SA8xwfrv0CofLNVnqbfyhwCkaO0w==
+  dependencies:
+    "@babel/code-frame" "^7.0.0"
+    ajv "^6.10.0"
+    chalk "^2.1.0"
+    cross-spawn "^6.0.5"
+    debug "^4.0.1"
+    doctrine "^3.0.0"
+    eslint-scope "^4.0.3"
+    eslint-utils "^1.3.1"
+    eslint-visitor-keys "^1.0.0"
+    espree "^6.0.0"
+    esquery "^1.0.1"
+    esutils "^2.0.2"
+    file-entry-cache "^5.0.1"
+    functional-red-black-tree "^1.0.1"
+    glob-parent "^3.1.0"
+    globals "^11.7.0"
+    ignore "^4.0.6"
+    import-fresh "^3.0.0"
+    imurmurhash "^0.1.4"
+    inquirer "^6.2.2"
+    is-glob "^4.0.0"
+    js-yaml "^3.13.1"
+    json-stable-stringify-without-jsonify "^1.0.1"
+    levn "^0.3.0"
+    lodash "^4.17.11"
+    minimatch "^3.0.4"
+    mkdirp "^0.5.1"
+    natural-compare "^1.4.0"
+    optionator "^0.8.2"
+    progress "^2.0.0"
+    regexpp "^2.0.1"
+    semver "^5.5.1"
+    strip-ansi "^4.0.0"
+    strip-json-comments "^2.0.1"
+    table "^5.2.3"
+    text-table "^0.2.0"
+
+espree@^6.0.0:
+  version "6.0.0"
+  resolved "https://registry.yarnpkg.com/espree/-/espree-6.0.0.tgz#716fc1f5a245ef5b9a7fdb1d7b0d3f02322e75f6"
+  integrity sha512-lJvCS6YbCn3ImT3yKkPe0+tJ+mH6ljhGNjHQH9mRtiO6gjhVAOhVXW1yjnwqGwTkK3bGbye+hb00nFNmu0l/1Q==
+  dependencies:
+    acorn "^6.0.7"
+    acorn-jsx "^5.0.0"
+    eslint-visitor-keys "^1.0.0"
+
+esprima-fb@^15001.1.0-dev-harmony-fb:
+  version "15001.1.0-dev-harmony-fb"
+  resolved "https://registry.yarnpkg.com/esprima-fb/-/esprima-fb-15001.1.0-dev-harmony-fb.tgz#30a947303c6b8d5e955bee2b99b1d233206a6901"
+  integrity sha1-MKlHMDxrjV6VW+4rmbHSMyBqaQE=
+
+esprima@^4.0.0:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
+  integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
+
+esprima@~3.1.0:
+  version "3.1.3"
+  resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633"
+  integrity sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=
+
+esquery@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.1.tgz#406c51658b1f5991a5f9b62b1dc25b00e3e5c708"
+  integrity sha512-SmiyZ5zIWH9VM+SRUReLS5Q8a7GxtRdxEBVZpm98rJM7Sb+A9DVCndXfkeFUd3byderg+EbDkfnevfCwynWaNA==
+  dependencies:
+    estraverse "^4.0.0"
+
+esrecurse@^4.1.0:
+  version "4.2.1"
+  resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf"
+  integrity sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==
+  dependencies:
+    estraverse "^4.1.0"
+
+estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1:
+  version "4.2.0"
+  resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13"
+  integrity sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=
+
+esutils@^2.0.2:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b"
+  integrity sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=
+
+etag@~1.8.1:
+  version "1.8.1"
+  resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
+  integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=
+
+eventemitter3@^3.0.0:
+  version "3.1.2"
+  resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.2.tgz#2d3d48f9c346698fce83a85d7d664e98535df6e7"
+  integrity sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q==
+
+events@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/events/-/events-3.0.0.tgz#9a0a0dfaf62893d92b875b8f2698ca4114973e88"
+  integrity sha512-Dc381HFWJzEOhQ+d8pkNon++bk9h6cdAoAj4iE6Q4y6xgTzySWXlKn05/TVNpjnfRqi/X0EpJEJohPjNI3zpVA==
+
+eventsource@^1.0.7:
+  version "1.0.7"
+  resolved "https://registry.yarnpkg.com/eventsource/-/eventsource-1.0.7.tgz#8fbc72c93fcd34088090bc0a4e64f4b5cee6d8d0"
+  integrity sha512-4Ln17+vVT0k8aWq+t/bF5arcS3EpT9gYtW66EPacdj/mAFevznsnyoHLPy2BA8gbIQeIHoPsvwmfBftfcG//BQ==
+  dependencies:
+    original "^1.0.0"
+
+evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02"
+  integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==
+  dependencies:
+    md5.js "^1.3.4"
+    safe-buffer "^5.1.1"
+
+execa@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8"
+  integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==
+  dependencies:
+    cross-spawn "^6.0.0"
+    get-stream "^4.0.0"
+    is-stream "^1.1.0"
+    npm-run-path "^2.0.0"
+    p-finally "^1.0.0"
+    signal-exit "^3.0.0"
+    strip-eof "^1.0.0"
+
+expand-brackets@^2.1.4:
+  version "2.1.4"
+  resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622"
+  integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI=
+  dependencies:
+    debug "^2.3.3"
+    define-property "^0.2.5"
+    extend-shallow "^2.0.1"
+    posix-character-classes "^0.1.0"
+    regex-not "^1.0.0"
+    snapdragon "^0.8.1"
+    to-regex "^3.0.1"
+
+expand-tilde@^2.0.0, expand-tilde@^2.0.2:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/expand-tilde/-/expand-tilde-2.0.2.tgz#97e801aa052df02454de46b02bf621642cdc8502"
+  integrity sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=
+  dependencies:
+    homedir-polyfill "^1.0.1"
+
+express@^4.17.1:
+  version "4.17.1"
+  resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134"
+  integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==
+  dependencies:
+    accepts "~1.3.7"
+    array-flatten "1.1.1"
+    body-parser "1.19.0"
+    content-disposition "0.5.3"
+    content-type "~1.0.4"
+    cookie "0.4.0"
+    cookie-signature "1.0.6"
+    debug "2.6.9"
+    depd "~1.1.2"
+    encodeurl "~1.0.2"
+    escape-html "~1.0.3"
+    etag "~1.8.1"
+    finalhandler "~1.1.2"
+    fresh "0.5.2"
+    merge-descriptors "1.0.1"
+    methods "~1.1.2"
+    on-finished "~2.3.0"
+    parseurl "~1.3.3"
+    path-to-regexp "0.1.7"
+    proxy-addr "~2.0.5"
+    qs "6.7.0"
+    range-parser "~1.2.1"
+    safe-buffer "5.1.2"
+    send "0.17.1"
+    serve-static "1.14.1"
+    setprototypeof "1.1.1"
+    statuses "~1.5.0"
+    type-is "~1.6.18"
+    utils-merge "1.0.1"
+    vary "~1.1.2"
+
+extend-shallow@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f"
+  integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=
+  dependencies:
+    is-extendable "^0.1.0"
+
+extend-shallow@^3.0.0, extend-shallow@^3.0.2:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8"
+  integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=
+  dependencies:
+    assign-symbols "^1.0.0"
+    is-extendable "^1.0.1"
+
+extend@~3.0.2:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
+  integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
+
+external-editor@^3.0.3:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495"
+  integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==
+  dependencies:
+    chardet "^0.7.0"
+    iconv-lite "^0.4.24"
+    tmp "^0.0.33"
+
+extglob@^2.0.4:
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543"
+  integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==
+  dependencies:
+    array-unique "^0.3.2"
+    define-property "^1.0.0"
+    expand-brackets "^2.1.4"
+    extend-shallow "^2.0.1"
+    fragment-cache "^0.2.1"
+    regex-not "^1.0.0"
+    snapdragon "^0.8.1"
+    to-regex "^3.0.1"
+
+extsprintf@1.3.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05"
+  integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=
+
+extsprintf@^1.2.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f"
+  integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8=
+
+fast-deep-equal@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49"
+  integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=
+
+fast-json-stable-stringify@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2"
+  integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I=
+
+fast-levenshtein@~2.0.4:
+  version "2.0.6"
+  resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917"
+  integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=
+
+fastparse@^1.0.0:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.2.tgz#91728c5a5942eced8531283c79441ee4122c35a9"
+  integrity sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==
+
+faye-websocket@^0.10.0:
+  version "0.10.0"
+  resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4"
+  integrity sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=
+  dependencies:
+    websocket-driver ">=0.5.1"
+
+faye-websocket@~0.11.1:
+  version "0.11.3"
+  resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.11.3.tgz#5c0e9a8968e8912c286639fde977a8b209f2508e"
+  integrity sha512-D2y4bovYpzziGgbHYtGCMjlJM36vAl/y+xUyn1C+FVx8szd1E+86KwVw6XvYSzOP8iMpm1X0I4xJD+QtUb36OA==
+  dependencies:
+    websocket-driver ">=0.5.1"
+
+fetch@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/fetch/-/fetch-1.1.0.tgz#0a8279f06be37f9f0ebb567560a30a480da59a2e"
+  integrity sha1-CoJ58Gvjf58Ou1Z1YKMKSA2lmi4=
+  dependencies:
+    biskviit "1.0.1"
+    encoding "0.1.12"
+
+figgy-pudding@^3.5.1:
+  version "3.5.1"
+  resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.1.tgz#862470112901c727a0e495a80744bd5baa1d6790"
+  integrity sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w==
+
+figures@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962"
+  integrity sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI=
+  dependencies:
+    escape-string-regexp "^1.0.5"
+
+file-entry-cache@^5.0.1:
+  version "5.0.1"
+  resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-5.0.1.tgz#ca0f6efa6dd3d561333fb14515065c2fafdf439c"
+  integrity sha512-bCg29ictuBaKUwwArK4ouCaqDgLZcysCFLmM/Yn/FDoqndh/9vNuQfXRDvTuXKLxfD/JtZQGKFT8MGcJBK644g==
+  dependencies:
+    flat-cache "^2.0.1"
+
+fill-range@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7"
+  integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=
+  dependencies:
+    extend-shallow "^2.0.1"
+    is-number "^3.0.0"
+    repeat-string "^1.6.1"
+    to-regex-range "^2.1.0"
+
+finalhandler@~1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d"
+  integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==
+  dependencies:
+    debug "2.6.9"
+    encodeurl "~1.0.2"
+    escape-html "~1.0.3"
+    on-finished "~2.3.0"
+    parseurl "~1.3.3"
+    statuses "~1.5.0"
+    unpipe "~1.0.0"
+
+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"
+  integrity sha1-yN765XyKUqinhPnjHFfHQumToLk=
+  dependencies:
+    commondir "^1.0.1"
+    mkdirp "^0.5.1"
+    pkg-dir "^1.0.0"
+
+find-cache-dir@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-2.1.0.tgz#8d0f94cd13fe43c6c7c261a0d86115ca918c05f7"
+  integrity sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==
+  dependencies:
+    commondir "^1.0.1"
+    make-dir "^2.0.0"
+    pkg-dir "^3.0.0"
+
+find-up@^1.0.0:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f"
+  integrity sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=
+  dependencies:
+    path-exists "^2.0.0"
+    pinkie-promise "^2.0.0"
+
+find-up@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73"
+  integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==
+  dependencies:
+    locate-path "^3.0.0"
+
+findup-sync@3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-3.0.0.tgz#17b108f9ee512dfb7a5c7f3c8b27ea9e1a9c08d1"
+  integrity sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==
+  dependencies:
+    detect-file "^1.0.0"
+    is-glob "^4.0.0"
+    micromatch "^3.0.4"
+    resolve-dir "^1.0.1"
+
+flat-cache@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-2.0.1.tgz#5d296d6f04bda44a4630a301413bdbc2ec085ec0"
+  integrity sha512-LoQe6yDuUMDzQAEH8sgmh4Md6oZnc/7PjtwjNFSzveXqSHt6ka9fPBuso7IGf9Rz4uqnSnWiFH2B/zj24a5ReA==
+  dependencies:
+    flatted "^2.0.0"
+    rimraf "2.6.3"
+    write "1.0.3"
+
+flatted@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/flatted/-/flatted-2.0.1.tgz#69e57caa8f0eacbc281d2e2cb458d46fdb449e08"
+  integrity sha512-a1hQMktqW9Nmqr5aktAux3JMNqaucxGcjtjWnZLHX7yyPCmlSV3M54nGYbqT8K+0GhF3NBgmJCc3ma+WOgX8Jg==
+
+flush-write-stream@^1.0.0:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.1.1.tgz#8dd7d873a1babc207d94ead0c2e0e44276ebf2e8"
+  integrity sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w==
+  dependencies:
+    inherits "^2.0.3"
+    readable-stream "^2.3.6"
+
+follow-redirects@^1.0.0:
+  version "1.7.0"
+  resolved "https://registry.yarnpkg.com/follow-redirects/-/follow-redirects-1.7.0.tgz#489ebc198dc0e7f64167bd23b03c4c19b5784c76"
+  integrity sha512-m/pZQy4Gj287eNy94nivy5wchN3Kp+Q5WgUPNy5lJSZ3sgkVKSYV/ZChMAQVIgx1SqfZ2zBZtPA2YlXIWxxJOQ==
+  dependencies:
+    debug "^3.2.6"
+
+for-in@^0.1.3:
+  version "0.1.8"
+  resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.8.tgz#d8773908e31256109952b1fdb9b3fa867d2775e1"
+  integrity sha1-2Hc5COMSVhCZUrH9ubP6hn0ndeE=
+
+for-in@^1.0.1, for-in@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80"
+  integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=
+
+for-own@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/for-own/-/for-own-1.0.0.tgz#c63332f415cedc4b04dbfe70cf836494c53cb44b"
+  integrity sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=
+  dependencies:
+    for-in "^1.0.1"
+
+forever-agent@~0.6.1:
+  version "0.6.1"
+  resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
+  integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=
+
+form-data@~2.3.2:
+  version "2.3.3"
+  resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6"
+  integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==
+  dependencies:
+    asynckit "^0.4.0"
+    combined-stream "^1.0.6"
+    mime-types "^2.1.12"
+
+forwarded@~0.1.2:
+  version "0.1.2"
+  resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84"
+  integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=
+
+fragment-cache@^0.2.1:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19"
+  integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=
+  dependencies:
+    map-cache "^0.2.2"
+
+fresh@0.5.2:
+  version "0.5.2"
+  resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7"
+  integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=
+
+from2@^2.1.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af"
+  integrity sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=
+  dependencies:
+    inherits "^2.0.1"
+    readable-stream "^2.0.0"
+
+fs-minipass@^1.2.5:
+  version "1.2.6"
+  resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.6.tgz#2c5cc30ded81282bfe8a0d7c7c1853ddeb102c07"
+  integrity sha512-crhvyXcMejjv3Z5d2Fa9sf5xLYVCF5O1c71QxbVnbLsmYMBEvDAftewesN/HhY03YRoA7zOMxjNGrF5svGaaeQ==
+  dependencies:
+    minipass "^2.2.1"
+
+fs-write-stream-atomic@^1.0.8:
+  version "1.0.10"
+  resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9"
+  integrity sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=
+  dependencies:
+    graceful-fs "^4.1.2"
+    iferr "^0.1.5"
+    imurmurhash "^0.1.4"
+    readable-stream "1 || 2"
+
+fs.realpath@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f"
+  integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8=
+
+fsevents@^1.2.7:
+  version "1.2.9"
+  resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.9.tgz#3f5ed66583ccd6f400b5a00db6f7e861363e388f"
+  integrity sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==
+  dependencies:
+    nan "^2.12.1"
+    node-pre-gyp "^0.12.0"
+
+fstream@^1.0.0, fstream@^1.0.12:
+  version "1.0.12"
+  resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.12.tgz#4e8ba8ee2d48be4f7d0de505455548eae5932045"
+  integrity sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==
+  dependencies:
+    graceful-fs "^4.1.2"
+    inherits "~2.0.0"
+    mkdirp ">=0.5 0"
+    rimraf "2"
+
+function-bind@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
+  integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
+
+functional-red-black-tree@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327"
+  integrity sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=
+
+gauge@~2.7.3:
+  version "2.7.4"
+  resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7"
+  integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=
+  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"
+    wide-align "^1.1.0"
+
+gaze@^1.0.0:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/gaze/-/gaze-1.1.3.tgz#c441733e13b927ac8c0ff0b4c3b033f28812924a"
+  integrity sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==
+  dependencies:
+    globule "^1.0.0"
+
+get-caller-file@^1.0.1:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a"
+  integrity sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==
+
+get-caller-file@^2.0.1:
+  version "2.0.5"
+  resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e"
+  integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==
+
+get-stdin@^4.0.1:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe"
+  integrity sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=
+
+get-stream@^4.0.0:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5"
+  integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==
+  dependencies:
+    pump "^3.0.0"
+
+get-value@^2.0.3, get-value@^2.0.6:
+  version "2.0.6"
+  resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28"
+  integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=
+
+getpass@^0.1.1:
+  version "0.1.7"
+  resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa"
+  integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=
+  dependencies:
+    assert-plus "^1.0.0"
+
+glob-parent@^3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae"
+  integrity sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=
+  dependencies:
+    is-glob "^3.1.0"
+    path-dirname "^1.0.0"
+
+glob@^5.0.15:
+  version "5.0.15"
+  resolved "https://registry.yarnpkg.com/glob/-/glob-5.0.15.tgz#1bc936b9e02f4a603fcc222ecf7633d30b8b93b1"
+  integrity sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=
+  dependencies:
+    inflight "^1.0.4"
+    inherits "2"
+    minimatch "2 || 3"
+    once "^1.3.0"
+    path-is-absolute "^1.0.0"
+
+glob@^7.0.0, glob@^7.0.3, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@~7.1.1:
+  version "7.1.4"
+  resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.4.tgz#aa608a2f6c577ad357e1ae5a5c26d9a8d1969255"
+  integrity sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==
+  dependencies:
+    fs.realpath "^1.0.0"
+    inflight "^1.0.4"
+    inherits "2"
+    minimatch "^3.0.4"
+    once "^1.3.0"
+    path-is-absolute "^1.0.0"
+
+global-modules@2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-2.0.0.tgz#997605ad2345f27f51539bea26574421215c7780"
+  integrity sha512-NGbfmJBp9x8IxyJSd1P+otYK8vonoJactOogrVfFRIAEY1ukil8RSKDz2Yo7wh1oihl51l/r6W4epkeKJHqL8A==
+  dependencies:
+    global-prefix "^3.0.0"
+
+global-modules@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/global-modules/-/global-modules-1.0.0.tgz#6d770f0eb523ac78164d72b5e71a8877265cc3ea"
+  integrity sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==
+  dependencies:
+    global-prefix "^1.0.1"
+    is-windows "^1.0.1"
+    resolve-dir "^1.0.0"
+
+global-prefix@^1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-1.0.2.tgz#dbf743c6c14992593c655568cb66ed32c0122ebe"
+  integrity sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=
+  dependencies:
+    expand-tilde "^2.0.2"
+    homedir-polyfill "^1.0.1"
+    ini "^1.3.4"
+    is-windows "^1.0.1"
+    which "^1.2.14"
+
+global-prefix@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/global-prefix/-/global-prefix-3.0.0.tgz#fc85f73064df69f50421f47f883fe5b913ba9b97"
+  integrity sha512-awConJSVCHVGND6x3tmMaKcQvwXLhjdkmomy2W+Goaui8YPgYgXJZewhg3fWC+DlfqqQuWg8AwqjGTD2nAPVWg==
+  dependencies:
+    ini "^1.3.5"
+    kind-of "^6.0.2"
+    which "^1.3.1"
+
+globals@^11.1.0, globals@^11.7.0:
+  version "11.12.0"
+  resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
+  integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==
+
+globby@^6.1.0:
+  version "6.1.0"
+  resolved "https://registry.yarnpkg.com/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c"
+  integrity sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=
+  dependencies:
+    array-union "^1.0.1"
+    glob "^7.0.3"
+    object-assign "^4.0.1"
+    pify "^2.0.0"
+    pinkie-promise "^2.0.0"
+
+globule@^1.0.0:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/globule/-/globule-1.2.1.tgz#5dffb1b191f22d20797a9369b49eab4e9839696d"
+  integrity sha512-g7QtgWF4uYSL5/dn71WxubOrS7JVGCnFPEnoeChJmBnyR9Mw8nGoEwOgJL/RC2Te0WhbsEUCejfH8SZNJ+adYQ==
+  dependencies:
+    glob "~7.1.1"
+    lodash "~4.17.10"
+    minimatch "~3.0.2"
+
+graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2:
+  version "4.2.0"
+  resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.0.tgz#8d8fdc73977cb04104721cb53666c1ca64cd328b"
+  integrity sha512-jpSvDPV4Cq/bgtpndIWbI5hmYxhQGHPC4d4cqBPb4DLniCfhJokdXhwhaDuLBGLQdvvRum/UiX6ECVIPvDXqdg==
+
+"graceful-readlink@>= 1.0.0":
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725"
+  integrity sha1-TK+tdrxi8C+gObL5Tpo906ORpyU=
+
+handle-thing@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-2.0.0.tgz#0e039695ff50c93fc288557d696f3c1dc6776754"
+  integrity sha512-d4sze1JNC454Wdo2fkuyzCr6aHcbL6PGGuFAz0Li/NcOm1tCHGnWDRmJP85dh9IhQErTc2svWFEX5xHIOo//kQ==
+
+har-schema@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92"
+  integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=
+
+har-validator@~5.1.0:
+  version "5.1.3"
+  resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080"
+  integrity sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==
+  dependencies:
+    ajv "^6.5.5"
+    har-schema "^2.0.0"
+
+has-ansi@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91"
+  integrity sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=
+  dependencies:
+    ansi-regex "^2.0.0"
+
+has-flag@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd"
+  integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0=
+
+has-symbols@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44"
+  integrity sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=
+
+has-unicode@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9"
+  integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=
+
+has-value@^0.3.1:
+  version "0.3.1"
+  resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f"
+  integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=
+  dependencies:
+    get-value "^2.0.3"
+    has-values "^0.1.4"
+    isobject "^2.0.0"
+
+has-value@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177"
+  integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=
+  dependencies:
+    get-value "^2.0.6"
+    has-values "^1.0.0"
+    isobject "^3.0.0"
+
+has-values@^0.1.4:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771"
+  integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E=
+
+has-values@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f"
+  integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=
+  dependencies:
+    is-number "^3.0.0"
+    kind-of "^4.0.0"
+
+has@^1.0.1, has@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796"
+  integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==
+  dependencies:
+    function-bind "^1.1.1"
+
+hash-base@^3.0.0:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.0.4.tgz#5fc8686847ecd73499403319a6b0a3f3f6ae4918"
+  integrity sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=
+  dependencies:
+    inherits "^2.0.1"
+    safe-buffer "^5.0.1"
+
+hash-sum@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/hash-sum/-/hash-sum-1.0.2.tgz#33b40777754c6432573c120cc3808bbd10d47f04"
+  integrity sha1-M7QHd3VMZDJXPBIMw4CLvRDUfwQ=
+
+hash.js@^1.0.0, hash.js@^1.0.3:
+  version "1.1.7"
+  resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42"
+  integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==
+  dependencies:
+    inherits "^2.0.3"
+    minimalistic-assert "^1.0.1"
+
+he@1.1.x:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd"
+  integrity sha1-k0EP0hsAlzUVH4howvJx80J+I/0=
+
+he@1.2.x, he@^1.1.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f"
+  integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==
+
+header-case@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/header-case/-/header-case-1.0.1.tgz#9535973197c144b09613cd65d317ef19963bd02d"
+  integrity sha1-lTWXMZfBRLCWE81l0xfvGZY70C0=
+  dependencies:
+    no-case "^2.2.0"
+    upper-case "^1.1.3"
+
+hmac-drbg@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1"
+  integrity sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=
+  dependencies:
+    hash.js "^1.0.3"
+    minimalistic-assert "^1.0.0"
+    minimalistic-crypto-utils "^1.0.1"
+
+homedir-polyfill@^1.0.1:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz#743298cef4e5af3e194161fbadcc2151d3a058e8"
+  integrity sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==
+  dependencies:
+    parse-passwd "^1.0.0"
+
+hosted-git-info@^2.1.4:
+  version "2.7.1"
+  resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.7.1.tgz#97f236977bd6e125408930ff6de3eec6281ec047"
+  integrity sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==
+
+hpack.js@^2.1.6:
+  version "2.1.6"
+  resolved "https://registry.yarnpkg.com/hpack.js/-/hpack.js-2.1.6.tgz#87774c0949e513f42e84575b3c45681fade2a0b2"
+  integrity sha1-h3dMCUnlE/QuhFdbPEVoH63ioLI=
+  dependencies:
+    inherits "^2.0.1"
+    obuf "^1.0.0"
+    readable-stream "^2.0.1"
+    wbuf "^1.1.0"
+
+html-entities@^1.2.1:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.2.1.tgz#0df29351f0721163515dfb9e5543e5f6eed5162f"
+  integrity sha1-DfKTUfByEWNRXfueVUPl9u7VFi8=
+
+html-minifier@^2.1.5:
+  version "2.1.7"
+  resolved "https://registry.yarnpkg.com/html-minifier/-/html-minifier-2.1.7.tgz#9051d6fcbbcf214ed307e1ad74f432bb9ad655cc"
+  integrity sha1-kFHW/LvPIU7TB+GtdPQyu5rWVcw=
+  dependencies:
+    change-case "3.0.x"
+    clean-css "3.4.x"
+    commander "2.9.x"
+    he "1.1.x"
+    ncname "1.0.x"
+    relateurl "0.2.x"
+    uglify-js "2.6.x"
+
+html-minifier@^3.2.3:
+  version "3.5.21"
+  resolved "https://registry.yarnpkg.com/html-minifier/-/html-minifier-3.5.21.tgz#d0040e054730e354db008463593194015212d20c"
+  integrity sha512-LKUKwuJDhxNa3uf/LPR/KVjm/l3rBqtYeCOAekvG8F1vItxMUpueGd94i/asDDr8/1u7InxzFA5EeGjhhG5mMA==
+  dependencies:
+    camel-case "3.0.x"
+    clean-css "4.2.x"
+    commander "2.17.x"
+    he "1.2.x"
+    param-case "2.1.x"
+    relateurl "0.2.x"
+    uglify-js "3.4.x"
+
+html-webpack-plugin@^3.2.0:
+  version "3.2.0"
+  resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-3.2.0.tgz#b01abbd723acaaa7b37b6af4492ebda03d9dd37b"
+  integrity sha1-sBq71yOsqqeze2r0SS69oD2d03s=
+  dependencies:
+    html-minifier "^3.2.3"
+    loader-utils "^0.2.16"
+    lodash "^4.17.3"
+    pretty-error "^2.0.2"
+    tapable "^1.0.0"
+    toposort "^1.0.0"
+    util.promisify "1.0.0"
+
+htmlparser2@^3.10.1, htmlparser2@^3.3.0:
+  version "3.10.1"
+  resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.10.1.tgz#bd679dc3f59897b6a34bb10749c855bb53a9392f"
+  integrity sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==
+  dependencies:
+    domelementtype "^1.3.1"
+    domhandler "^2.3.0"
+    domutils "^1.5.1"
+    entities "^1.1.1"
+    inherits "^2.0.1"
+    readable-stream "^3.1.1"
+
+http-deceiver@^1.2.7:
+  version "1.2.7"
+  resolved "https://registry.yarnpkg.com/http-deceiver/-/http-deceiver-1.2.7.tgz#fa7168944ab9a519d337cb0bec7284dc3e723d87"
+  integrity sha1-+nFolEq5pRnTN8sL7HKE3D5yPYc=
+
+http-errors@1.7.2:
+  version "1.7.2"
+  resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f"
+  integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg==
+  dependencies:
+    depd "~1.1.2"
+    inherits "2.0.3"
+    setprototypeof "1.1.1"
+    statuses ">= 1.5.0 < 2"
+    toidentifier "1.0.0"
+
+http-errors@~1.6.2:
+  version "1.6.3"
+  resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.3.tgz#8b55680bb4be283a0b5bf4ea2e38580be1d9320d"
+  integrity sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=
+  dependencies:
+    depd "~1.1.2"
+    inherits "2.0.3"
+    setprototypeof "1.1.0"
+    statuses ">= 1.4.0 < 2"
+
+http-errors@~1.7.2:
+  version "1.7.3"
+  resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06"
+  integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==
+  dependencies:
+    depd "~1.1.2"
+    inherits "2.0.4"
+    setprototypeof "1.1.1"
+    statuses ">= 1.5.0 < 2"
+    toidentifier "1.0.0"
+
+"http-parser-js@>=0.4.0 <0.4.11":
+  version "0.4.10"
+  resolved "https://registry.yarnpkg.com/http-parser-js/-/http-parser-js-0.4.10.tgz#92c9c1374c35085f75db359ec56cc257cbb93fa4"
+  integrity sha1-ksnBN0w1CF912zWexWzCV8u5P6Q=
+
+http-proxy-middleware@^0.19.1:
+  version "0.19.1"
+  resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-0.19.1.tgz#183c7dc4aa1479150306498c210cdaf96080a43a"
+  integrity sha512-yHYTgWMQO8VvwNS22eLLloAkvungsKdKTLO8AJlftYIKNfJr3GK3zK0ZCfzDDGUBttdGc8xFy1mCitvNKQtC3Q==
+  dependencies:
+    http-proxy "^1.17.0"
+    is-glob "^4.0.0"
+    lodash "^4.17.11"
+    micromatch "^3.1.10"
+
+http-proxy@^1.17.0:
+  version "1.17.0"
+  resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.17.0.tgz#7ad38494658f84605e2f6db4436df410f4e5be9a"
+  integrity sha512-Taqn+3nNvYRfJ3bGvKfBSRwy1v6eePlm3oc/aWVxZp57DQr5Eq3xhKJi7Z4hZpS8PC3H4qI+Yly5EmFacGuA/g==
+  dependencies:
+    eventemitter3 "^3.0.0"
+    follow-redirects "^1.0.0"
+    requires-port "^1.0.0"
+
+http-signature@~1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1"
+  integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=
+  dependencies:
+    assert-plus "^1.0.0"
+    jsprim "^1.2.2"
+    sshpk "^1.7.0"
+
+https-browserify@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73"
+  integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=
+
+iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4, iconv-lite@^0.4.5, iconv-lite@~0.4.13:
+  version "0.4.24"
+  resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
+  integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
+  dependencies:
+    safer-buffer ">= 2.1.2 < 3"
+
+icss-utils@^4.0.0, icss-utils@^4.1.1:
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-4.1.1.tgz#21170b53789ee27447c2f47dd683081403f9a467"
+  integrity sha512-4aFq7wvWyMHKgxsH8QQtGpvbASCf+eM3wPRLI6R+MgAnTCZ6STYsRvttLvRWK0Nfif5piF394St3HeJDaljGPA==
+  dependencies:
+    postcss "^7.0.14"
+
+ieee754@^1.1.4:
+  version "1.1.13"
+  resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.13.tgz#ec168558e95aa181fd87d37f55c32bbcb6708b84"
+  integrity sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==
+
+iferr@^0.1.5:
+  version "0.1.5"
+  resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501"
+  integrity sha1-xg7taebY/bazEEofy8ocGS3FtQE=
+
+ignore-walk@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/ignore-walk/-/ignore-walk-3.0.1.tgz#a83e62e7d272ac0e3b551aaa82831a19b69f82f8"
+  integrity sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==
+  dependencies:
+    minimatch "^3.0.4"
+
+ignore@^4.0.6:
+  version "4.0.6"
+  resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc"
+  integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==
+
+import-fresh@^3.0.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.1.0.tgz#6d33fa1dcef6df930fae003446f33415af905118"
+  integrity sha512-PpuksHKGt8rXfWEr9m9EHIpgyyaltBy8+eF6GJM0QCAxMgxCfucMF3mjecK2QsJr0amJW7gTqh5/wht0z2UhEQ==
+  dependencies:
+    parent-module "^1.0.0"
+    resolve-from "^4.0.0"
+
+import-local@2.0.0, import-local@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/import-local/-/import-local-2.0.0.tgz#55070be38a5993cf18ef6db7e961f5bee5c5a09d"
+  integrity sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==
+  dependencies:
+    pkg-dir "^3.0.0"
+    resolve-cwd "^2.0.0"
+
+imurmurhash@^0.1.4:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"
+  integrity sha1-khi5srkoojixPcT7a21XbyMUU+o=
+
+in-publish@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/in-publish/-/in-publish-2.0.0.tgz#e20ff5e3a2afc2690320b6dc552682a9c7fadf51"
+  integrity sha1-4g/146KvwmkDILbcVSaCqcf631E=
+
+indent-string@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80"
+  integrity sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=
+  dependencies:
+    repeating "^2.0.0"
+
+indexes-of@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607"
+  integrity sha1-8w9xbI4r00bHtn0985FVZqfAVgc=
+
+inflight@^1.0.4:
+  version "1.0.6"
+  resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9"
+  integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=
+  dependencies:
+    once "^1.3.0"
+    wrappy "1"
+
+inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1, inherits@~2.0.3:
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
+  integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
+
+inherits@2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1"
+  integrity sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=
+
+inherits@2.0.3:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
+  integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
+
+ini@^1.3.4, ini@^1.3.5, ini@~1.3.0:
+  version "1.3.5"
+  resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.5.tgz#eee25f56db1c9ec6085e0c22778083f596abf927"
+  integrity sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==
+
+inquirer@^6.2.2:
+  version "6.5.0"
+  resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.5.0.tgz#2303317efc9a4ea7ec2e2df6f86569b734accf42"
+  integrity sha512-scfHejeG/lVZSpvCXpsB4j/wQNPM5JC8kiElOI0OUTwmc1RTpXr4H32/HOlQHcZiYl2z2VElwuCVDRG8vFmbnA==
+  dependencies:
+    ansi-escapes "^3.2.0"
+    chalk "^2.4.2"
+    cli-cursor "^2.1.0"
+    cli-width "^2.0.0"
+    external-editor "^3.0.3"
+    figures "^2.0.0"
+    lodash "^4.17.12"
+    mute-stream "0.0.7"
+    run-async "^2.2.0"
+    rxjs "^6.4.0"
+    string-width "^2.1.0"
+    strip-ansi "^5.1.0"
+    through "^2.3.6"
+
+internal-ip@^4.3.0:
+  version "4.3.0"
+  resolved "https://registry.yarnpkg.com/internal-ip/-/internal-ip-4.3.0.tgz#845452baad9d2ca3b69c635a137acb9a0dad0907"
+  integrity sha512-S1zBo1D6zcsyuC6PMmY5+55YMILQ9av8lotMx447Bq6SAgo/sDK6y6uUKmuYhW7eacnIhFfsPmCNYdDzsnnDCg==
+  dependencies:
+    default-gateway "^4.2.0"
+    ipaddr.js "^1.9.0"
+
+interpret@1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.2.0.tgz#d5061a6224be58e8083985f5014d844359576296"
+  integrity sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==
+
+invariant@^2.2.2:
+  version "2.2.4"
+  resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"
+  integrity sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==
+  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"
+  integrity sha1-EEqOSqym09jNFXqO+L+rLXo//bY=
+
+invert-kv@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02"
+  integrity sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==
+
+ip-regex@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9"
+  integrity sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk=
+
+ip@^1.1.0, ip@^1.1.5:
+  version "1.1.5"
+  resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a"
+  integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo=
+
+ipaddr.js@1.9.0, ipaddr.js@^1.9.0:
+  version "1.9.0"
+  resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.0.tgz#37df74e430a0e47550fe54a2defe30d8acd95f65"
+  integrity sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA==
+
+is-accessor-descriptor@^0.1.6:
+  version "0.1.6"
+  resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6"
+  integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=
+  dependencies:
+    kind-of "^3.0.2"
+
+is-accessor-descriptor@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656"
+  integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==
+  dependencies:
+    kind-of "^6.0.0"
+
+is-arrayish@^0.2.1:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d"
+  integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=
+
+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"
+  integrity sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=
+  dependencies:
+    binary-extensions "^1.0.0"
+
+is-buffer@^1.1.5, is-buffer@~1.1.1:
+  version "1.1.6"
+  resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
+  integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==
+
+is-callable@^1.1.4:
+  version "1.1.4"
+  resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75"
+  integrity sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==
+
+is-data-descriptor@^0.1.4:
+  version "0.1.4"
+  resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56"
+  integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=
+  dependencies:
+    kind-of "^3.0.2"
+
+is-data-descriptor@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7"
+  integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==
+  dependencies:
+    kind-of "^6.0.0"
+
+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"
+  integrity sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=
+
+is-descriptor@^0.1.0:
+  version "0.1.6"
+  resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca"
+  integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==
+  dependencies:
+    is-accessor-descriptor "^0.1.6"
+    is-data-descriptor "^0.1.4"
+    kind-of "^5.0.0"
+
+is-descriptor@^1.0.0, is-descriptor@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec"
+  integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==
+  dependencies:
+    is-accessor-descriptor "^1.0.0"
+    is-data-descriptor "^1.0.0"
+    kind-of "^6.0.2"
+
+is-extendable@^0.1.0, is-extendable@^0.1.1:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89"
+  integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=
+
+is-extendable@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4"
+  integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==
+  dependencies:
+    is-plain-object "^2.0.4"
+
+is-extglob@^2.1.0, is-extglob@^2.1.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2"
+  integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=
+
+is-finite@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa"
+  integrity sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=
+  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"
+  integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs=
+  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"
+  integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=
+
+is-glob@^3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a"
+  integrity sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=
+  dependencies:
+    is-extglob "^2.1.0"
+
+is-glob@^4.0.0:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc"
+  integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==
+  dependencies:
+    is-extglob "^2.1.1"
+
+is-lower-case@^1.1.0:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/is-lower-case/-/is-lower-case-1.1.3.tgz#7e147be4768dc466db3bfb21cc60b31e6ad69393"
+  integrity sha1-fhR75HaNxGbbO/shzGCzHmrWk5M=
+  dependencies:
+    lower-case "^1.1.0"
+
+is-number@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195"
+  integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=
+  dependencies:
+    kind-of "^3.0.2"
+
+is-path-cwd@^2.0.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-2.2.0.tgz#67d43b82664a7b5191fd9119127eb300048a9fdb"
+  integrity sha512-w942bTcih8fdJPJmQHFzkS76NEP8Kzzvmw92cXsazb8intwLqPibPPdXf4ANdKV3rYMuuQYGIWtvz9JilB3NFQ==
+
+is-path-in-cwd@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-2.1.0.tgz#bfe2dca26c69f397265a4009963602935a053acb"
+  integrity sha512-rNocXHgipO+rvnP6dk3zI20RpOtrAM/kzbB258Uw5BWr3TpXi861yzjo16Dn4hUox07iw5AyeMLHWsujkjzvRQ==
+  dependencies:
+    is-path-inside "^2.1.0"
+
+is-path-inside@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-2.1.0.tgz#7c9810587d659a40d27bcdb4d5616eab059494b2"
+  integrity sha512-wiyhTzfDWsvwAW53OBWF5zuvaOGlZ6PwYxAbPVDhpm+gM09xKQGjBq/8uYN12aDvMxnAnq3dxTyoSoRNmg5YFg==
+  dependencies:
+    path-is-inside "^1.0.2"
+
+is-plain-object@^2.0.3, is-plain-object@^2.0.4:
+  version "2.0.4"
+  resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677"
+  integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==
+  dependencies:
+    isobject "^3.0.1"
+
+is-promise@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa"
+  integrity sha1-eaKp7OfwlugPNtKy87wWwf9L8/o=
+
+is-regex@^1.0.4:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491"
+  integrity sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=
+  dependencies:
+    has "^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"
+  integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ=
+
+is-symbol@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.2.tgz#a055f6ae57192caee329e7a860118b497a950f38"
+  integrity sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==
+  dependencies:
+    has-symbols "^1.0.0"
+
+is-typedarray@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a"
+  integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=
+
+is-upper-case@^1.1.0:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/is-upper-case/-/is-upper-case-1.1.2.tgz#8d0b1fa7e7933a1e58483600ec7d9661cbaf756f"
+  integrity sha1-jQsfp+eTOh5YSDYA7H2WYcuvdW8=
+  dependencies:
+    upper-case "^1.1.0"
+
+is-utf8@^0.2.0:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72"
+  integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=
+
+is-windows@^1.0.1, is-windows@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d"
+  integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==
+
+is-wsl@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d"
+  integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=
+
+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"
+  integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=
+
+isexe@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
+  integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=
+
+isobject@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89"
+  integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=
+  dependencies:
+    isarray "1.0.0"
+
+isobject@^3.0.0, isobject@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df"
+  integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8=
+
+isstream@~0.1.2:
+  version "0.1.2"
+  resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a"
+  integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=
+
+jquery-ui@^1.12.1:
+  version "1.12.1"
+  resolved "https://registry.yarnpkg.com/jquery-ui/-/jquery-ui-1.12.1.tgz#bcb4045c8dd0539c134bc1488cdd3e768a7a9e51"
+  integrity sha1-vLQEXI3QU5wTS8FIjN0+dop6nlE=
+
+jquery@^3.1.1:
+  version "3.4.1"
+  resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.4.1.tgz#714f1f8d9dde4bdfa55764ba37ef214630d80ef2"
+  integrity sha512-36+AdBzCL+y6qjw5Tx7HgzeGCzC81MDDgaUP8ld2zhx58HdqXGoBd+tHdrBMiyjGQs0Hxs/MLZTu/eHNJJuWPw==
+
+js-base64@^2.1.8:
+  version "2.5.1"
+  resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.5.1.tgz#1efa39ef2c5f7980bb1784ade4a8af2de3291121"
+  integrity sha512-M7kLczedRMYX4L8Mdh4MzyAMM9O5osx+4FcOQuTvr3A9F2D9S5JXheN0ewNbrvK2UatkTRhL5ejGmGSjNMiZuw==
+
+js-levenshtein@^1.1.3:
+  version "1.1.6"
+  resolved "https://registry.yarnpkg.com/js-levenshtein/-/js-levenshtein-1.1.6.tgz#c6cee58eb3550372df8deb85fad5ce66ce01d59d"
+  integrity sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==
+
+"js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
+  integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==
+
+js-yaml@^3.13.1:
+  version "3.13.1"
+  resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847"
+  integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==
+  dependencies:
+    argparse "^1.0.7"
+    esprima "^4.0.0"
+
+jsbn@~0.1.0:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513"
+  integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM=
+
+jsesc@^2.5.1:
+  version "2.5.2"
+  resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4"
+  integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==
+
+jsesc@~0.5.0:
+  version "0.5.0"
+  resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d"
+  integrity sha1-597mbjXW/Bb3EP6R1c9p9w8IkR0=
+
+json-parse-better-errors@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9"
+  integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==
+
+json-schema-traverse@^0.4.1:
+  version "0.4.1"
+  resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
+  integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
+
+json-schema@0.2.3:
+  version "0.2.3"
+  resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
+  integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=
+
+json-stable-stringify-without-jsonify@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz#9db7b59496ad3f3cfef30a75142d2d930ad72651"
+  integrity sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=
+
+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"
+  integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=
+
+json3@^3.3.2:
+  version "3.3.3"
+  resolved "https://registry.yarnpkg.com/json3/-/json3-3.3.3.tgz#7fc10e375fc5ae42c4705a5cc0aa6f62be305b81"
+  integrity sha512-c7/8mbUsKigAbLkD5B010BK4D9LZm7A1pNItkEwiUZRpIN66exu/e7YQWysGun+TRKaJp8MhemM+VkfWv42aCA==
+
+json5@^0.5.0:
+  version "0.5.1"
+  resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821"
+  integrity sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=
+
+json5@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe"
+  integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==
+  dependencies:
+    minimist "^1.2.0"
+
+json5@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.0.tgz#e7a0c62c48285c628d20a10b85c89bb807c32850"
+  integrity sha512-8Mh9h6xViijj36g7Dxi+Y4S6hNGV96vcJZr/SrlHh1LR/pEn/8j/+qIBbs44YKl69Lrfctp4QD+AdWLTMqEZAQ==
+  dependencies:
+    minimist "^1.2.0"
+
+jsprim@^1.2.2:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2"
+  integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=
+  dependencies:
+    assert-plus "1.0.0"
+    extsprintf "1.3.0"
+    json-schema "0.2.3"
+    verror "1.10.0"
+
+jstransform@^11.0.3:
+  version "11.0.3"
+  resolved "https://registry.yarnpkg.com/jstransform/-/jstransform-11.0.3.tgz#09a78993e0ae4d4ef4487f6155a91f6190cb4223"
+  integrity sha1-CaeJk+CuTU70SH9hVakfYZDLQiM=
+  dependencies:
+    base62 "^1.1.0"
+    commoner "^0.10.1"
+    esprima-fb "^15001.1.0-dev-harmony-fb"
+    object-assign "^2.0.0"
+    source-map "^0.4.2"
+
+killable@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/killable/-/killable-1.0.1.tgz#4c8ce441187a061c7474fb87ca08e2a638194892"
+  integrity sha512-LzqtLKlUwirEUyl/nicirVmNiPvYs7l5n8wOPP7fyJVpUPkvCnW/vuiXGpylGUlnPDnB7311rARzAt3Mhswpjg==
+
+kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0:
+  version "3.2.2"
+  resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64"
+  integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=
+  dependencies:
+    is-buffer "^1.1.5"
+
+kind-of@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57"
+  integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc=
+  dependencies:
+    is-buffer "^1.1.5"
+
+kind-of@^5.0.0:
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d"
+  integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==
+
+kind-of@^6.0.0, kind-of@^6.0.2:
+  version "6.0.2"
+  resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.2.tgz#01146b36a6218e64e58f3a8d66de5d7fc6f6d051"
+  integrity sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==
+
+lazy-cache@^1.0.3:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e"
+  integrity sha1-odePw6UEdMuAhF07O24dpJpEbo4=
+
+lcid@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835"
+  integrity sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=
+  dependencies:
+    invert-kv "^1.0.0"
+
+lcid@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/lcid/-/lcid-2.0.0.tgz#6ef5d2df60e52f82eb228a4c373e8d1f397253cf"
+  integrity sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==
+  dependencies:
+    invert-kv "^2.0.0"
+
+levn@^0.3.0, levn@~0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee"
+  integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=
+  dependencies:
+    prelude-ls "~1.1.2"
+    type-check "~0.3.2"
+
+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"
+  integrity sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=
+  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"
+
+loader-fs-cache@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/loader-fs-cache/-/loader-fs-cache-1.0.2.tgz#54cedf6b727e1779fd8f01205f05f6e88706f086"
+  integrity sha512-70IzT/0/L+M20jUlEqZhZyArTU6VKLRTYRDAYN26g4jfzpJqjipLL3/hgYpySqI9PwsVRHHFja0LfEmsx9X2Cw==
+  dependencies:
+    find-cache-dir "^0.1.1"
+    mkdirp "0.5.1"
+
+loader-runner@^2.3.0:
+  version "2.4.0"
+  resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.4.0.tgz#ed47066bfe534d7e84c4c7b9998c2a75607d9357"
+  integrity sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==
+
+loader-utils@1.2.3, loader-utils@^1.0.1, loader-utils@^1.0.2, loader-utils@^1.1.0, loader-utils@^1.2.3:
+  version "1.2.3"
+  resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.2.3.tgz#1ff5dc6911c9f0a062531a4c04b609406108c2c7"
+  integrity sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==
+  dependencies:
+    big.js "^5.2.2"
+    emojis-list "^2.0.0"
+    json5 "^1.0.1"
+
+loader-utils@^0.2.16:
+  version "0.2.17"
+  resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-0.2.17.tgz#f86e6374d43205a6e6c60e9196f17c0299bfb348"
+  integrity sha1-+G5jdNQyBabmxg6RlvF8Apm/s0g=
+  dependencies:
+    big.js "^3.1.3"
+    emojis-list "^2.0.0"
+    json5 "^0.5.0"
+    object-assign "^4.0.1"
+
+locate-path@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e"
+  integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==
+  dependencies:
+    p-locate "^3.0.0"
+    path-exists "^3.0.0"
+
+lodash.tail@^4.1.1:
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/lodash.tail/-/lodash.tail-4.1.1.tgz#d2333a36d9e7717c8ad2f7cacafec7c32b444664"
+  integrity sha1-0jM6NtnncXyK0vfKyv7HwytERmQ=
+
+lodash@^4.0.0, lodash@^4.17.11, lodash@^4.17.12, lodash@^4.17.14, lodash@^4.17.3, lodash@~4.17.10:
+  version "4.17.14"
+  resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.14.tgz#9ce487ae66c96254fe20b599f21b6816028078ba"
+  integrity sha512-mmKYbW3GLuJeX+iGP+Y7Gp1AiGHGbXHCOh/jZmrawMmsE7MS4znI3RL2FsjbqOyMayHInjOeykW7PEajUk1/xw==
+
+loglevel@^1.6.3:
+  version "1.6.3"
+  resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.6.3.tgz#77f2eb64be55a404c9fd04ad16d57c1d6d6b1280"
+  integrity sha512-LoEDv5pgpvWgPF4kNYuIp0qqSJVWak/dML0RY74xlzMZiT9w77teNAwKYKWBTYjlokMirg+o3jBwp+vlLrcfAA==
+
+longest@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097"
+  integrity sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=
+
+loose-envify@^1.0.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
+  integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==
+  dependencies:
+    js-tokens "^3.0.0 || ^4.0.0"
+
+loud-rejection@^1.0.0:
+  version "1.6.0"
+  resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f"
+  integrity sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=
+  dependencies:
+    currently-unhandled "^0.4.1"
+    signal-exit "^3.0.0"
+
+lower-case-first@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/lower-case-first/-/lower-case-first-1.0.2.tgz#e5da7c26f29a7073be02d52bac9980e5922adfa1"
+  integrity sha1-5dp8JvKacHO+AtUrrJmA5ZIq36E=
+  dependencies:
+    lower-case "^1.1.2"
+
+lower-case@^1.1.0, lower-case@^1.1.1, lower-case@^1.1.2:
+  version "1.1.4"
+  resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-1.1.4.tgz#9a2cabd1b9e8e0ae993a4bf7d5875c39c42e8eac"
+  integrity sha1-miyr0bno4K6ZOkv31YdcOcQujqw=
+
+lru-cache@^4.0.1, lru-cache@^4.1.2:
+  version "4.1.5"
+  resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd"
+  integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==
+  dependencies:
+    pseudomap "^1.0.2"
+    yallist "^2.1.2"
+
+lru-cache@^5.1.1:
+  version "5.1.1"
+  resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920"
+  integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==
+  dependencies:
+    yallist "^3.0.2"
+
+make-dir@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5"
+  integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==
+  dependencies:
+    pify "^4.0.1"
+    semver "^5.6.0"
+
+mamacro@^0.0.3:
+  version "0.0.3"
+  resolved "https://registry.yarnpkg.com/mamacro/-/mamacro-0.0.3.tgz#ad2c9576197c9f1abf308d0787865bd975a3f3e4"
+  integrity sha512-qMEwh+UujcQ+kbz3T6V+wAmO2U8veoq2w+3wY8MquqwVA3jChfwY+Tk52GZKDfACEPjuZ7r2oJLejwpt8jtwTA==
+
+map-age-cleaner@^0.1.1:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz#7d583a7306434c055fe474b0f45078e6e1b4b92a"
+  integrity sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==
+  dependencies:
+    p-defer "^1.0.0"
+
+map-cache@^0.2.2:
+  version "0.2.2"
+  resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf"
+  integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=
+
+map-obj@^1.0.0, map-obj@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d"
+  integrity sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=
+
+map-visit@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f"
+  integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=
+  dependencies:
+    object-visit "^1.0.0"
+
+md5.js@^1.3.4:
+  version "1.3.5"
+  resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f"
+  integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==
+  dependencies:
+    hash-base "^3.0.0"
+    inherits "^2.0.1"
+    safe-buffer "^5.1.2"
+
+md5@^2.0.0:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/md5/-/md5-2.2.1.tgz#53ab38d5fe3c8891ba465329ea23fac0540126f9"
+  integrity sha1-U6s41f48iJG6RlMp6iP6wFQBJvk=
+  dependencies:
+    charenc "~0.0.1"
+    crypt "~0.0.1"
+    is-buffer "~1.1.1"
+
+media-typer@0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
+  integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=
+
+mem@^4.0.0:
+  version "4.3.0"
+  resolved "https://registry.yarnpkg.com/mem/-/mem-4.3.0.tgz#461af497bc4ae09608cdb2e60eefb69bff744178"
+  integrity sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==
+  dependencies:
+    map-age-cleaner "^0.1.1"
+    mimic-fn "^2.0.0"
+    p-is-promise "^2.0.0"
+
+memory-fs@^0.4.0, memory-fs@^0.4.1, memory-fs@~0.4.1:
+  version "0.4.1"
+  resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552"
+  integrity sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=
+  dependencies:
+    errno "^0.1.3"
+    readable-stream "^2.0.1"
+
+meow@^3.7.0:
+  version "3.7.0"
+  resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb"
+  integrity sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=
+  dependencies:
+    camelcase-keys "^2.0.0"
+    decamelize "^1.1.2"
+    loud-rejection "^1.0.0"
+    map-obj "^1.0.1"
+    minimist "^1.1.3"
+    normalize-package-data "^2.3.4"
+    object-assign "^4.0.1"
+    read-pkg-up "^1.0.1"
+    redent "^1.0.0"
+    trim-newlines "^1.0.0"
+
+merge-descriptors@1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61"
+  integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=
+
+merge-source-map@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/merge-source-map/-/merge-source-map-1.1.0.tgz#2fdde7e6020939f70906a68f2d7ae685e4c8c646"
+  integrity sha512-Qkcp7P2ygktpMPh2mCQZaf3jhN6D3Z/qVZHSdWvQ+2Ef5HgRAPBO57A77+ENm0CPx2+1Ce/MYKi3ymqdfuqibw==
+  dependencies:
+    source-map "^0.6.1"
+
+methods@~1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
+  integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=
+
+micromatch@^3.0.4, micromatch@^3.1.10, micromatch@^3.1.4, micromatch@^3.1.8:
+  version "3.1.10"
+  resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23"
+  integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==
+  dependencies:
+    arr-diff "^4.0.0"
+    array-unique "^0.3.2"
+    braces "^2.3.1"
+    define-property "^2.0.2"
+    extend-shallow "^3.0.2"
+    extglob "^2.0.4"
+    fragment-cache "^0.2.1"
+    kind-of "^6.0.2"
+    nanomatch "^1.2.9"
+    object.pick "^1.3.0"
+    regex-not "^1.0.0"
+    snapdragon "^0.8.1"
+    to-regex "^3.0.2"
+
+miller-rabin@^4.0.0:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d"
+  integrity sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==
+  dependencies:
+    bn.js "^4.0.0"
+    brorand "^1.0.1"
+
+mime-db@1.40.0, "mime-db@>= 1.40.0 < 2":
+  version "1.40.0"
+  resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.40.0.tgz#a65057e998db090f732a68f6c276d387d4126c32"
+  integrity sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==
+
+mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.19, mime-types@~2.1.24:
+  version "2.1.24"
+  resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.24.tgz#b6f8d0b3e951efb77dedeca194cff6d16f676f81"
+  integrity sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==
+  dependencies:
+    mime-db "1.40.0"
+
+mime@1.6.0:
+  version "1.6.0"
+  resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1"
+  integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==
+
+mime@^2.4.2:
+  version "2.4.4"
+  resolved "https://registry.yarnpkg.com/mime/-/mime-2.4.4.tgz#bd7b91135fc6b01cde3e9bae33d659b63d8857e5"
+  integrity sha512-LRxmNwziLPT828z+4YkNzloCFC2YM4wrB99k+AV5ZbEyfGNWfG8SO1FUXLmLDBSo89NrJZ4DIWeLjy1CHGhMGA==
+
+mimic-fn@^1.0.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022"
+  integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ==
+
+mimic-fn@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
+  integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
+
+minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7"
+  integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==
+
+minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a"
+  integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=
+
+"minimatch@2 || 3", minimatch@^3.0.4, minimatch@~3.0.2:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083"
+  integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==
+  dependencies:
+    brace-expansion "^1.1.7"
+
+minimist@0.0.8:
+  version "0.0.8"
+  resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d"
+  integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=
+
+minimist@^1.1.3, minimist@^1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284"
+  integrity sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=
+
+minipass@^2.2.1, minipass@^2.3.5:
+  version "2.3.5"
+  resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.3.5.tgz#cacebe492022497f656b0f0f51e2682a9ed2d848"
+  integrity sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==
+  dependencies:
+    safe-buffer "^5.1.2"
+    yallist "^3.0.0"
+
+minizlib@^1.2.1:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.2.1.tgz#dd27ea6136243c7c880684e8672bb3a45fd9b614"
+  integrity sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==
+  dependencies:
+    minipass "^2.2.1"
+
+mississippi@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-3.0.0.tgz#ea0a3291f97e0b5e8776b363d5f0a12d94c67022"
+  integrity sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==
+  dependencies:
+    concat-stream "^1.5.0"
+    duplexify "^3.4.2"
+    end-of-stream "^1.1.0"
+    flush-write-stream "^1.0.0"
+    from2 "^2.1.0"
+    parallel-transform "^1.1.0"
+    pump "^3.0.0"
+    pumpify "^1.3.3"
+    stream-each "^1.1.0"
+    through2 "^2.0.0"
+
+mixin-deep@^1.2.0:
+  version "1.3.2"
+  resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566"
+  integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==
+  dependencies:
+    for-in "^1.0.2"
+    is-extendable "^1.0.1"
+
+mixin-object@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/mixin-object/-/mixin-object-2.0.1.tgz#4fb949441dab182540f1fe035ba60e1947a5e57e"
+  integrity sha1-T7lJRB2rGCVA8f4DW6YOGUel5X4=
+  dependencies:
+    for-in "^0.1.3"
+    is-extendable "^0.1.1"
+
+mkdirp@0.5.1, mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0:
+  version "0.5.1"
+  resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903"
+  integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=
+  dependencies:
+    minimist "0.0.8"
+
+moment@^2.10.2:
+  version "2.24.0"
+  resolved "https://registry.yarnpkg.com/moment/-/moment-2.24.0.tgz#0d055d53f5052aa653c9f6eb68bb5d12bf5c2b5b"
+  integrity sha512-bV7f+6l2QigeBBZSM/6yTNq4P2fNpSWj/0e7jQcy87A8e7o2nAfP/34/2ky5Vw4B9S446EtIhodAzkFCcR4dQg==
+
+move-concurrently@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92"
+  integrity sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=
+  dependencies:
+    aproba "^1.1.1"
+    copy-concurrently "^1.0.0"
+    fs-write-stream-atomic "^1.0.8"
+    mkdirp "^0.5.1"
+    rimraf "^2.5.4"
+    run-queue "^1.0.3"
+
+ms@2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
+  integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=
+
+ms@2.1.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a"
+  integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==
+
+ms@^2.1.1:
+  version "2.1.2"
+  resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009"
+  integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==
+
+multicast-dns-service-types@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/multicast-dns-service-types/-/multicast-dns-service-types-1.1.0.tgz#899f11d9686e5e05cb91b35d5f0e63b773cfc901"
+  integrity sha1-iZ8R2WhuXgXLkbNdXw5jt3PPyQE=
+
+multicast-dns@^6.0.1:
+  version "6.2.3"
+  resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-6.2.3.tgz#a0ec7bd9055c4282f790c3c82f4e28db3b31b229"
+  integrity sha512-ji6J5enbMyGRHIAkAOu3WdV8nggqviKCEKtXcOqfphZZtQrmHKycfynJ2V7eVPUA4NhJ6V7Wf4TmGbTwKE9B6g==
+  dependencies:
+    dns-packet "^1.3.1"
+    thunky "^1.0.2"
+
+mute-stream@0.0.7:
+  version "0.0.7"
+  resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab"
+  integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=
+
+nan@^2.12.1, nan@^2.13.2:
+  version "2.14.0"
+  resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c"
+  integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==
+
+nanomatch@^1.2.9:
+  version "1.2.13"
+  resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119"
+  integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==
+  dependencies:
+    arr-diff "^4.0.0"
+    array-unique "^0.3.2"
+    define-property "^2.0.2"
+    extend-shallow "^3.0.2"
+    fragment-cache "^0.2.1"
+    is-windows "^1.0.2"
+    kind-of "^6.0.2"
+    object.pick "^1.3.0"
+    regex-not "^1.0.0"
+    snapdragon "^0.8.1"
+    to-regex "^3.0.1"
+
+natural-compare@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
+  integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=
+
+ncname@1.0.x:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/ncname/-/ncname-1.0.0.tgz#5b57ad18b1ca092864ef62b0b1ed8194f383b71c"
+  integrity sha1-W1etGLHKCShk72Kwse2BlPODtxw=
+  dependencies:
+    xml-char-classes "^1.0.0"
+
+needle@^2.2.1:
+  version "2.4.0"
+  resolved "https://registry.yarnpkg.com/needle/-/needle-2.4.0.tgz#6833e74975c444642590e15a750288c5f939b57c"
+  integrity sha512-4Hnwzr3mi5L97hMYeNl8wRW/Onhy4nUKR/lVemJ8gJedxxUyBLm9kkrDColJvoSfwi0jCNhD+xCdOtiGDQiRZg==
+  dependencies:
+    debug "^3.2.6"
+    iconv-lite "^0.4.4"
+    sax "^1.2.4"
+
+negotiator@0.6.2:
+  version "0.6.2"
+  resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb"
+  integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==
+
+neo-async@^2.5.0:
+  version "2.6.1"
+  resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.1.tgz#ac27ada66167fa8849a6addd837f6b189ad2081c"
+  integrity sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==
+
+nice-try@^1.0.4:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366"
+  integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==
+
+no-case@^2.2.0, no-case@^2.3.2:
+  version "2.3.2"
+  resolved "https://registry.yarnpkg.com/no-case/-/no-case-2.3.2.tgz#60b813396be39b3f1288a4c1ed5d1e7d28b464ac"
+  integrity sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==
+  dependencies:
+    lower-case "^1.1.1"
+
+node-forge@0.7.5:
+  version "0.7.5"
+  resolved "https://registry.yarnpkg.com/node-forge/-/node-forge-0.7.5.tgz#6c152c345ce11c52f465c2abd957e8639cd674df"
+  integrity sha512-MmbQJ2MTESTjt3Gi/3yG1wGpIMhUfcIypUCGtTizFR9IiccFwxSpfp0vtIZlkFclEqERemxfnSdZEMR9VqqEFQ==
+
+node-gyp@^3.8.0:
+  version "3.8.0"
+  resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-3.8.0.tgz#540304261c330e80d0d5edce253a68cb3964218c"
+  integrity sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA==
+  dependencies:
+    fstream "^1.0.0"
+    glob "^7.0.3"
+    graceful-fs "^4.1.2"
+    mkdirp "^0.5.0"
+    nopt "2 || 3"
+    npmlog "0 || 1 || 2 || 3 || 4"
+    osenv "0"
+    request "^2.87.0"
+    rimraf "2"
+    semver "~5.3.0"
+    tar "^2.0.0"
+    which "1"
+
+node-libs-browser@^2.0.0:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.1.tgz#b64f513d18338625f90346d27b0d235e631f6425"
+  integrity sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==
+  dependencies:
+    assert "^1.1.1"
+    browserify-zlib "^0.2.0"
+    buffer "^4.3.0"
+    console-browserify "^1.1.0"
+    constants-browserify "^1.0.0"
+    crypto-browserify "^3.11.0"
+    domain-browser "^1.1.1"
+    events "^3.0.0"
+    https-browserify "^1.0.0"
+    os-browserify "^0.3.0"
+    path-browserify "0.0.1"
+    process "^0.11.10"
+    punycode "^1.2.4"
+    querystring-es3 "^0.2.0"
+    readable-stream "^2.3.3"
+    stream-browserify "^2.0.1"
+    stream-http "^2.7.2"
+    string_decoder "^1.0.0"
+    timers-browserify "^2.0.4"
+    tty-browserify "0.0.0"
+    url "^0.11.0"
+    util "^0.11.0"
+    vm-browserify "^1.0.1"
+
+node-pre-gyp@^0.12.0:
+  version "0.12.0"
+  resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.12.0.tgz#39ba4bb1439da030295f899e3b520b7785766149"
+  integrity sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A==
+  dependencies:
+    detect-libc "^1.0.2"
+    mkdirp "^0.5.1"
+    needle "^2.2.1"
+    nopt "^4.0.1"
+    npm-packlist "^1.1.6"
+    npmlog "^4.0.2"
+    rc "^1.2.7"
+    rimraf "^2.6.1"
+    semver "^5.3.0"
+    tar "^4"
+
+node-releases@^1.1.25:
+  version "1.1.25"
+  resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.25.tgz#0c2d7dbc7fed30fbe02a9ee3007b8c90bf0133d3"
+  integrity sha512-fI5BXuk83lKEoZDdH3gRhtsNgh05/wZacuXkgbiYkceE7+QIMXOg98n9ZV7mz27B+kFHnqHcUpscZZlGRSmTpQ==
+  dependencies:
+    semver "^5.3.0"
+
+node-sass@^4.12.0:
+  version "4.12.0"
+  resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.12.0.tgz#0914f531932380114a30cc5fa4fa63233a25f017"
+  integrity sha512-A1Iv4oN+Iel6EPv77/HddXErL2a+gZ4uBeZUy+a8O35CFYTXhgA8MgLCWBtwpGZdCvTvQ9d+bQxX/QC36GDPpQ==
+  dependencies:
+    async-foreach "^0.1.3"
+    chalk "^1.1.1"
+    cross-spawn "^3.0.0"
+    gaze "^1.0.0"
+    get-stdin "^4.0.1"
+    glob "^7.0.3"
+    in-publish "^2.0.0"
+    lodash "^4.17.11"
+    meow "^3.7.0"
+    mkdirp "^0.5.1"
+    nan "^2.13.2"
+    node-gyp "^3.8.0"
+    npmlog "^4.0.0"
+    request "^2.88.0"
+    sass-graph "^2.2.4"
+    stdout-stream "^1.4.0"
+    "true-case-path" "^1.0.2"
+
+"nopt@2 || 3":
+  version "3.0.6"
+  resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9"
+  integrity sha1-xkZdvwirzU2zWTF/eaxopkayj/k=
+  dependencies:
+    abbrev "1"
+
+nopt@^4.0.1:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d"
+  integrity sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=
+  dependencies:
+    abbrev "1"
+    osenv "^0.1.4"
+
+normalize-package-data@^2.3.2, normalize-package-data@^2.3.4:
+  version "2.5.0"
+  resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8"
+  integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==
+  dependencies:
+    hosted-git-info "^2.1.4"
+    resolve "^1.10.0"
+    semver "2 || 3 || 4 || 5"
+    validate-npm-package-license "^3.0.1"
+
+normalize-path@^2.1.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9"
+  integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=
+  dependencies:
+    remove-trailing-separator "^1.0.1"
+
+normalize-path@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
+  integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
+
+npm-bundled@^1.0.1:
+  version "1.0.6"
+  resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.0.6.tgz#e7ba9aadcef962bb61248f91721cd932b3fe6bdd"
+  integrity sha512-8/JCaftHwbd//k6y2rEWp6k1wxVfpFzB6t1p825+cUb7Ym2XQfhwIC5KwhrvzZRJu+LtDE585zVaS32+CGtf0g==
+
+npm-packlist@^1.1.6:
+  version "1.4.4"
+  resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.4.tgz#866224233850ac534b63d1a6e76050092b5d2f44"
+  integrity sha512-zTLo8UcVYtDU3gdeaFu2Xu0n0EvelfHDGuqtNIn5RO7yQj4H1TqNdBc/yZjxnWA0PVB8D3Woyp0i5B43JwQ6Vw==
+  dependencies:
+    ignore-walk "^3.0.1"
+    npm-bundled "^1.0.1"
+
+npm-run-path@^2.0.0:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f"
+  integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=
+  dependencies:
+    path-key "^2.0.0"
+
+"npmlog@0 || 1 || 2 || 3 || 4", npmlog@^4.0.0, npmlog@^4.0.2:
+  version "4.1.2"
+  resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b"
+  integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==
+  dependencies:
+    are-we-there-yet "~1.1.2"
+    console-control-strings "~1.1.0"
+    gauge "~2.7.3"
+    set-blocking "~2.0.0"
+
+nth-check@~1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.2.tgz#b2bd295c37e3dd58a3bf0700376663ba4d9cf05c"
+  integrity sha512-WeBOdju8SnzPN5vTUJYxYUxLeXpCaVP5i5e0LF8fg7WORF2Wd7wFX/pk0tYZk7s8T+J7VLy0Da6J1+wCT0AtHg==
+  dependencies:
+    boolbase "~1.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"
+  integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=
+
+oauth-sign@~0.9.0:
+  version "0.9.0"
+  resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455"
+  integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==
+
+object-assign@^2.0.0:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-2.1.1.tgz#43c36e5d569ff8e4816c4efa8be02d26967c18aa"
+  integrity sha1-Q8NuXVaf+OSBbE76i+AtJpZ8GKo=
+
+object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1:
+  version "4.1.1"
+  resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
+  integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
+
+object-copy@^0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c"
+  integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw=
+  dependencies:
+    copy-descriptor "^0.1.0"
+    define-property "^0.2.5"
+    kind-of "^3.0.3"
+
+object-hash@^1.1.4:
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-1.3.1.tgz#fde452098a951cb145f039bb7d455449ddc126df"
+  integrity sha512-OSuu/pU4ENM9kmREg0BdNrUDIl1heYa4mBZacJc+vVWz4GtAwu7jO8s4AIt2aGRUTqxykpWzI3Oqnsm13tTMDA==
+
+object-keys@^1.0.11, object-keys@^1.0.12:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e"
+  integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==
+
+object-visit@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb"
+  integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=
+  dependencies:
+    isobject "^3.0.0"
+
+object.assign@^4.1.0:
+  version "4.1.0"
+  resolved "https://registry.yarnpkg.com/object.assign/-/object.assign-4.1.0.tgz#968bf1100d7956bb3ca086f006f846b3bc4008da"
+  integrity sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==
+  dependencies:
+    define-properties "^1.1.2"
+    function-bind "^1.1.1"
+    has-symbols "^1.0.0"
+    object-keys "^1.0.11"
+
+object.getownpropertydescriptors@^2.0.3:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz#8758c846f5b407adab0f236e0986f14b051caa16"
+  integrity sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=
+  dependencies:
+    define-properties "^1.1.2"
+    es-abstract "^1.5.1"
+
+object.pick@^1.3.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747"
+  integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=
+  dependencies:
+    isobject "^3.0.1"
+
+obuf@^1.0.0, obuf@^1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.2.tgz#09bea3343d41859ebd446292d11c9d4db619084e"
+  integrity sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==
+
+on-finished@~2.3.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947"
+  integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=
+  dependencies:
+    ee-first "1.1.1"
+
+on-headers@~1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f"
+  integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==
+
+once@^1.3.0, once@^1.3.1, once@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
+  integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
+  dependencies:
+    wrappy "1"
+
+onetime@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4"
+  integrity sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ=
+  dependencies:
+    mimic-fn "^1.0.0"
+
+opn@^5.5.0:
+  version "5.5.0"
+  resolved "https://registry.yarnpkg.com/opn/-/opn-5.5.0.tgz#fc7164fab56d235904c51c3b27da6758ca3b9bfc"
+  integrity sha512-PqHpggC9bLV0VeWcdKhkpxY+3JTzetLSqTCWL/z/tFIbI6G8JCjondXklT1JinczLz2Xib62sSp0T/gKT4KksA==
+  dependencies:
+    is-wsl "^1.1.0"
+
+optionator@^0.8.2:
+  version "0.8.2"
+  resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64"
+  integrity sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=
+  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"
+
+original@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/original/-/original-1.0.2.tgz#e442a61cffe1c5fd20a65f3261c26663b303f25f"
+  integrity sha512-hyBVl6iqqUOJ8FqRe+l/gS8H+kKYjrEndd5Pm1MfBtsEKA038HkkdbAl/72EAXGyonD/PFsvmVG+EvcIpliMBg==
+  dependencies:
+    url-parse "^1.4.3"
+
+os-browserify@^0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27"
+  integrity sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=
+
+os-homedir@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
+  integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M=
+
+os-locale@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9"
+  integrity sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=
+  dependencies:
+    lcid "^1.0.0"
+
+os-locale@^3.0.0, os-locale@^3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-3.1.0.tgz#a802a6ee17f24c10483ab9935719cef4ed16bf1a"
+  integrity sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==
+  dependencies:
+    execa "^1.0.0"
+    lcid "^2.0.0"
+    mem "^4.0.0"
+
+os-tmpdir@^1.0.0, os-tmpdir@~1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
+  integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=
+
+osenv@0, osenv@^0.1.4:
+  version "0.1.5"
+  resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410"
+  integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==
+  dependencies:
+    os-homedir "^1.0.0"
+    os-tmpdir "^1.0.0"
+
+p-defer@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/p-defer/-/p-defer-1.0.0.tgz#9f6eb182f6c9aa8cd743004a7d4f96b196b0fb0c"
+  integrity sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=
+
+p-finally@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae"
+  integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=
+
+p-is-promise@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/p-is-promise/-/p-is-promise-2.1.0.tgz#918cebaea248a62cf7ffab8e3bca8c5f882fc42e"
+  integrity sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==
+
+p-limit@^2.0.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.2.0.tgz#417c9941e6027a9abcba5092dd2904e255b5fbc2"
+  integrity sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==
+  dependencies:
+    p-try "^2.0.0"
+
+p-locate@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4"
+  integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==
+  dependencies:
+    p-limit "^2.0.0"
+
+p-map@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175"
+  integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw==
+
+p-retry@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/p-retry/-/p-retry-3.0.1.tgz#316b4c8893e2c8dc1cfa891f406c4b422bebf328"
+  integrity sha512-XE6G4+YTTkT2a0UWb2kjZe8xNwf8bIbnqpc/IS/idOBVhyves0mK5OJgeocjx7q5pvX/6m23xuzVPYT1uGM73w==
+  dependencies:
+    retry "^0.12.0"
+
+p-try@^2.0.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6"
+  integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==
+
+pako@~1.0.5:
+  version "1.0.10"
+  resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.10.tgz#4328badb5086a426aa90f541977d4955da5c9732"
+  integrity sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw==
+
+parallel-transform@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.1.0.tgz#d410f065b05da23081fcd10f28854c29bda33b06"
+  integrity sha1-1BDwZbBdojCB/NEPKIVMKb2jOwY=
+  dependencies:
+    cyclist "~0.2.2"
+    inherits "^2.0.3"
+    readable-stream "^2.1.5"
+
+param-case@2.1.x, param-case@^2.1.0:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/param-case/-/param-case-2.1.1.tgz#df94fd8cf6531ecf75e6bef9a0858fbc72be2247"
+  integrity sha1-35T9jPZTHs915r75oIWPvHK+Ikc=
+  dependencies:
+    no-case "^2.2.0"
+
+parent-module@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2"
+  integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==
+  dependencies:
+    callsites "^3.0.0"
+
+parse-asn1@^5.0.0:
+  version "5.1.4"
+  resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.4.tgz#37f6628f823fbdeb2273b4d540434a22f3ef1fcc"
+  integrity sha512-Qs5duJcuvNExRfFZ99HDD3z4mAi3r9Wl/FOjEOijlxwCZs7E7mW2vjTpgQ4J8LpTF8x5v+1Vn5UQFejmWT11aw==
+  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"
+    safe-buffer "^5.1.1"
+
+parse-json@^2.2.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9"
+  integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=
+  dependencies:
+    error-ex "^1.2.0"
+
+parse-passwd@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/parse-passwd/-/parse-passwd-1.0.0.tgz#6d5b934a456993b23d37f40a382d6f1666a8e5c6"
+  integrity sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=
+
+parseurl@~1.3.2, parseurl@~1.3.3:
+  version "1.3.3"
+  resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4"
+  integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==
+
+pascal-case@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/pascal-case/-/pascal-case-2.0.1.tgz#2d578d3455f660da65eca18ef95b4e0de912761e"
+  integrity sha1-LVeNNFX2YNpl7KGO+VtODekSdh4=
+  dependencies:
+    camel-case "^3.0.0"
+    upper-case-first "^1.1.0"
+
+pascalcase@^0.1.1:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14"
+  integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=
+
+path-browserify@0.0.1:
+  version "0.0.1"
+  resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.1.tgz#e6c4ddd7ed3aa27c68a20cc4e50e1a4ee83bbc4a"
+  integrity sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==
+
+path-case@^2.1.0:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/path-case/-/path-case-2.1.1.tgz#94b8037c372d3fe2906e465bb45e25d226e8eea5"
+  integrity sha1-lLgDfDctP+KQbkZbtF4l0ibo7qU=
+  dependencies:
+    no-case "^2.2.0"
+
+path-dirname@^1.0.0:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0"
+  integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=
+
+path-exists@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b"
+  integrity sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=
+  dependencies:
+    pinkie-promise "^2.0.0"
+
+path-exists@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515"
+  integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=
+
+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"
+  integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18=
+
+path-is-inside@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53"
+  integrity sha1-NlQX3t5EQw0cEa9hAn+s8HS9/FM=
+
+path-key@^2.0.0, path-key@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40"
+  integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=
+
+path-parse@^1.0.6:
+  version "1.0.6"
+  resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c"
+  integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==
+
+path-to-regexp@0.1.7:
+  version "0.1.7"
+  resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
+  integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=
+
+path-type@^1.0.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441"
+  integrity sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=
+  dependencies:
+    graceful-fs "^4.1.2"
+    pify "^2.0.0"
+    pinkie-promise "^2.0.0"
+
+pbkdf2@^3.0.3:
+  version "3.0.17"
+  resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.17.tgz#976c206530617b14ebb32114239f7b09336e93a6"
+  integrity sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==
+  dependencies:
+    create-hash "^1.1.2"
+    create-hmac "^1.1.4"
+    ripemd160 "^2.0.1"
+    safe-buffer "^5.0.1"
+    sha.js "^2.4.8"
+
+performance-now@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b"
+  integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=
+
+pify@^2.0.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c"
+  integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw=
+
+pify@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176"
+  integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=
+
+pify@^4.0.1:
+  version "4.0.1"
+  resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231"
+  integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==
+
+pinkie-promise@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa"
+  integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o=
+  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"
+  integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA=
+
+pkg-dir@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-1.0.0.tgz#7a4b508a8d5bb2d629d447056ff4e9c9314cf3d4"
+  integrity sha1-ektQio1bstYp1EcFb/TpyTFM89Q=
+  dependencies:
+    find-up "^1.0.0"
+
+pkg-dir@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3"
+  integrity sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==
+  dependencies:
+    find-up "^3.0.0"
+
+portfinder@^1.0.20:
+  version "1.0.21"
+  resolved "https://registry.yarnpkg.com/portfinder/-/portfinder-1.0.21.tgz#60e1397b95ac170749db70034ece306b9a27e324"
+  integrity sha512-ESabpDCzmBS3ekHbmpAIiESq3udRsCBGiBZLsC+HgBKv2ezb0R4oG+7RnYEVZ/ZCfhel5Tx3UzdNWA0Lox2QCA==
+  dependencies:
+    async "^1.5.2"
+    debug "^2.2.0"
+    mkdirp "0.5.x"
+
+posix-character-classes@^0.1.0:
+  version "0.1.1"
+  resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab"
+  integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=
+
+postcss-modules-extract-imports@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-2.0.0.tgz#818719a1ae1da325f9832446b01136eeb493cd7e"
+  integrity sha512-LaYLDNS4SG8Q5WAWqIJgdHPJrDDr/Lv775rMBFUbgjTz6j34lUznACHcdRWroPvXANP2Vj7yNK57vp9eFqzLWQ==
+  dependencies:
+    postcss "^7.0.5"
+
+postcss-modules-local-by-default@^3.0.2:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-3.0.2.tgz#e8a6561be914aaf3c052876377524ca90dbb7915"
+  integrity sha512-jM/V8eqM4oJ/22j0gx4jrp63GSvDH6v86OqyTHHUvk4/k1vceipZsaymiZ5PvocqZOl5SFHiFJqjs3la0wnfIQ==
+  dependencies:
+    icss-utils "^4.1.1"
+    postcss "^7.0.16"
+    postcss-selector-parser "^6.0.2"
+    postcss-value-parser "^4.0.0"
+
+postcss-modules-scope@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-2.1.0.tgz#ad3f5bf7856114f6fcab901b0502e2a2bc39d4eb"
+  integrity sha512-91Rjps0JnmtUB0cujlc8KIKCsJXWjzuxGeT/+Q2i2HXKZ7nBUeF9YQTZZTNvHVoNYj1AthsjnGLtqDUE0Op79A==
+  dependencies:
+    postcss "^7.0.6"
+    postcss-selector-parser "^6.0.0"
+
+postcss-modules-values@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-3.0.0.tgz#5b5000d6ebae29b4255301b4a3a54574423e7f10"
+  integrity sha512-1//E5jCBrZ9DmRX+zCtmQtRSV6PV42Ix7Bzj9GbwJceduuf7IqP8MgeTXuRDHOWj2m0VzZD5+roFWDuU8RQjcg==
+  dependencies:
+    icss-utils "^4.0.0"
+    postcss "^7.0.6"
+
+postcss-selector-parser@^5.0.0:
+  version "5.0.0"
+  resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-5.0.0.tgz#249044356697b33b64f1a8f7c80922dddee7195c"
+  integrity sha512-w+zLE5Jhg6Liz8+rQOWEAwtwkyqpfnmsinXjXg6cY7YIONZZtgvE0v2O0uhQBs0peNomOJwWRKt6JBfTdTd3OQ==
+  dependencies:
+    cssesc "^2.0.0"
+    indexes-of "^1.0.1"
+    uniq "^1.0.1"
+
+postcss-selector-parser@^6.0.0, postcss-selector-parser@^6.0.2:
+  version "6.0.2"
+  resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.2.tgz#934cf799d016c83411859e09dcecade01286ec5c"
+  integrity sha512-36P2QR59jDTOAiIkqEprfJDsoNrvwFei3eCqKd1Y0tUsBimsq39BLp7RD+JWny3WgB1zGhJX8XVePwm9k4wdBg==
+  dependencies:
+    cssesc "^3.0.0"
+    indexes-of "^1.0.1"
+    uniq "^1.0.1"
+
+postcss-value-parser@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.0.0.tgz#99a983d365f7b2ad8d0f9b8c3094926eab4b936d"
+  integrity sha512-ESPktioptiSUchCKgggAkzdmkgzKfmp0EU8jXH+5kbIUB+unr0Y4CY9SRMvibuvYUBjNh1ACLbxqYNpdTQOteQ==
+
+postcss@^7.0.14, postcss@^7.0.16, postcss@^7.0.17, postcss@^7.0.5, postcss@^7.0.6:
+  version "7.0.17"
+  resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.17.tgz#4da1bdff5322d4a0acaab4d87f3e782436bad31f"
+  integrity sha512-546ZowA+KZ3OasvQZHsbuEpysvwTZNGJv9EfyCQdsIDltPSWHAeTQ5fQy/Npi2ZDtLI3zs7Ps/p6wThErhm9fQ==
+  dependencies:
+    chalk "^2.4.2"
+    source-map "^0.6.1"
+    supports-color "^6.1.0"
+
+prelude-ls@~1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
+  integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=
+
+prettier@1.16.3:
+  version "1.16.3"
+  resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.16.3.tgz#8c62168453badef702f34b45b6ee899574a6a65d"
+  integrity sha512-kn/GU6SMRYPxUakNXhpP0EedT/KmaPzr0H5lIsDogrykbaxOpOfAFfk5XA7DZrJyMAv1wlMV3CPcZruGXVVUZw==
+
+pretty-error@^2.0.2:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/pretty-error/-/pretty-error-2.1.1.tgz#5f4f87c8f91e5ae3f3ba87ab4cf5e03b1a17f1a3"
+  integrity sha1-X0+HyPkeWuPzuoerTPXgOxoX8aM=
+  dependencies:
+    renderkid "^2.0.1"
+    utila "~0.4"
+
+private@^0.1.6, private@~0.1.5:
+  version "0.1.8"
+  resolved "https://registry.yarnpkg.com/private/-/private-0.1.8.tgz#2381edb3689f7a53d653190060fcf822d2f368ff"
+  integrity sha512-VvivMrbvd2nKkiG38qjULzlc+4Vx4wm/whI9pQD35YrARNnhxeiRktSOhSukRLFNlzg6Br/cJPet5J/u19r/mg==
+
+process-nextick-args@~2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
+  integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
+
+process@^0.11.10:
+  version "0.11.10"
+  resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
+  integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI=
+
+progress@^2.0.0:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8"
+  integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==
+
+promise-inflight@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3"
+  integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM=
+
+proxy-addr@~2.0.5:
+  version "2.0.5"
+  resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.5.tgz#34cbd64a2d81f4b1fd21e76f9f06c8a45299ee34"
+  integrity sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ==
+  dependencies:
+    forwarded "~0.1.2"
+    ipaddr.js "1.9.0"
+
+prr@~1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476"
+  integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY=
+
+pseudomap@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3"
+  integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM=
+
+psl@^1.1.24, psl@^1.1.7:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/psl/-/psl-1.2.0.tgz#df12b5b1b3a30f51c329eacbdef98f3a6e136dc6"
+  integrity sha512-GEn74ZffufCmkDDLNcl3uuyF/aSD6exEyh1v/ZSdAomB82t6G9hzJVRx0jBmLDW+VfZqks3aScmMw9DszwUalA==
+
+public-encrypt@^4.0.0:
+  version "4.0.3"
+  resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0"
+  integrity sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==
+  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"
+    safe-buffer "^5.1.2"
+
+pump@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909"
+  integrity sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==
+  dependencies:
+    end-of-stream "^1.1.0"
+    once "^1.3.1"
+
+pump@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64"
+  integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==
+  dependencies:
+    end-of-stream "^1.1.0"
+    once "^1.3.1"
+
+pumpify@^1.3.3:
+  version "1.5.1"
+  resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce"
+  integrity sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==
+  dependencies:
+    duplexify "^3.6.0"
+    inherits "^2.0.3"
+    pump "^2.0.0"
+
+punycode@1.3.2:
+  version "1.3.2"
+  resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d"
+  integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=
+
+punycode@^1.2.4, punycode@^1.4.1:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
+  integrity sha1-wNWmOycYgArY4esPpSachN1BhF4=
+
+punycode@^2.1.0:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
+  integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==
+
+q@^1.1.2:
+  version "1.5.1"
+  resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7"
+  integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc=
+
+qs@6.7.0:
+  version "6.7.0"
+  resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc"
+  integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==
+
+qs@~6.5.2:
+  version "6.5.2"
+  resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
+  integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==
+
+querystring-es3@^0.2.0:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73"
+  integrity sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=
+
+querystring@0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620"
+  integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=
+
+querystringify@^2.1.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.1.1.tgz#60e5a5fd64a7f8bfa4d2ab2ed6fdf4c85bad154e"
+  integrity sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA==
+
+randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a"
+  integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==
+  dependencies:
+    safe-buffer "^5.1.0"
+
+randomfill@^1.0.3:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458"
+  integrity sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==
+  dependencies:
+    randombytes "^2.0.5"
+    safe-buffer "^5.1.0"
+
+range-parser@^1.2.1, range-parser@~1.2.1:
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
+  integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==
+
+raw-body@2.4.0:
+  version "2.4.0"
+  resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332"
+  integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q==
+  dependencies:
+    bytes "3.1.0"
+    http-errors "1.7.2"
+    iconv-lite "0.4.24"
+    unpipe "1.0.0"
+
+rc@^1.2.7:
+  version "1.2.8"
+  resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed"
+  integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==
+  dependencies:
+    deep-extend "^0.6.0"
+    ini "~1.3.0"
+    minimist "^1.2.0"
+    strip-json-comments "~2.0.1"
+
+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"
+  integrity sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=
+  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"
+  integrity sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=
+  dependencies:
+    load-json-file "^1.0.0"
+    normalize-package-data "^2.3.2"
+    path-type "^1.0.0"
+
+"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6:
+  version "2.3.6"
+  resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf"
+  integrity sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==
+  dependencies:
+    core-util-is "~1.0.0"
+    inherits "~2.0.3"
+    isarray "~1.0.0"
+    process-nextick-args "~2.0.0"
+    safe-buffer "~5.1.1"
+    string_decoder "~1.1.1"
+    util-deprecate "~1.0.1"
+
+readable-stream@^3.0.6, readable-stream@^3.1.1:
+  version "3.4.0"
+  resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.4.0.tgz#a51c26754658e0a3c21dbf59163bd45ba6f447fc"
+  integrity sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==
+  dependencies:
+    inherits "^2.0.3"
+    string_decoder "^1.1.1"
+    util-deprecate "^1.0.1"
+
+readdirp@^2.2.1:
+  version "2.2.1"
+  resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525"
+  integrity sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==
+  dependencies:
+    graceful-fs "^4.1.11"
+    micromatch "^3.1.10"
+    readable-stream "^2.0.2"
+
+recast@^0.11.17, recast@~0.11.12:
+  version "0.11.23"
+  resolved "https://registry.yarnpkg.com/recast/-/recast-0.11.23.tgz#451fd3004ab1e4df9b4e4b66376b2a21912462d3"
+  integrity sha1-RR/TAEqx5N+bTktmN2sqIZEkYtM=
+  dependencies:
+    ast-types "0.9.6"
+    esprima "~3.1.0"
+    private "~0.1.5"
+    source-map "~0.5.0"
+
+redent@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde"
+  integrity sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=
+  dependencies:
+    indent-string "^2.1.0"
+    strip-indent "^1.0.1"
+
+regenerate-unicode-properties@^8.0.2:
+  version "8.1.0"
+  resolved "https://registry.yarnpkg.com/regenerate-unicode-properties/-/regenerate-unicode-properties-8.1.0.tgz#ef51e0f0ea4ad424b77bf7cb41f3e015c70a3f0e"
+  integrity sha512-LGZzkgtLY79GeXLm8Dp0BVLdQlWICzBnJz/ipWUgo59qBaZ+BHtq51P2q1uVZlppMuUAT37SDk39qUbjTWB7bA==
+  dependencies:
+    regenerate "^1.4.0"
+
+regenerate@^1.4.0:
+  version "1.4.0"
+  resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.4.0.tgz#4a856ec4b56e4077c557589cae85e7a4c8869a11"
+  integrity sha512-1G6jJVDWrt0rK99kBjvEtziZNCICAuvIPkSiUFIQxVP06RCVpq3dmDo2oi6ABpYaDYaTRr67BEhL8r1wgEZZKg==
+
+regenerator-runtime@^0.11.0:
+  version "0.11.1"
+  resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.11.1.tgz#be05ad7f9bf7d22e056f9726cee5017fbf19e2e9"
+  integrity sha512-MguG95oij0fC3QV3URf4V2SDYGJhJnJGqvIIgdECeODCT98wSWDAJ94SSuVpYQUoTcGUIL6L4yNB7j1DFFHSBg==
+
+regenerator-runtime@^0.13.2:
+  version "0.13.2"
+  resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.2.tgz#32e59c9a6fb9b1a4aff09b4930ca2d4477343447"
+  integrity sha512-S/TQAZJO+D3m9xeN1WTI8dLKBBiRgXBlTJvbWjCThHWZj9EvHK70Ff50/tYj2J/fvBY6JtFVwRuazHN2E7M9BA==
+
+regenerator-transform@^0.14.0:
+  version "0.14.0"
+  resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.14.0.tgz#2ca9aaf7a2c239dd32e4761218425b8c7a86ecaf"
+  integrity sha512-rtOelq4Cawlbmq9xuMR5gdFmv7ku/sFoB7sRiywx7aq53bc52b4j6zvH7Te1Vt/X2YveDKnCGUbioieU7FEL3w==
+  dependencies:
+    private "^0.1.6"
+
+regex-not@^1.0.0, regex-not@^1.0.2:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c"
+  integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==
+  dependencies:
+    extend-shallow "^3.0.2"
+    safe-regex "^1.1.0"
+
+regexp-tree@^0.1.6:
+  version "0.1.11"
+  resolved "https://registry.yarnpkg.com/regexp-tree/-/regexp-tree-0.1.11.tgz#c9c7f00fcf722e0a56c7390983a7a63dd6c272f3"
+  integrity sha512-7/l/DgapVVDzZobwMCCgMlqiqyLFJ0cduo/j+3BcDJIB+yJdsYCfKuI3l/04NV+H/rfNRdPIDbXNZHM9XvQatg==
+
+regexpp@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-2.0.1.tgz#8d19d31cf632482b589049f8281f93dbcba4d07f"
+  integrity sha512-lv0M6+TkDVniA3aD1Eg0DVpfU/booSu7Eev3TDO/mZKHBfVjgCGTV4t4buppESEYDtkArYFOxTJWv6S5C+iaNw==
+
+regexpu-core@^4.5.4:
+  version "4.5.4"
+  resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-4.5.4.tgz#080d9d02289aa87fe1667a4f5136bc98a6aebaae"
+  integrity sha512-BtizvGtFQKGPUcTy56o3nk1bGRp4SZOTYrDtGNlqCQufptV5IkkLN6Emw+yunAJjzf+C9FQFtvq7IoA3+oMYHQ==
+  dependencies:
+    regenerate "^1.4.0"
+    regenerate-unicode-properties "^8.0.2"
+    regjsgen "^0.5.0"
+    regjsparser "^0.6.0"
+    unicode-match-property-ecmascript "^1.0.4"
+    unicode-match-property-value-ecmascript "^1.1.0"
+
+regjsgen@^0.5.0:
+  version "0.5.0"
+  resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.5.0.tgz#a7634dc08f89209c2049adda3525711fb97265dd"
+  integrity sha512-RnIrLhrXCX5ow/E5/Mh2O4e/oa1/jW0eaBKTSy3LaCj+M3Bqvm97GWDp2yUtzIs4LEn65zR2yiYGFqb2ApnzDA==
+
+regjsparser@^0.6.0:
+  version "0.6.0"
+  resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.6.0.tgz#f1e6ae8b7da2bae96c99399b868cd6c933a2ba9c"
+  integrity sha512-RQ7YyokLiQBomUJuUG8iGVvkgOLxwyZM8k6d3q5SAXpg4r5TZJZigKFvC6PpD+qQ98bCDC5YelPeA3EucDoNeQ==
+  dependencies:
+    jsesc "~0.5.0"
+
+relateurl@0.2.x:
+  version "0.2.7"
+  resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9"
+  integrity sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=
+
+remove-trailing-separator@^1.0.1:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef"
+  integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8=
+
+renderkid@^2.0.1:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/renderkid/-/renderkid-2.0.3.tgz#380179c2ff5ae1365c522bf2fcfcff01c5b74149"
+  integrity sha512-z8CLQp7EZBPCwCnncgf9C4XAi3WR0dv+uWu/PjIyhhAb5d6IJ/QZqlHFprHeKT+59//V6BNUsLbvN8+2LarxGA==
+  dependencies:
+    css-select "^1.1.0"
+    dom-converter "^0.2"
+    htmlparser2 "^3.3.0"
+    strip-ansi "^3.0.0"
+    utila "^0.4.0"
+
+repeat-element@^1.1.2:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce"
+  integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==
+
+repeat-string@^1.5.2, repeat-string@^1.6.1:
+  version "1.6.1"
+  resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637"
+  integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc=
+
+repeating@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda"
+  integrity sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=
+  dependencies:
+    is-finite "^1.0.0"
+
+request@^2.87.0, request@^2.88.0:
+  version "2.88.0"
+  resolved "https://registry.yarnpkg.com/request/-/request-2.88.0.tgz#9c2fca4f7d35b592efe57c7f0a55e81052124fef"
+  integrity sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==
+  dependencies:
+    aws-sign2 "~0.7.0"
+    aws4 "^1.8.0"
+    caseless "~0.12.0"
+    combined-stream "~1.0.6"
+    extend "~3.0.2"
+    forever-agent "~0.6.1"
+    form-data "~2.3.2"
+    har-validator "~5.1.0"
+    http-signature "~1.2.0"
+    is-typedarray "~1.0.0"
+    isstream "~0.1.2"
+    json-stringify-safe "~5.0.1"
+    mime-types "~2.1.19"
+    oauth-sign "~0.9.0"
+    performance-now "^2.1.0"
+    qs "~6.5.2"
+    safe-buffer "^5.1.2"
+    tough-cookie "~2.4.3"
+    tunnel-agent "^0.6.0"
+    uuid "^3.3.2"
+
+require-directory@^2.1.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42"
+  integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I=
+
+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"
+  integrity sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=
+
+require-main-filename@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b"
+  integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==
+
+requires-port@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff"
+  integrity sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=
+
+resolve-cwd@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a"
+  integrity sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=
+  dependencies:
+    resolve-from "^3.0.0"
+
+resolve-dir@^1.0.0, resolve-dir@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/resolve-dir/-/resolve-dir-1.0.1.tgz#79a40644c362be82f26effe739c9bb5382046f43"
+  integrity sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=
+  dependencies:
+    expand-tilde "^2.0.0"
+    global-modules "^1.0.0"
+
+resolve-from@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748"
+  integrity sha1-six699nWiBvItuZTM17rywoYh0g=
+
+resolve-from@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
+  integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==
+
+resolve-url@^0.2.1:
+  version "0.2.1"
+  resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a"
+  integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=
+
+resolve@^1.10.0, resolve@^1.3.2, resolve@^1.8.1:
+  version "1.11.1"
+  resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.11.1.tgz#ea10d8110376982fef578df8fc30b9ac30a07a3e"
+  integrity sha512-vIpgF6wfuJOZI7KKKSP+HmiKggadPQAdsp5HiC1mvqnfp0gF1vdwgBWZIdrVft9pgqoMFQN+R7BSWZiBxx+BBw==
+  dependencies:
+    path-parse "^1.0.6"
+
+restore-cursor@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf"
+  integrity sha1-n37ih/gv0ybU/RYpI9YhKe7g368=
+  dependencies:
+    onetime "^2.0.0"
+    signal-exit "^3.0.2"
+
+ret@~0.1.10:
+  version "0.1.15"
+  resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc"
+  integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==
+
+retry@^0.12.0:
+  version "0.12.0"
+  resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b"
+  integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=
+
+right-align@^0.1.1:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef"
+  integrity sha1-YTObci/mo1FWiSENJOFMlhSGE+8=
+  dependencies:
+    align-text "^0.1.1"
+
+rimraf@2, rimraf@2.6.3, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.3:
+  version "2.6.3"
+  resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab"
+  integrity sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==
+  dependencies:
+    glob "^7.1.3"
+
+ripemd160@^2.0.0, ripemd160@^2.0.1:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c"
+  integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==
+  dependencies:
+    hash-base "^3.0.0"
+    inherits "^2.0.1"
+
+run-async@^2.2.0:
+  version "2.3.0"
+  resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.3.0.tgz#0371ab4ae0bdd720d4166d7dfda64ff7a445a6c0"
+  integrity sha1-A3GrSuC91yDUFm19/aZP96RFpsA=
+  dependencies:
+    is-promise "^2.1.0"
+
+run-queue@^1.0.0, run-queue@^1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/run-queue/-/run-queue-1.0.3.tgz#e848396f057d223f24386924618e25694161ec47"
+  integrity sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=
+  dependencies:
+    aproba "^1.1.1"
+
+rxjs@^6.4.0:
+  version "6.5.2"
+  resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.2.tgz#2e35ce815cd46d84d02a209fb4e5921e051dbec7"
+  integrity sha512-HUb7j3kvb7p7eCUHE3FqjoDsC1xfZQ4AHFWfTKSpZ+sAhhz5X1WX0ZuUqWbzB2QhSLp3DoLUG+hMdEDKqWo2Zg==
+  dependencies:
+    tslib "^1.9.0"
+
+safe-buffer@5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
+  version "5.1.2"
+  resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
+  integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
+
+safe-buffer@>=5.1.0, safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2:
+  version "5.2.0"
+  resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519"
+  integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==
+
+safe-regex@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e"
+  integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4=
+  dependencies:
+    ret "~0.1.10"
+
+"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0:
+  version "2.1.2"
+  resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a"
+  integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==
+
+sass-graph@^2.2.4:
+  version "2.2.4"
+  resolved "https://registry.yarnpkg.com/sass-graph/-/sass-graph-2.2.4.tgz#13fbd63cd1caf0908b9fd93476ad43a51d1e0b49"
+  integrity sha1-E/vWPNHK8JCLn9k0dq1DpR0eC0k=
+  dependencies:
+    glob "^7.0.0"
+    lodash "^4.0.0"
+    scss-tokenizer "^0.2.3"
+    yargs "^7.0.0"
+
+sass-loader@^7.1.0:
+  version "7.1.0"
+  resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-7.1.0.tgz#16fd5138cb8b424bf8a759528a1972d72aad069d"
+  integrity sha512-+G+BKGglmZM2GUSfT9TLuEp6tzehHPjAMoRRItOojWIqIGPloVCMhNIQuG639eJ+y033PaGTSjLaTHts8Kw79w==
+  dependencies:
+    clone-deep "^2.0.1"
+    loader-utils "^1.0.1"
+    lodash.tail "^4.1.1"
+    neo-async "^2.5.0"
+    pify "^3.0.0"
+    semver "^5.5.0"
+
+sax@^1.2.4:
+  version "1.2.4"
+  resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
+  integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==
+
+schema-utils@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-1.0.0.tgz#0b79a93204d7b600d4b2850d1f66c2a34951c770"
+  integrity sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==
+  dependencies:
+    ajv "^6.1.0"
+    ajv-errors "^1.0.0"
+    ajv-keywords "^3.1.0"
+
+scss-tokenizer@^0.2.3:
+  version "0.2.3"
+  resolved "https://registry.yarnpkg.com/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz#8eb06db9a9723333824d3f5530641149847ce5d1"
+  integrity sha1-jrBtualyMzOCTT9VMGQRSYR85dE=
+  dependencies:
+    js-base64 "^2.1.8"
+    source-map "^0.4.2"
+
+select-hose@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/select-hose/-/select-hose-2.0.0.tgz#625d8658f865af43ec962bfc376a37359a4994ca"
+  integrity sha1-Yl2GWPhlr0Psliv8N2o3NZpJlMo=
+
+selfsigned@^1.10.4:
+  version "1.10.4"
+  resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-1.10.4.tgz#cdd7eccfca4ed7635d47a08bf2d5d3074092e2cd"
+  integrity sha512-9AukTiDmHXGXWtWjembZ5NDmVvP2695EtpgbCsxCa68w3c88B+alqbmZ4O3hZ4VWGXeGWzEVdvqgAJD8DQPCDw==
+  dependencies:
+    node-forge "0.7.5"
+
+"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0:
+  version "5.7.0"
+  resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.0.tgz#790a7cf6fea5459bac96110b29b60412dc8ff96b"
+  integrity sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==
+
+semver@^6.1.1:
+  version "6.2.0"
+  resolved "https://registry.yarnpkg.com/semver/-/semver-6.2.0.tgz#4d813d9590aaf8a9192693d6c85b9344de5901db"
+  integrity sha512-jdFC1VdUGT/2Scgbimf7FSx9iJLXoqfglSF+gJeuNWVpiE37OIbc1jywR/GJyFdz3mnkz2/id0L0J/cr0izR5A==
+
+semver@~5.3.0:
+  version "5.3.0"
+  resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f"
+  integrity sha1-myzl094C0XxgEq0yaqa00M9U+U8=
+
+send@0.17.1:
+  version "0.17.1"
+  resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8"
+  integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg==
+  dependencies:
+    debug "2.6.9"
+    depd "~1.1.2"
+    destroy "~1.0.4"
+    encodeurl "~1.0.2"
+    escape-html "~1.0.3"
+    etag "~1.8.1"
+    fresh "0.5.2"
+    http-errors "~1.7.2"
+    mime "1.6.0"
+    ms "2.1.1"
+    on-finished "~2.3.0"
+    range-parser "~1.2.1"
+    statuses "~1.5.0"
+
+sentence-case@^2.1.0:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/sentence-case/-/sentence-case-2.1.1.tgz#1f6e2dda39c168bf92d13f86d4a918933f667ed4"
+  integrity sha1-H24t2jnBaL+S0T+G1KkYkz9mftQ=
+  dependencies:
+    no-case "^2.2.0"
+    upper-case-first "^1.1.2"
+
+serialize-javascript@^1.7.0:
+  version "1.7.0"
+  resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-1.7.0.tgz#d6e0dfb2a3832a8c94468e6eb1db97e55a192a65"
+  integrity sha512-ke8UG8ulpFOxO8f8gRYabHQe/ZntKlcig2Mp+8+URDP1D8vJZ0KUt7LYo07q25Z/+JVSgpr/cui9PIp5H6/+nA==
+
+serve-index@^1.9.1:
+  version "1.9.1"
+  resolved "https://registry.yarnpkg.com/serve-index/-/serve-index-1.9.1.tgz#d3768d69b1e7d82e5ce050fff5b453bea12a9239"
+  integrity sha1-03aNabHn2C5c4FD/9bRTvqEqkjk=
+  dependencies:
+    accepts "~1.3.4"
+    batch "0.6.1"
+    debug "2.6.9"
+    escape-html "~1.0.3"
+    http-errors "~1.6.2"
+    mime-types "~2.1.17"
+    parseurl "~1.3.2"
+
+serve-static@1.14.1:
+  version "1.14.1"
+  resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9"
+  integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg==
+  dependencies:
+    encodeurl "~1.0.2"
+    escape-html "~1.0.3"
+    parseurl "~1.3.3"
+    send "0.17.1"
+
+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"
+  integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc=
+
+set-value@^2.0.0, set-value@^2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b"
+  integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==
+  dependencies:
+    extend-shallow "^2.0.1"
+    is-extendable "^0.1.1"
+    is-plain-object "^2.0.3"
+    split-string "^3.0.1"
+
+setimmediate@^1.0.4:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285"
+  integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=
+
+setprototypeof@1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.0.tgz#d0bd85536887b6fe7c0d818cb962d9d91c54e656"
+  integrity sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==
+
+setprototypeof@1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683"
+  integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==
+
+sha.js@^2.4.0, sha.js@^2.4.8:
+  version "2.4.11"
+  resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7"
+  integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==
+  dependencies:
+    inherits "^2.0.1"
+    safe-buffer "^5.0.1"
+
+shallow-clone@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-1.0.0.tgz#4480cd06e882ef68b2ad88a3ea54832e2c48b571"
+  integrity sha512-oeXreoKR/SyNJtRJMAKPDSvd28OqEwG4eR/xc856cRGBII7gX9lvAqDxusPm0846z/w/hWYjI1NpKwJ00NHzRA==
+  dependencies:
+    is-extendable "^0.1.1"
+    kind-of "^5.0.0"
+    mixin-object "^2.0.1"
+
+shebang-command@^1.2.0:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea"
+  integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=
+  dependencies:
+    shebang-regex "^1.0.0"
+
+shebang-regex@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3"
+  integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=
+
+signal-exit@^3.0.0, signal-exit@^3.0.2:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
+  integrity sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=
+
+slice-ansi@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-2.1.0.tgz#cacd7693461a637a5788d92a7dd4fba068e81636"
+  integrity sha512-Qu+VC3EwYLldKa1fCxuuvULvSJOKEgk9pi8dZeCVK7TqBfUNTH4sFkk4joj8afVSfAYgJoSOetjx9QWOJ5mYoQ==
+  dependencies:
+    ansi-styles "^3.2.0"
+    astral-regex "^1.0.0"
+    is-fullwidth-code-point "^2.0.0"
+
+snake-case@^2.1.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/snake-case/-/snake-case-2.1.0.tgz#41bdb1b73f30ec66a04d4e2cad1b76387d4d6d9f"
+  integrity sha1-Qb2xtz8w7GagTU4srRt2OH1NbZ8=
+  dependencies:
+    no-case "^2.2.0"
+
+snapdragon-node@^2.0.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b"
+  integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==
+  dependencies:
+    define-property "^1.0.0"
+    isobject "^3.0.0"
+    snapdragon-util "^3.0.1"
+
+snapdragon-util@^3.0.1:
+  version "3.0.1"
+  resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2"
+  integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==
+  dependencies:
+    kind-of "^3.2.0"
+
+snapdragon@^0.8.1:
+  version "0.8.2"
+  resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d"
+  integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==
+  dependencies:
+    base "^0.11.1"
+    debug "^2.2.0"
+    define-property "^0.2.5"
+    extend-shallow "^2.0.1"
+    map-cache "^0.2.2"
+    source-map "^0.5.6"
+    source-map-resolve "^0.5.0"
+    use "^3.1.0"
+
+sockjs-client@1.3.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/sockjs-client/-/sockjs-client-1.3.0.tgz#12fc9d6cb663da5739d3dc5fb6e8687da95cb177"
+  integrity sha512-R9jxEzhnnrdxLCNln0xg5uGHqMnkhPSTzUZH2eXcR03S/On9Yvoq2wyUZILRUhZCNVu2PmwWVoyuiPz8th8zbg==
+  dependencies:
+    debug "^3.2.5"
+    eventsource "^1.0.7"
+    faye-websocket "~0.11.1"
+    inherits "^2.0.3"
+    json3 "^3.3.2"
+    url-parse "^1.4.3"
+
+sockjs@0.3.19:
+  version "0.3.19"
+  resolved "https://registry.yarnpkg.com/sockjs/-/sockjs-0.3.19.tgz#d976bbe800af7bd20ae08598d582393508993c0d"
+  integrity sha512-V48klKZl8T6MzatbLlzzRNhMepEys9Y4oGFpypBFFn1gLI/QQ9HtLLyWJNbPlwGLelOVOEijUbTTJeLLI59jLw==
+  dependencies:
+    faye-websocket "^0.10.0"
+    uuid "^3.0.1"
+
+source-list-map@^2.0.0:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34"
+  integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==
+
+source-map-resolve@^0.5.0:
+  version "0.5.2"
+  resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.2.tgz#72e2cc34095543e43b2c62b2c4c10d4a9054f259"
+  integrity sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==
+  dependencies:
+    atob "^2.1.1"
+    decode-uri-component "^0.2.0"
+    resolve-url "^0.2.1"
+    source-map-url "^0.4.0"
+    urix "^0.1.0"
+
+source-map-support@~0.5.12:
+  version "0.5.12"
+  resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.12.tgz#b4f3b10d51857a5af0138d3ce8003b201613d599"
+  integrity sha512-4h2Pbvyy15EE02G+JOZpUCmqWJuqrs+sEkzewTm++BPi7Hvn/HwcqLAcNxYAyI0x13CpPPn+kMjl+hplXMHITQ==
+  dependencies:
+    buffer-from "^1.0.0"
+    source-map "^0.6.0"
+
+source-map-url@^0.4.0:
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3"
+  integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=
+
+source-map@0.4.x, source-map@^0.4.2:
+  version "0.4.4"
+  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b"
+  integrity sha1-66T12pwNyZneaAMti092FzZSA2s=
+  dependencies:
+    amdefine ">=0.0.4"
+
+source-map@^0.5.0, source-map@^0.5.6, source-map@~0.5.0, source-map@~0.5.1:
+  version "0.5.7"
+  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc"
+  integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=
+
+source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.0, source-map@~0.6.1:
+  version "0.6.1"
+  resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263"
+  integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==
+
+spdx-correct@^3.0.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.0.tgz#fb83e504445268f154b074e218c87c003cd31df4"
+  integrity sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==
+  dependencies:
+    spdx-expression-parse "^3.0.0"
+    spdx-license-ids "^3.0.0"
+
+spdx-exceptions@^2.1.0:
+  version "2.2.0"
+  resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz#2ea450aee74f2a89bfb94519c07fcd6f41322977"
+  integrity sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==
+
+spdx-expression-parse@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz#99e119b7a5da00e05491c9fa338b7904823b41d0"
+  integrity sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==
+  dependencies:
+    spdx-exceptions "^2.1.0"
+    spdx-license-ids "^3.0.0"
+
+spdx-license-ids@^3.0.0:
+  version "3.0.5"
+  resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz#3694b5804567a458d3c8045842a6358632f62654"
+  integrity sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==
+
+spdy-transport@^3.0.0:
+  version "3.0.0"
+  resolved "https://registry.yarnpkg.com/spdy-transport/-/spdy-transport-3.0.0.tgz#00d4863a6400ad75df93361a1608605e5dcdcf31"
+  integrity sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==
+  dependencies:
+    debug "^4.1.0"
+    detect-node "^2.0.4"
+    hpack.js "^2.1.6"
+    obuf "^1.1.2"
+    readable-stream "^3.0.6"
+    wbuf "^1.7.3"
+
+spdy@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/spdy/-/spdy-4.0.0.tgz#81f222b5a743a329aa12cea6a390e60e9b613c52"
+  integrity sha512-ot0oEGT/PGUpzf/6uk4AWLqkq+irlqHXkrdbk51oWONh3bxQmBuljxPNl66zlRRcIJStWq0QkLUCPOPjgjvU0Q==
+  dependencies:
+    debug "^4.1.0"
+    handle-thing "^2.0.0"
+    http-deceiver "^1.2.7"
+    select-hose "^2.0.0"
+    spdy-transport "^3.0.0"
+
+split-string@^3.0.1, split-string@^3.0.2:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2"
+  integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==
+  dependencies:
+    extend-shallow "^3.0.0"
+
+sprintf-js@~1.0.2:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c"
+  integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=
+
+sshpk@^1.7.0:
+  version "1.16.1"
+  resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877"
+  integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==
+  dependencies:
+    asn1 "~0.2.3"
+    assert-plus "^1.0.0"
+    bcrypt-pbkdf "^1.0.0"
+    dashdash "^1.12.0"
+    ecc-jsbn "~0.1.1"
+    getpass "^0.1.1"
+    jsbn "~0.1.0"
+    safer-buffer "^2.0.2"
+    tweetnacl "~0.14.0"
+
+ssri@^6.0.1:
+  version "6.0.1"
+  resolved "https://registry.yarnpkg.com/ssri/-/ssri-6.0.1.tgz#2a3c41b28dd45b62b63676ecb74001265ae9edd8"
+  integrity sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==
+  dependencies:
+    figgy-pudding "^3.5.1"
+
+static-extend@^0.1.1:
+  version "0.1.2"
+  resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6"
+  integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=
+  dependencies:
+    define-property "^0.2.5"
+    object-copy "^0.1.0"
+
+"statuses@>= 1.4.0 < 2", "statuses@>= 1.5.0 < 2", statuses@~1.5.0:
+  version "1.5.0"
+  resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
+  integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=
+
+stdout-stream@^1.4.0:
+  version "1.4.1"
+  resolved "https://registry.yarnpkg.com/stdout-stream/-/stdout-stream-1.4.1.tgz#5ac174cdd5cd726104aa0c0b2bd83815d8d535de"
+  integrity sha512-j4emi03KXqJWcIeF8eIXkjMFN1Cmb8gUlDYGeBALLPo5qdyTfA9bOtl8m33lRoC+vFMkP3gl0WsDr6+gzxbbTA==
+  dependencies:
+    readable-stream "^2.0.1"
+
+stream-browserify@^2.0.1:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.2.tgz#87521d38a44aa7ee91ce1cd2a47df0cb49dd660b"
+  integrity sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==
+  dependencies:
+    inherits "~2.0.1"
+    readable-stream "^2.0.2"
+
+stream-each@^1.1.0:
+  version "1.2.3"
+  resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.3.tgz#ebe27a0c389b04fbcc233642952e10731afa9bae"
+  integrity sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==
+  dependencies:
+    end-of-stream "^1.1.0"
+    stream-shift "^1.0.0"
+
+stream-http@^2.7.2:
+  version "2.8.3"
+  resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.3.tgz#b2d242469288a5a27ec4fe8933acf623de6514fc"
+  integrity sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==
+  dependencies:
+    builtin-status-codes "^3.0.0"
+    inherits "^2.0.1"
+    readable-stream "^2.3.6"
+    to-arraybuffer "^1.0.0"
+    xtend "^4.0.0"
+
+stream-shift@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952"
+  integrity sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=
+
+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"
+  integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=
+  dependencies:
+    code-point-at "^1.0.0"
+    is-fullwidth-code-point "^1.0.0"
+    strip-ansi "^3.0.0"
+
+"string-width@^1.0.2 || 2", string-width@^2.0.0, string-width@^2.1.0, string-width@^2.1.1:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e"
+  integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==
+  dependencies:
+    is-fullwidth-code-point "^2.0.0"
+    strip-ansi "^4.0.0"
+
+string-width@^3.0.0, string-width@^3.1.0:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961"
+  integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==
+  dependencies:
+    emoji-regex "^7.0.1"
+    is-fullwidth-code-point "^2.0.0"
+    strip-ansi "^5.1.0"
+
+string_decoder@^1.0.0, string_decoder@^1.1.1:
+  version "1.2.0"
+  resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.2.0.tgz#fe86e738b19544afe70469243b2a1ee9240eae8d"
+  integrity sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w==
+  dependencies:
+    safe-buffer "~5.1.0"
+
+string_decoder@~1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
+  integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==
+  dependencies:
+    safe-buffer "~5.1.0"
+
+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"
+  integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=
+  dependencies:
+    ansi-regex "^2.0.0"
+
+strip-ansi@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f"
+  integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8=
+  dependencies:
+    ansi-regex "^3.0.0"
+
+strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0:
+  version "5.2.0"
+  resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae"
+  integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==
+  dependencies:
+    ansi-regex "^4.1.0"
+
+strip-bom@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e"
+  integrity sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=
+  dependencies:
+    is-utf8 "^0.2.0"
+
+strip-eof@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
+  integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=
+
+strip-indent@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2"
+  integrity sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=
+  dependencies:
+    get-stdin "^4.0.1"
+
+strip-json-comments@^2.0.1, strip-json-comments@~2.0.1:
+  version "2.0.1"
+  resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a"
+  integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo=
+
+supports-color@6.1.0, supports-color@^6.1.0:
+  version "6.1.0"
+  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-6.1.0.tgz#0764abc69c63d5ac842dd4867e8d025e880df8f3"
+  integrity sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==
+  dependencies:
+    has-flag "^3.0.0"
+
+supports-color@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7"
+  integrity sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=
+
+supports-color@^5.3.0:
+  version "5.5.0"
+  resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f"
+  integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==
+  dependencies:
+    has-flag "^3.0.0"
+
+swap-case@^1.1.0:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/swap-case/-/swap-case-1.1.2.tgz#c39203a4587385fad3c850a0bd1bcafa081974e3"
+  integrity sha1-w5IDpFhzhfrTyFCgvRvK+ggZdOM=
+  dependencies:
+    lower-case "^1.1.1"
+    upper-case "^1.1.1"
+
+table@^5.2.3:
+  version "5.4.4"
+  resolved "https://registry.yarnpkg.com/table/-/table-5.4.4.tgz#6e0f88fdae3692793d1077fd172a4667afe986a6"
+  integrity sha512-IIfEAUx5QlODLblLrGTTLJA7Tk0iLSGBvgY8essPRVNGHAzThujww1YqHLs6h3HfTg55h++RzLHH5Xw/rfv+mg==
+  dependencies:
+    ajv "^6.10.2"
+    lodash "^4.17.14"
+    slice-ansi "^2.1.0"
+    string-width "^3.0.0"
+
+tapable@^1.0.0, tapable@^1.1.0:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2"
+  integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==
+
+tar@^2.0.0:
+  version "2.2.2"
+  resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.2.tgz#0ca8848562c7299b8b446ff6a4d60cdbb23edc40"
+  integrity sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA==
+  dependencies:
+    block-stream "*"
+    fstream "^1.0.12"
+    inherits "2"
+
+tar@^4:
+  version "4.4.10"
+  resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.10.tgz#946b2810b9a5e0b26140cf78bea6b0b0d689eba1"
+  integrity sha512-g2SVs5QIxvo6OLp0GudTqEf05maawKUxXru104iaayWA09551tFCTI8f1Asb4lPfkBr91k07iL4c11XO3/b0tA==
+  dependencies:
+    chownr "^1.1.1"
+    fs-minipass "^1.2.5"
+    minipass "^2.3.5"
+    minizlib "^1.2.1"
+    mkdirp "^0.5.0"
+    safe-buffer "^5.1.2"
+    yallist "^3.0.3"
+
+terser-webpack-plugin@^1.1.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.3.0.tgz#69aa22426299f4b5b3775cbed8cb2c5d419aa1d4"
+  integrity sha512-W2YWmxPjjkUcOWa4pBEv4OP4er1aeQJlSo2UhtCFQCuRXEHjOFscO8VyWHj9JLlA0RzQb8Y2/Ta78XZvT54uGg==
+  dependencies:
+    cacache "^11.3.2"
+    find-cache-dir "^2.0.0"
+    is-wsl "^1.1.0"
+    loader-utils "^1.2.3"
+    schema-utils "^1.0.0"
+    serialize-javascript "^1.7.0"
+    source-map "^0.6.1"
+    terser "^4.0.0"
+    webpack-sources "^1.3.0"
+    worker-farm "^1.7.0"
+
+terser@^4.0.0:
+  version "4.1.2"
+  resolved "https://registry.yarnpkg.com/terser/-/terser-4.1.2.tgz#b2656c8a506f7ce805a3f300a2ff48db022fa391"
+  integrity sha512-jvNoEQSPXJdssFwqPSgWjsOrb+ELoE+ILpHPKXC83tIxOlh2U75F1KuB2luLD/3a6/7K3Vw5pDn+hvu0C4AzSw==
+  dependencies:
+    commander "^2.20.0"
+    source-map "~0.6.1"
+    source-map-support "~0.5.12"
+
+text-table@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4"
+  integrity sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=
+
+through2@^2.0.0:
+  version "2.0.5"
+  resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd"
+  integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==
+  dependencies:
+    readable-stream "~2.3.6"
+    xtend "~4.0.1"
+
+through@^2.3.6, through@~2.3.4, through@~2.3.6:
+  version "2.3.8"
+  resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5"
+  integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=
+
+thunky@^1.0.2:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.0.3.tgz#f5df732453407b09191dae73e2a8cc73f381a826"
+  integrity sha512-YwT8pjmNcAXBZqrubu22P4FYsh2D4dxRmnWBOL8Jk8bUcRUtc5326kx32tuTmFDAZtLOGEVNl8POAR8j896Iow==
+
+timers-browserify@^2.0.4:
+  version "2.0.10"
+  resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.10.tgz#1d28e3d2aadf1d5a5996c4e9f95601cd053480ae"
+  integrity sha512-YvC1SV1XdOUaL6gx5CoGroT3Gu49pK9+TZ38ErPldOWW4j49GI1HKs9DV+KGq/w6y+LZ72W1c8cKz2vzY+qpzg==
+  dependencies:
+    setimmediate "^1.0.4"
+
+title-case@^2.1.0:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/title-case/-/title-case-2.1.1.tgz#3e127216da58d2bc5becf137ab91dae3a7cd8faa"
+  integrity sha1-PhJyFtpY0rxb7PE3q5Ha46fNj6o=
+  dependencies:
+    no-case "^2.2.0"
+    upper-case "^1.0.3"
+
+tmp@^0.0.33:
+  version "0.0.33"
+  resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9"
+  integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==
+  dependencies:
+    os-tmpdir "~1.0.2"
+
+to-arraybuffer@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43"
+  integrity sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=
+
+to-fast-properties@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e"
+  integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=
+
+to-object-path@^0.3.0:
+  version "0.3.0"
+  resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af"
+  integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=
+  dependencies:
+    kind-of "^3.0.2"
+
+to-regex-range@^2.1.0:
+  version "2.1.1"
+  resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38"
+  integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=
+  dependencies:
+    is-number "^3.0.0"
+    repeat-string "^1.6.1"
+
+to-regex@^3.0.1, to-regex@^3.0.2:
+  version "3.0.2"
+  resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce"
+  integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==
+  dependencies:
+    define-property "^2.0.2"
+    extend-shallow "^3.0.2"
+    regex-not "^1.0.2"
+    safe-regex "^1.1.0"
+
+toidentifier@1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553"
+  integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==
+
+toposort@^1.0.0:
+  version "1.0.7"
+  resolved "https://registry.yarnpkg.com/toposort/-/toposort-1.0.7.tgz#2e68442d9f64ec720b8cc89e6443ac6caa950029"
+  integrity sha1-LmhELZ9k7HILjMieZEOsbKqVACk=
+
+tough-cookie@~2.4.3:
+  version "2.4.3"
+  resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781"
+  integrity sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==
+  dependencies:
+    psl "^1.1.24"
+    punycode "^1.4.1"
+
+trim-newlines@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613"
+  integrity sha1-WIeWa7WCpFA6QetST301ARgVphM=
+
+trim-right@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003"
+  integrity sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=
+
+"true-case-path@^1.0.2":
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/true-case-path/-/true-case-path-1.0.3.tgz#f813b5a8c86b40da59606722b144e3225799f47d"
+  integrity sha512-m6s2OdQe5wgpFMC+pAJ+q9djG82O2jcHPOI6RNg1yy9rCYR+WD6Nbpl32fDpfC56nirdRy+opFa/Vk7HYhqaew==
+  dependencies:
+    glob "^7.1.2"
+
+tslib@^1.9.0:
+  version "1.10.0"
+  resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a"
+  integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==
+
+tty-browserify@0.0.0:
+  version "0.0.0"
+  resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6"
+  integrity sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=
+
+tunnel-agent@^0.6.0:
+  version "0.6.0"
+  resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd"
+  integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=
+  dependencies:
+    safe-buffer "^5.0.1"
+
+tweetnacl@^0.14.3, tweetnacl@~0.14.0:
+  version "0.14.5"
+  resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64"
+  integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=
+
+type-check@~0.3.2:
+  version "0.3.2"
+  resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72"
+  integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=
+  dependencies:
+    prelude-ls "~1.1.2"
+
+type-is@~1.6.17, type-is@~1.6.18:
+  version "1.6.18"
+  resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131"
+  integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==
+  dependencies:
+    media-typer "0.3.0"
+    mime-types "~2.1.24"
+
+typedarray@^0.0.6:
+  version "0.0.6"
+  resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777"
+  integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=
+
+uglify-js@2.6.x:
+  version "2.6.4"
+  resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.6.4.tgz#65ea2fb3059c9394692f15fed87c2b36c16b9adf"
+  integrity sha1-ZeovswWck5RpLxX+2HwrNsFrmt8=
+  dependencies:
+    async "~0.2.6"
+    source-map "~0.5.1"
+    uglify-to-browserify "~1.0.0"
+    yargs "~3.10.0"
+
+uglify-js@3.4.x:
+  version "3.4.10"
+  resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.4.10.tgz#9ad9563d8eb3acdfb8d38597d2af1d815f6a755f"
+  integrity sha512-Y2VsbPVs0FIshJztycsO2SfPk7/KAF/T72qzv9u5EpQ4kB2hQoHlhNQTsNyy6ul7lQtqJN/AoWeS23OzEiEFxw==
+  dependencies:
+    commander "~2.19.0"
+    source-map "~0.6.1"
+
+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"
+  integrity sha1-bgkk1r2mta/jSeOabWMoUKD4grc=
+
+unicode-canonical-property-names-ecmascript@^1.0.4:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818"
+  integrity sha512-jDrNnXWHd4oHiTZnx/ZG7gtUTVp+gCcTTKr8L0HjlwphROEW3+Him+IpvC+xcJEFegapiMZyZe02CyuOnRmbnQ==
+
+unicode-match-property-ecmascript@^1.0.4:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-1.0.4.tgz#8ed2a32569961bce9227d09cd3ffbb8fed5f020c"
+  integrity sha512-L4Qoh15vTfntsn4P1zqnHulG0LdXgjSO035fEpdtp6YxXhMT51Q6vgM5lYdG/5X3MjS+k/Y9Xw4SFCY9IkR0rg==
+  dependencies:
+    unicode-canonical-property-names-ecmascript "^1.0.4"
+    unicode-property-aliases-ecmascript "^1.0.4"
+
+unicode-match-property-value-ecmascript@^1.1.0:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-1.1.0.tgz#5b4b426e08d13a80365e0d657ac7a6c1ec46a277"
+  integrity sha512-hDTHvaBk3RmFzvSl0UVrUmC3PuW9wKVnpoUDYH0JDkSIovzw+J5viQmeYHxVSBptubnr7PbH2e0fnpDRQnQl5g==
+
+unicode-property-aliases-ecmascript@^1.0.4:
+  version "1.0.5"
+  resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.5.tgz#a9cc6cc7ce63a0a3023fc99e341b94431d405a57"
+  integrity sha512-L5RAqCfXqAwR3RriF8pM0lU0w4Ryf/GgzONwi6KnL1taJQa7x1TCxdJnILX59WIGOwR57IVxn7Nej0fz1Ny6fw==
+
+union-value@^1.0.0:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847"
+  integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==
+  dependencies:
+    arr-union "^3.1.0"
+    get-value "^2.0.6"
+    is-extendable "^0.1.1"
+    set-value "^2.0.1"
+
+uniq@^1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff"
+  integrity sha1-sxxa6CVIRKOoKBVBzisEuGWnNP8=
+
+unique-filename@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230"
+  integrity sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==
+  dependencies:
+    unique-slug "^2.0.0"
+
+unique-slug@^2.0.0:
+  version "2.0.2"
+  resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.2.tgz#baabce91083fc64e945b0f3ad613e264f7cd4e6c"
+  integrity sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==
+  dependencies:
+    imurmurhash "^0.1.4"
+
+unpipe@1.0.0, unpipe@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec"
+  integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=
+
+unset-value@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559"
+  integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=
+  dependencies:
+    has-value "^0.3.1"
+    isobject "^3.0.0"
+
+upath@^1.1.1:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/upath/-/upath-1.1.2.tgz#3db658600edaeeccbe6db5e684d67ee8c2acd068"
+  integrity sha512-kXpym8nmDmlCBr7nKdIx8P2jNBa+pBpIUFRnKJ4dr8htyYGJFokkr2ZvERRtUN+9SY+JqXouNgUPtv6JQva/2Q==
+
+upper-case-first@^1.1.0, upper-case-first@^1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/upper-case-first/-/upper-case-first-1.1.2.tgz#5d79bedcff14419518fd2edb0a0507c9b6859115"
+  integrity sha1-XXm+3P8UQZUY/S7bCgUHybaFkRU=
+  dependencies:
+    upper-case "^1.1.1"
+
+upper-case@^1.0.3, upper-case@^1.1.0, upper-case@^1.1.1, upper-case@^1.1.3:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-1.1.3.tgz#f6b4501c2ec4cdd26ba78be7222961de77621598"
+  integrity sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=
+
+uri-js@^4.2.2:
+  version "4.2.2"
+  resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0"
+  integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==
+  dependencies:
+    punycode "^2.1.0"
+
+urix@^0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72"
+  integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=
+
+url-parse@^1.4.3:
+  version "1.4.7"
+  resolved "https://registry.yarnpkg.com/url-parse/-/url-parse-1.4.7.tgz#a8a83535e8c00a316e403a5db4ac1b9b853ae278"
+  integrity sha512-d3uaVyzDB9tQoSXFvuSUNFibTd9zxd2bkVrDRvF5TmvWWQwqE4lgYJ5m+x1DbecWkw+LK4RNl2CU1hHuOKPVlg==
+  dependencies:
+    querystringify "^2.1.1"
+    requires-port "^1.0.0"
+
+url@^0.11.0:
+  version "0.11.0"
+  resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1"
+  integrity sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=
+  dependencies:
+    punycode "1.3.2"
+    querystring "0.2.0"
+
+use@^3.1.0:
+  version "3.1.1"
+  resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f"
+  integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==
+
+util-deprecate@^1.0.1, util-deprecate@~1.0.1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
+  integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
+
+util.promisify@1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/util.promisify/-/util.promisify-1.0.0.tgz#440f7165a459c9a16dc145eb8e72f35687097030"
+  integrity sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==
+  dependencies:
+    define-properties "^1.1.2"
+    object.getownpropertydescriptors "^2.0.3"
+
+util@0.10.3:
+  version "0.10.3"
+  resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9"
+  integrity sha1-evsa/lCAUkZInj23/g7TeTNqwPk=
+  dependencies:
+    inherits "2.0.1"
+
+util@^0.11.0:
+  version "0.11.1"
+  resolved "https://registry.yarnpkg.com/util/-/util-0.11.1.tgz#3236733720ec64bb27f6e26f421aaa2e1b588d61"
+  integrity sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==
+  dependencies:
+    inherits "2.0.3"
+
+utila@^0.4.0, utila@~0.4:
+  version "0.4.0"
+  resolved "https://registry.yarnpkg.com/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c"
+  integrity sha1-ihagXURWV6Oupe7MWxKk+lN5dyw=
+
+utils-merge@1.0.1:
+  version "1.0.1"
+  resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713"
+  integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=
+
+uuid@^3.0.1, uuid@^3.3.2:
+  version "3.3.2"
+  resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.2.tgz#1b4af4955eb3077c501c23872fc6513811587131"
+  integrity sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==
+
+v8-compile-cache@2.0.3:
+  version "2.0.3"
+  resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.0.3.tgz#00f7494d2ae2b688cfe2899df6ed2c54bef91dbe"
+  integrity sha512-CNmdbwQMBjwr9Gsmohvm0pbL954tJrNzf6gWL3K+QMQf00PF7ERGrEiLgjuU3mKreLC2MeGhUsNV9ybTbLgd3w==
+
+validate-npm-package-license@^3.0.1:
+  version "3.0.4"
+  resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a"
+  integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==
+  dependencies:
+    spdx-correct "^3.0.0"
+    spdx-expression-parse "^3.0.0"
+
+vary@~1.1.2:
+  version "1.1.2"
+  resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
+  integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=
+
+verror@1.10.0:
+  version "1.10.0"
+  resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400"
+  integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=
+  dependencies:
+    assert-plus "^1.0.0"
+    core-util-is "1.0.2"
+    extsprintf "^1.2.0"
+
+vm-browserify@^1.0.1:
+  version "1.1.0"
+  resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.0.tgz#bd76d6a23323e2ca8ffa12028dc04559c75f9019"
+  integrity sha512-iq+S7vZJE60yejDYM0ek6zg308+UZsdtPExWP9VZoCFCz1zkJoXFnAX7aZfd/ZwrkidzdUZL0C/ryW+JwAiIGw==
+
+vue-hot-reload-api@^2.3.0, vue-hot-reload-api@^2.3.3:
+  version "2.3.3"
+  resolved "https://registry.yarnpkg.com/vue-hot-reload-api/-/vue-hot-reload-api-2.3.3.tgz#2756f46cb3258054c5f4723de8ae7e87302a1ccf"
+  integrity sha512-KmvZVtmM26BQOMK1rwUZsrqxEGeKiYSZGA7SNWE6uExx8UX/cj9hq2MRV/wWC3Cq6AoeDGk57rL9YMFRel/q+g==
+
+vue-html-loader@^1.2.4:
+  version "1.2.4"
+  resolved "https://registry.yarnpkg.com/vue-html-loader/-/vue-html-loader-1.2.4.tgz#54ce489be06065c91dc2a1173122f3e004e0a253"
+  integrity sha1-VM5Im+BgZckdwqEXMSLz4ATgolM=
+  dependencies:
+    es6-templates "^0.2.2"
+    fastparse "^1.0.0"
+    html-minifier "^2.1.5"
+    loader-utils "^1.0.2"
+    object-assign "^4.1.0"
+
+vue-loader@^15.7.0:
+  version "15.7.0"
+  resolved "https://registry.yarnpkg.com/vue-loader/-/vue-loader-15.7.0.tgz#27275aa5a3ef4958c5379c006dd1436ad04b25b3"
+  integrity sha512-x+NZ4RIthQOxcFclEcs8sXGEWqnZHodL2J9Vq+hUz+TDZzBaDIh1j3d9M2IUlTjtrHTZy4uMuRdTi8BGws7jLA==
+  dependencies:
+    "@vue/component-compiler-utils" "^2.5.1"
+    hash-sum "^1.0.2"
+    loader-utils "^1.1.0"
+    vue-hot-reload-api "^2.3.0"
+    vue-style-loader "^4.1.0"
+
+vue-roaster@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/vue-roaster/-/vue-roaster-1.1.1.tgz#4718300137862e621e8d7f9130c6dacb5989ca1a"
+  integrity sha1-RxgwATeGLmIejX+RMMbay1mJyho=
+  dependencies:
+    babel-runtime "^6.0.0"
+    jquery "^3.1.1"
+    jquery-ui "^1.12.1"
+    vue "^1.0.0"
+
+vue-router@^3.0.7:
+  version "3.0.7"
+  resolved "https://registry.yarnpkg.com/vue-router/-/vue-router-3.0.7.tgz#b36ca107b4acb8ff5bc4ff824584059c23fcb87b"
+  integrity sha512-utJ+QR3YlIC/6x6xq17UMXeAfxEvXA0VKD3PiSio7hBOZNusA1jXcbxZxVEfJunLp48oonjTepY8ORoIlRx/EQ==
+
+vue-style-loader@^4.1.0, vue-style-loader@^4.1.2:
+  version "4.1.2"
+  resolved "https://registry.yarnpkg.com/vue-style-loader/-/vue-style-loader-4.1.2.tgz#dedf349806f25ceb4e64f3ad7c0a44fba735fcf8"
+  integrity sha512-0ip8ge6Gzz/Bk0iHovU9XAUQaFt/G2B61bnWa2tCcqqdgfHs1lF9xXorFbE55Gmy92okFT+8bfmySuUOu13vxQ==
+  dependencies:
+    hash-sum "^1.0.2"
+    loader-utils "^1.0.2"
+
+vue-template-compiler@^2.6.10:
+  version "2.6.10"
+  resolved "https://registry.yarnpkg.com/vue-template-compiler/-/vue-template-compiler-2.6.10.tgz#323b4f3495f04faa3503337a82f5d6507799c9cc"
+  integrity sha512-jVZkw4/I/HT5ZMvRnhv78okGusqe0+qH2A0Em0Cp8aq78+NK9TII263CDVz2QXZsIT+yyV/gZc/j/vlwa+Epyg==
+  dependencies:
+    de-indent "^1.0.2"
+    he "^1.1.0"
+
+vue-template-es2015-compiler@^1.9.0:
+  version "1.9.1"
+  resolved "https://registry.yarnpkg.com/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz#1ee3bc9a16ecbf5118be334bb15f9c46f82f5825"
+  integrity sha512-4gDntzrifFnCEvyoO8PqyJDmguXgVPxKiIxrBKjIowvL9l+N66196+72XVYR8BBf1Uv1Fgt3bGevJ+sEmxfZzw==
+
+vue@^1.0.0:
+  version "1.0.28"
+  resolved "https://registry.yarnpkg.com/vue/-/vue-1.0.28.tgz#ed2ff07b200bde15c87a90ef8727ceea7d38567d"
+  integrity sha1-7S/weyAL3hXIepDvhyfO6n04Vn0=
+  dependencies:
+    envify "^3.4.0"
+
+vue@^2.6.10:
+  version "2.6.10"
+  resolved "https://registry.yarnpkg.com/vue/-/vue-2.6.10.tgz#a72b1a42a4d82a721ea438d1b6bf55e66195c637"
+  integrity sha512-ImThpeNU9HbdZL3utgMCq0oiMzAkt1mcgy3/E6zWC/G6AaQoeuFdsl9nDhTDU3X1R6FK7nsIUuRACVcjI+A2GQ==
+
+vuex@^3.1.1:
+  version "3.1.1"
+  resolved "https://registry.yarnpkg.com/vuex/-/vuex-3.1.1.tgz#0c264bfe30cdbccf96ab9db3177d211828a5910e"
+  integrity sha512-ER5moSbLZuNSMBFnEBVGhQ1uCBNJslH9W/Dw2W7GZN23UQA69uapP5GTT9Vm8Trc0PzBSVt6LzF3hGjmv41xcg==
+
+watchpack@^1.5.0:
+  version "1.6.0"
+  resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.6.0.tgz#4bc12c2ebe8aa277a71f1d3f14d685c7b446cd00"
+  integrity sha512-i6dHe3EyLjMmDlU1/bGQpEw25XSjkJULPuAVKCbNRefQVq48yXKUpwg538F7AZTf9kyr57zj++pQFltUa5H7yA==
+  dependencies:
+    chokidar "^2.0.2"
+    graceful-fs "^4.1.2"
+    neo-async "^2.5.0"
+
+wbuf@^1.1.0, wbuf@^1.7.3:
+  version "1.7.3"
+  resolved "https://registry.yarnpkg.com/wbuf/-/wbuf-1.7.3.tgz#c1d8d149316d3ea852848895cb6a0bfe887b87df"
+  integrity sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==
+  dependencies:
+    minimalistic-assert "^1.0.0"
+
+webpack-cli@^3.3.5:
+  version "3.3.5"
+  resolved "https://registry.yarnpkg.com/webpack-cli/-/webpack-cli-3.3.5.tgz#f4d1238a66a2843d9cebf189835ea22142e72767"
+  integrity sha512-w0j/s42c5UhchwTmV/45MLQnTVwRoaUTu9fM5LuyOd/8lFoCNCELDogFoecx5NzRUndO0yD/gF2b02XKMnmAWQ==
+  dependencies:
+    chalk "2.4.2"
+    cross-spawn "6.0.5"
+    enhanced-resolve "4.1.0"
+    findup-sync "3.0.0"
+    global-modules "2.0.0"
+    import-local "2.0.0"
+    interpret "1.2.0"
+    loader-utils "1.2.3"
+    supports-color "6.1.0"
+    v8-compile-cache "2.0.3"
+    yargs "13.2.4"
+
+webpack-dev-middleware@^3.7.0:
+  version "3.7.0"
+  resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-3.7.0.tgz#ef751d25f4e9a5c8a35da600c5fda3582b5c6cff"
+  integrity sha512-qvDesR1QZRIAZHOE3iQ4CXLZZSQ1lAUsSpnQmlB1PBfoN/xdRjmge3Dok0W4IdaVLJOGJy3sGI4sZHwjRU0PCA==
+  dependencies:
+    memory-fs "^0.4.1"
+    mime "^2.4.2"
+    range-parser "^1.2.1"
+    webpack-log "^2.0.0"
+
+webpack-dev-server@^3.7.2:
+  version "3.7.2"
+  resolved "https://registry.yarnpkg.com/webpack-dev-server/-/webpack-dev-server-3.7.2.tgz#f79caa5974b7f8b63268ef5421222a8486d792f5"
+  integrity sha512-mjWtrKJW2T9SsjJ4/dxDC2fkFVUw8jlpemDERqV0ZJIkjjjamR2AbQlr3oz+j4JLhYCHImHnXZK5H06P2wvUew==
+  dependencies:
+    ansi-html "0.0.7"
+    bonjour "^3.5.0"
+    chokidar "^2.1.6"
+    compression "^1.7.4"
+    connect-history-api-fallback "^1.6.0"
+    debug "^4.1.1"
+    del "^4.1.1"
+    express "^4.17.1"
+    html-entities "^1.2.1"
+    http-proxy-middleware "^0.19.1"
+    import-local "^2.0.0"
+    internal-ip "^4.3.0"
+    ip "^1.1.5"
+    killable "^1.0.1"
+    loglevel "^1.6.3"
+    opn "^5.5.0"
+    p-retry "^3.0.1"
+    portfinder "^1.0.20"
+    schema-utils "^1.0.0"
+    selfsigned "^1.10.4"
+    semver "^6.1.1"
+    serve-index "^1.9.1"
+    sockjs "0.3.19"
+    sockjs-client "1.3.0"
+    spdy "^4.0.0"
+    strip-ansi "^3.0.1"
+    supports-color "^6.1.0"
+    url "^0.11.0"
+    webpack-dev-middleware "^3.7.0"
+    webpack-log "^2.0.0"
+    yargs "12.0.5"
+
+webpack-log@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/webpack-log/-/webpack-log-2.0.0.tgz#5b7928e0637593f119d32f6227c1e0ac31e1b47f"
+  integrity sha512-cX8G2vR/85UYG59FgkoMamwHUIkSSlV3bBMRsbxVXVUk2j6NleCKjQ/WE9eYg9WY4w25O9w8wKP4rzNZFmUcUg==
+  dependencies:
+    ansi-colors "^3.0.0"
+    uuid "^3.3.2"
+
+webpack-md5-hash@0.0.6:
+  version "0.0.6"
+  resolved "https://registry.yarnpkg.com/webpack-md5-hash/-/webpack-md5-hash-0.0.6.tgz#317b766a0a724eb5501610b3c8f4cddc4edf70f5"
+  integrity sha512-HrQ0AJpeXHRa3IjsgyyEfTx8EqYs5y/4x/WklSYsNDcqBixHzCkrmJV5U+4ks+sx7ycKoIdqWLdyuk913FCS+Q==
+  dependencies:
+    md5 "^2.0.0"
+
+webpack-sources@^1.3.0:
+  version "1.3.0"
+  resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.3.0.tgz#2a28dcb9f1f45fe960d8f1493252b5ee6530fa85"
+  integrity sha512-OiVgSrbGu7NEnEvQJJgdSFPl2qWKkWq5lHMhgiToIiN9w34EBnjYzSYs+VbL5KoYiLNtFFa7BZIKxRED3I32pA==
+  dependencies:
+    source-list-map "^2.0.0"
+    source-map "~0.6.1"
+
+webpack@^4.35.3:
+  version "4.35.3"
+  resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.35.3.tgz#66bc35ef215a7b75e8790f84d560013ffecf0ca3"
+  integrity sha512-xggQPwr9ILlXzz61lHzjvgoqGU08v5+Wnut19Uv3GaTtzN4xBTcwnobodrXE142EL1tOiS5WVEButooGzcQzTA==
+  dependencies:
+    "@webassemblyjs/ast" "1.8.5"
+    "@webassemblyjs/helper-module-context" "1.8.5"
+    "@webassemblyjs/wasm-edit" "1.8.5"
+    "@webassemblyjs/wasm-parser" "1.8.5"
+    acorn "^6.2.0"
+    ajv "^6.1.0"
+    ajv-keywords "^3.1.0"
+    chrome-trace-event "^1.0.0"
+    enhanced-resolve "^4.1.0"
+    eslint-scope "^4.0.0"
+    json-parse-better-errors "^1.0.2"
+    loader-runner "^2.3.0"
+    loader-utils "^1.1.0"
+    memory-fs "~0.4.1"
+    micromatch "^3.1.8"
+    mkdirp "~0.5.0"
+    neo-async "^2.5.0"
+    node-libs-browser "^2.0.0"
+    schema-utils "^1.0.0"
+    tapable "^1.1.0"
+    terser-webpack-plugin "^1.1.0"
+    watchpack "^1.5.0"
+    webpack-sources "^1.3.0"
+
+websocket-driver@>=0.5.1:
+  version "0.7.3"
+  resolved "https://registry.yarnpkg.com/websocket-driver/-/websocket-driver-0.7.3.tgz#a2d4e0d4f4f116f1e6297eba58b05d430100e9f9"
+  integrity sha512-bpxWlvbbB459Mlipc5GBzzZwhoZgGEZLuqPaR0INBGnPAY1vdBX6hPnoFXiw+3yWxDuHyQjO2oXTMyS8A5haFg==
+  dependencies:
+    http-parser-js ">=0.4.0 <0.4.11"
+    safe-buffer ">=5.1.0"
+    websocket-extensions ">=0.1.1"
+
+websocket-extensions@>=0.1.1:
+  version "0.1.3"
+  resolved "https://registry.yarnpkg.com/websocket-extensions/-/websocket-extensions-0.1.3.tgz#5d2ff22977003ec687a4b87073dfbbac146ccf29"
+  integrity sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg==
+
+which-module@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f"
+  integrity sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=
+
+which-module@^2.0.0:
+  version "2.0.0"
+  resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a"
+  integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=
+
+which@1, which@^1.2.14, which@^1.2.9, which@^1.3.1:
+  version "1.3.1"
+  resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
+  integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==
+  dependencies:
+    isexe "^2.0.0"
+
+wide-align@^1.1.0:
+  version "1.1.3"
+  resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457"
+  integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==
+  dependencies:
+    string-width "^1.0.2 || 2"
+
+window-size@0.1.0:
+  version "0.1.0"
+  resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d"
+  integrity sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=
+
+wordwrap@0.0.2:
+  version "0.0.2"
+  resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f"
+  integrity sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=
+
+wordwrap@~1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb"
+  integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=
+
+worker-farm@^1.7.0:
+  version "1.7.0"
+  resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.7.0.tgz#26a94c5391bbca926152002f69b84a4bf772e5a8"
+  integrity sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==
+  dependencies:
+    errno "~0.1.7"
+
+wrap-ansi@^2.0.0:
+  version "2.1.0"
+  resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85"
+  integrity sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=
+  dependencies:
+    string-width "^1.0.1"
+    strip-ansi "^3.0.1"
+
+wrap-ansi@^5.1.0:
+  version "5.1.0"
+  resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09"
+  integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==
+  dependencies:
+    ansi-styles "^3.2.0"
+    string-width "^3.0.0"
+    strip-ansi "^5.0.0"
+
+wrappy@1:
+  version "1.0.2"
+  resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f"
+  integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=
+
+write@1.0.3:
+  version "1.0.3"
+  resolved "https://registry.yarnpkg.com/write/-/write-1.0.3.tgz#0800e14523b923a387e415123c865616aae0f5c3"
+  integrity sha512-/lg70HAjtkUgWPVZhZcm+T4hkL8Zbtp1nFNOn3lRrxnlv50SRBv7cR7RqR+GMsd3hUXy9hWBo4CHTbFTcOYwig==
+  dependencies:
+    mkdirp "^0.5.1"
+
+xml-char-classes@^1.0.0:
+  version "1.0.0"
+  resolved "https://registry.yarnpkg.com/xml-char-classes/-/xml-char-classes-1.0.0.tgz#64657848a20ffc5df583a42ad8a277b4512bbc4d"
+  integrity sha1-ZGV4SKIP/F31g6Qq2KJ3tFErvE0=
+
+xtend@^4.0.0, xtend@~4.0.1:
+  version "4.0.2"
+  resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54"
+  integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
+
+y18n@^3.2.1:
+  version "3.2.1"
+  resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41"
+  integrity sha1-bRX7qITAhnnA136I53WegR4H+kE=
+
+"y18n@^3.2.1 || ^4.0.0", y18n@^4.0.0:
+  version "4.0.0"
+  resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b"
+  integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==
+
+yallist@^2.1.2:
+  version "2.1.2"
+  resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52"
+  integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=
+
+yallist@^3.0.0, yallist@^3.0.2, yallist@^3.0.3:
+  version "3.0.3"
+  resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.3.tgz#b4b049e314be545e3ce802236d6cd22cd91c3de9"
+  integrity sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==
+
+yargs-parser@^11.1.1:
+  version "11.1.1"
+  resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-11.1.1.tgz#879a0865973bca9f6bab5cbdf3b1c67ec7d3bcf4"
+  integrity sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==
+  dependencies:
+    camelcase "^5.0.0"
+    decamelize "^1.2.0"
+
+yargs-parser@^13.1.0:
+  version "13.1.1"
+  resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-13.1.1.tgz#d26058532aa06d365fe091f6a1fc06b2f7e5eca0"
+  integrity sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==
+  dependencies:
+    camelcase "^5.0.0"
+    decamelize "^1.2.0"
+
+yargs-parser@^5.0.0:
+  version "5.0.0"
+  resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-5.0.0.tgz#275ecf0d7ffe05c77e64e7c86e4cd94bf0e1228a"
+  integrity sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo=
+  dependencies:
+    camelcase "^3.0.0"
+
+yargs@12.0.5:
+  version "12.0.5"
+  resolved "https://registry.yarnpkg.com/yargs/-/yargs-12.0.5.tgz#05f5997b609647b64f66b81e3b4b10a368e7ad13"
+  integrity sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==
+  dependencies:
+    cliui "^4.0.0"
+    decamelize "^1.2.0"
+    find-up "^3.0.0"
+    get-caller-file "^1.0.1"
+    os-locale "^3.0.0"
+    require-directory "^2.1.1"
+    require-main-filename "^1.0.1"
+    set-blocking "^2.0.0"
+    string-width "^2.0.0"
+    which-module "^2.0.0"
+    y18n "^3.2.1 || ^4.0.0"
+    yargs-parser "^11.1.1"
+
+yargs@13.2.4:
+  version "13.2.4"
+  resolved "https://registry.yarnpkg.com/yargs/-/yargs-13.2.4.tgz#0b562b794016eb9651b98bd37acf364aa5d6dc83"
+  integrity sha512-HG/DWAJa1PAnHT9JAhNa8AbAv3FPaiLzioSjCcmuXXhP8MlpHO5vwls4g4j6n30Z74GVQj8Xa62dWVx1QCGklg==
+  dependencies:
+    cliui "^5.0.0"
+    find-up "^3.0.0"
+    get-caller-file "^2.0.1"
+    os-locale "^3.1.0"
+    require-directory "^2.1.1"
+    require-main-filename "^2.0.0"
+    set-blocking "^2.0.0"
+    string-width "^3.0.0"
+    which-module "^2.0.0"
+    y18n "^4.0.0"
+    yargs-parser "^13.1.0"
+
+yargs@^7.0.0:
+  version "7.1.0"
+  resolved "https://registry.yarnpkg.com/yargs/-/yargs-7.1.0.tgz#6ba318eb16961727f5d284f8ea003e8d6154d0c8"
+  integrity sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg=
+  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 "^5.0.0"
+
+yargs@~3.10.0:
+  version "3.10.0"
+  resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1"
+  integrity sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=
+  dependencies:
+    camelcase "^1.0.2"
+    cliui "^2.1.0"
+    decamelize "^1.0.0"
+    window-size "0.1.0"