Переглянути джерело

feat: GraphQL translations + login form

NGPixel 7 роки тому
батько
коміт
32b7947704

+ 23 - 20
client/js/app.js

@@ -6,10 +6,14 @@
 import Vue from 'vue'
 import Vue from 'vue'
 import VueResource from 'vue-resource'
 import VueResource from 'vue-resource'
 import VueClipboards from 'vue-clipboards'
 import VueClipboards from 'vue-clipboards'
+import { ApolloClient, createBatchingNetworkInterface } from 'apollo-client'
 import store from './store'
 import store from './store'
-import i18next from 'i18next'
-import i18nextXHR from 'i18next-xhr-backend'
-import VueI18Next from '@panter/vue-i18next'
+
+// ====================================
+// Load Modules
+// ====================================
+
+import localization from './modules/localization'
 
 
 // ====================================
 // ====================================
 // Load Helpers
 // Load Helpers
@@ -29,6 +33,7 @@ import editorFileComponent from './components/editor-file.vue'
 import editorVideoComponent from './components/editor-video.vue'
 import editorVideoComponent from './components/editor-video.vue'
 import historyComponent from './components/history.vue'
 import historyComponent from './components/history.vue'
 import loadingSpinnerComponent from './components/loading-spinner.vue'
 import loadingSpinnerComponent from './components/loading-spinner.vue'
+import loginComponent from './components/login.vue'
 import modalCreatePageComponent from './components/modal-create-page.vue'
 import modalCreatePageComponent from './components/modal-create-page.vue'
 import modalCreateUserComponent from './components/modal-create-user.vue'
 import modalCreateUserComponent from './components/modal-create-user.vue'
 import modalDeleteUserComponent from './components/modal-delete-user.vue'
 import modalDeleteUserComponent from './components/modal-delete-user.vue'
@@ -49,13 +54,24 @@ import contentViewComponent from './pages/content-view.component.js'
 import editorComponent from './components/editor.component.js'
 import editorComponent from './components/editor.component.js'
 import sourceViewComponent from './pages/source-view.component.js'
 import sourceViewComponent from './pages/source-view.component.js'
 
 
+// ====================================
+// Initialize Apollo Client (GraphQL)
+// ====================================
+
+window.apollo = new ApolloClient({
+  networkInterface: createBatchingNetworkInterface({
+    uri: window.location.protocol + '//' + window.location.host + siteConfig.path + '/graphql'
+  }),
+  connectToDevTools: true
+})
+
 // ====================================
 // ====================================
 // Initialize Vue Modules
 // Initialize Vue Modules
 // ====================================
 // ====================================
 
 
 Vue.use(VueResource)
 Vue.use(VueResource)
 Vue.use(VueClipboards)
 Vue.use(VueClipboards)
-Vue.use(VueI18Next)
+Vue.use(localization.VueI18Next)
 Vue.use(helpers)
 Vue.use(helpers)
 
 
 // ====================================
 // ====================================
@@ -76,6 +92,7 @@ Vue.component('editorFile', editorFileComponent)
 Vue.component('editorVideo', editorVideoComponent)
 Vue.component('editorVideo', editorVideoComponent)
 Vue.component('history', historyComponent)
 Vue.component('history', historyComponent)
 Vue.component('loadingSpinner', loadingSpinnerComponent)
 Vue.component('loadingSpinner', loadingSpinnerComponent)
+Vue.component('login', loginComponent)
 Vue.component('modalCreatePage', modalCreatePageComponent)
 Vue.component('modalCreatePage', modalCreatePageComponent)
 Vue.component('modalCreateUser', modalCreateUserComponent)
 Vue.component('modalCreateUser', modalCreateUserComponent)
 Vue.component('modalDeleteUser', modalDeleteUserComponent)
 Vue.component('modalDeleteUser', modalDeleteUserComponent)
@@ -89,20 +106,6 @@ Vue.component('sourceView', sourceViewComponent)
 Vue.component('toggle', toggleComponent)
 Vue.component('toggle', toggleComponent)
 Vue.component('tree', treeComponent)
 Vue.component('tree', treeComponent)
 
 
-// ====================================
-// Load Localization strings
-// ====================================
-
-i18next
-  .use(i18nextXHR)
-  .init({
-    backend: {
-      loadPath: siteConfig.path + '/js/i18n/{{lng}}.json'
-    },
-    lng: siteConfig.lang,
-    fallbackLng: siteConfig.lang
-  })
-
 document.addEventListener('DOMContentLoaded', ev => {
 document.addEventListener('DOMContentLoaded', ev => {
   // ====================================
   // ====================================
   // Notifications
   // Notifications
@@ -116,13 +119,13 @@ document.addEventListener('DOMContentLoaded', ev => {
   // Bootstrap Vue
   // Bootstrap Vue
   // ====================================
   // ====================================
 
 
-  const i18n = new VueI18Next(i18next)
+  const i18n = localization.init()
   window.wiki = new Vue({
   window.wiki = new Vue({
     mixins: [helpers],
     mixins: [helpers],
     components: {},
     components: {},
     store,
     store,
     i18n,
     i18n,
-    el: '#root',
+    el: '#app',
     methods: {
     methods: {
       changeTheme(opts) {
       changeTheme(opts) {
         this.$el.className = `has-stickynav is-primary-${opts.primary} is-alternate-${opts.alt}`
         this.$el.className = `has-stickynav is-primary-${opts.primary} is-alternate-${opts.alt}`

+ 50 - 0
client/js/components/login.vue

@@ -0,0 +1,50 @@
+<template lang="pug">
+  .login(:class='{ "is-error": error }')
+    .login-container(:class='{ "is-expanded": strategies.length > 1 }')
+      .login-error(v-if='error')
+        strong
+          i.icon-warning-outline
+          | {{ error.title }}
+        span {{ error.message }}
+      .login-providers(v-show='strategies.length > 1')
+        button.is-active(:title='$t("auth:providers.local")')
+          i.nc-icon-outline.ui-1_database
+          span {{ $t('auth:providers.local') }}
+        button(v-for='strategy in strategies', @onclick='selectProvider(strategy.key, strategy.useForm)', :title='strategy.title')
+          //-!= strategy.icon
+          span {{ strategy.title }}
+      .login-frame
+        h1 {{ siteTitle }}
+        h2 {{ $t('auth:loginrequired') }}
+        form(method='post', action='/login')
+          input#login-user(type='text', name='email', :placeholder='$t("auth:fields.emailuser")')
+          input#login-pass(type='password', name='password', :placeholder='$t("auth:fields.password")')
+          button.button.is-light-blue.is-fullwidth(type='submit')
+            span {{ $t('auth:actions.login') }}
+    .login-copyright
+      span {{ $t('footer.poweredby') }}
+      a(href='https://wiki.js.org', rel='external', title='Wiki.js') Wiki.js
+</template>
+
+<script>
+export default {
+  name: 'login',
+  data() {
+    return {
+      error: false,
+      strategies: []
+    }
+  },
+  computed: {
+    siteTitle() {
+      return siteConfig.title
+    }
+  }
+  methods: {
+    selectProvider(key, useForm) {
+
+    }
+  }
+}
+</script>
+

+ 57 - 0
client/js/modules/localization.js

@@ -0,0 +1,57 @@
+import i18next from 'i18next'
+import i18nextXHR from 'i18next-xhr-backend'
+import i18nextCache from 'i18next-localstorage-cache'
+import gql from 'graphql-tag'
+import VueI18Next from '@panter/vue-i18next'
+import loSet from 'lodash/set'
+
+/* global siteConfig */
+
+module.exports = {
+  VueI18Next,
+  init() {
+    i18next
+      .use(i18nextXHR)
+      .use(i18nextCache)
+      .init({
+        backend: {
+          loadPath: '{{lng}}/{{ns}}',
+          parse: (data) => data,
+          ajax: (url, opts, cb, data) => {
+            let langParams = url.split('/')
+            console.info(langParams)
+            window.apollo.query({
+              query: gql`
+                {
+                  translations(locale:"${langParams[0]}", namespace:"${langParams[1]}") {
+                    key
+                    value
+                  }
+                }
+              `
+            }).then(resp => {
+              let ns = {}
+              if (resp.data.translations.length > 0) {
+                resp.data.translations.forEach(entry => {
+                  loSet(ns, entry.key, entry.value)
+                })
+              }
+              return cb(ns, {status: '200'})
+            }).catch(err => {
+              console.error(err)
+              return cb(null, {status: '404'})
+            })
+          }
+        },
+        cache: {
+          enabled: true,
+          expiration: 60 * 60 * 1000
+        },
+        defaultNS: 'common',
+        lng: siteConfig.lang,
+        fallbackLng: siteConfig.lang,
+        ns: ['common', 'admin', 'auth']
+      })
+    return new VueI18Next(i18next)
+  }
+}

+ 6 - 1
client/scss/base/base.scss

@@ -11,10 +11,15 @@ html {
   display: none;
   display: none;
 }
 }
 
 
-#root {
+#app {
   padding-bottom: 67px;
   padding-bottom: 67px;
   position: relative;
   position: relative;
   min-height: 100%;
   min-height: 100%;
+
+  &.is-fullscreen {
+    width: 100vw;
+    height: 100vh;
+  }
 }
 }
 
 
 body {
 body {

+ 3 - 4
client/scss/pages/_login.scss

@@ -81,7 +81,6 @@
 
 
     border-right: none;
     border-right: none;
     border-radius: 6px 0 0 6px;
     border-radius: 6px 0 0 6px;
-    background-color: mc('grey', '900');
     z-index: 1;
     z-index: 1;
     overflow: hidden;
     overflow: hidden;
 
 
@@ -94,8 +93,8 @@
       padding: 5px 15px;
       padding: 5px 15px;
       border: none;
       border: none;
       color: #FFF;
       color: #FFF;
-      background-color: mc('light-blue', '800');
-      border-top: 1px solid mc('light-blue', '900');
+      background: linear-gradient(to right, rgba(mc('light-blue', '800'), .7), rgba(mc('light-blue', '800'), 1));
+      border-top: 1px solid rgba(mc('light-blue', '900'), .5);
       font-family: $core-font-standard;
       font-family: $core-font-standard;
       font-weight: 600;
       font-weight: 600;
       text-align: left;
       text-align: left;
@@ -110,7 +109,7 @@
       }
       }
 
 
       &:hover {
       &:hover {
-        background-color: mc('light-blue', '600');
+        background-color: mc('light-blue', '900');
       }
       }
 
 
       &:first-child {
       &:first-child {

+ 5 - 2
package.json

@@ -53,6 +53,7 @@
     "connect-redis": "3.3.0",
     "connect-redis": "3.3.0",
     "cookie-parser": "1.4.3",
     "cookie-parser": "1.4.3",
     "diff2html": "2.3.0",
     "diff2html": "2.3.0",
+    "dotize": "^0.2.0",
     "execa": "0.8.0",
     "execa": "0.8.0",
     "express": "4.15.4",
     "express": "4.15.4",
     "express-brute": "1.0.1",
     "express-brute": "1.0.1",
@@ -68,6 +69,7 @@
     "highlight.js": "9.12.0",
     "highlight.js": "9.12.0",
     "i18next": "9.0.0",
     "i18next": "9.0.0",
     "i18next-express-middleware": "1.0.5",
     "i18next-express-middleware": "1.0.5",
+    "i18next-localstorage-cache": "^1.1.1",
     "i18next-node-fs-backend": "1.0.0",
     "i18next-node-fs-backend": "1.0.0",
     "image-size": "0.6.1",
     "image-size": "0.6.1",
     "ioredis": "3.1.4",
     "ioredis": "3.1.4",
@@ -105,7 +107,6 @@
     "passport-local": "1.0.0",
     "passport-local": "1.0.0",
     "passport-slack": "0.0.7",
     "passport-slack": "0.0.7",
     "passport-windowslive": "1.0.2",
     "passport-windowslive": "1.0.2",
-    "passport.socketio": "3.7.0",
     "pg": "7.3.0",
     "pg": "7.3.0",
     "pg-hstore": "2.3.2",
     "pg-hstore": "2.3.2",
     "pg-promise": "6.5.2",
     "pg-promise": "6.5.2",
@@ -120,7 +121,6 @@
     "sequelize": "4.8.2",
     "sequelize": "4.8.2",
     "serve-favicon": "2.4.3",
     "serve-favicon": "2.4.3",
     "simplemde": "1.11.2",
     "simplemde": "1.11.2",
-    "socket.io": "2.0.3",
     "stopword": "0.1.7",
     "stopword": "0.1.7",
     "stream-to-promise": "2.2.0",
     "stream-to-promise": "2.2.0",
     "tar": "4.0.1",
     "tar": "4.0.1",
@@ -133,6 +133,7 @@
   "devDependencies": {
   "devDependencies": {
     "@glimpse/glimpse": "0.22.15",
     "@glimpse/glimpse": "0.22.15",
     "@panter/vue-i18next": "0.5.1",
     "@panter/vue-i18next": "0.5.1",
+    "apollo-client": "^1.9.3",
     "babel-cli": "6.26.0",
     "babel-cli": "6.26.0",
     "babel-jest": "21.0.2",
     "babel-jest": "21.0.2",
     "babel-plugin-transform-object-assign": "6.22.0",
     "babel-plugin-transform-object-assign": "6.22.0",
@@ -147,6 +148,7 @@
     "eslint-plugin-promise": "3.5.0",
     "eslint-plugin-promise": "3.5.0",
     "eslint-plugin-standard": "3.0.1",
     "eslint-plugin-standard": "3.0.1",
     "fuse-box": "^2.2.31",
     "fuse-box": "^2.2.31",
+    "graphql-tag": "^2.4.2",
     "i18next-xhr-backend": "1.4.2",
     "i18next-xhr-backend": "1.4.2",
     "jest": "21.0.2",
     "jest": "21.0.2",
     "jquery": "3.2.1",
     "jquery": "3.2.1",
@@ -166,6 +168,7 @@
     "vue": "2.4.2",
     "vue": "2.4.2",
     "vue-clipboards": "1.1.0",
     "vue-clipboards": "1.1.0",
     "vue-lodash": "1.0.3",
     "vue-lodash": "1.0.3",
+    "vue-material": "^0.7.5",
     "vue-resource": "1.3.4",
     "vue-resource": "1.3.4",
     "vue-template-compiler": "2.4.2",
     "vue-template-compiler": "2.4.2",
     "vue-template-es2015-compiler": "1.5.3",
     "vue-template-es2015-compiler": "1.5.3",

+ 1 - 0
server/authentication/azure.js

@@ -11,6 +11,7 @@ const AzureAdOAuth2Strategy = require('passport-azure-ad-oauth2').Strategy
 module.exports = {
 module.exports = {
   key: 'azure',
   key: 'azure',
   title: 'Azure Active Directory',
   title: 'Azure Active Directory',
+  useForm: false,
   props: ['clientId', 'clientSecret', 'callbackURL', 'resource', 'tenant'],
   props: ['clientId', 'clientSecret', 'callbackURL', 'resource', 'tenant'],
   init (passport, conf) {
   init (passport, conf) {
     const jwt = require('jsonwebtoken')
     const jwt = require('jsonwebtoken')

+ 1 - 0
server/authentication/facebook.js

@@ -11,6 +11,7 @@ const FacebookStrategy = require('passport-facebook').Strategy
 module.exports = {
 module.exports = {
   key: 'facebook',
   key: 'facebook',
   title: 'Facebook',
   title: 'Facebook',
+  useForm: false,
   props: ['clientId', 'clientSecret', 'callbackURL'],
   props: ['clientId', 'clientSecret', 'callbackURL'],
   init (passport, conf) {
   init (passport, conf) {
     passport.use('facebook',
     passport.use('facebook',

+ 1 - 0
server/authentication/github.js

@@ -11,6 +11,7 @@ const GitHubStrategy = require('passport-github2').Strategy
 module.exports = {
 module.exports = {
   key: 'github',
   key: 'github',
   title: 'GitHub',
   title: 'GitHub',
+  useForm: false,
   props: ['clientId', 'clientSecret', 'callbackURL'],
   props: ['clientId', 'clientSecret', 'callbackURL'],
   init (passport, conf) {
   init (passport, conf) {
     passport.use('github',
     passport.use('github',

+ 1 - 0
server/authentication/google.js

@@ -11,6 +11,7 @@ const GoogleStrategy = require('passport-google-oauth20').Strategy
 module.exports = {
 module.exports = {
   key: 'google',
   key: 'google',
   title: 'Google ID',
   title: 'Google ID',
+  useForm: false,
   props: ['clientId', 'clientSecret', 'callbackURL'],
   props: ['clientId', 'clientSecret', 'callbackURL'],
   init (passport, conf) {
   init (passport, conf) {
     passport.use('google',
     passport.use('google',

+ 1 - 0
server/authentication/ldap.js

@@ -12,6 +12,7 @@ const fs = require('fs')
 module.exports = {
 module.exports = {
   key: 'ldap',
   key: 'ldap',
   title: 'LDAP / Active Directory',
   title: 'LDAP / Active Directory',
+  useForm: true,
   props: ['url', 'bindDn', 'bindCredentials', 'searchBase', 'searchFilter', 'tlsEnabled', 'tlsCertPath'],
   props: ['url', 'bindDn', 'bindCredentials', 'searchBase', 'searchFilter', 'tlsEnabled', 'tlsCertPath'],
   init (passport, conf) {
   init (passport, conf) {
     passport.use('ldapauth',
     passport.use('ldapauth',

+ 1 - 0
server/authentication/local.js

@@ -11,6 +11,7 @@ const LocalStrategy = require('passport-local').Strategy
 module.exports = {
 module.exports = {
   key: 'local',
   key: 'local',
   title: 'Local',
   title: 'Local',
+  useForm: true,
   props: [],
   props: [],
   init (passport, conf) {
   init (passport, conf) {
     passport.use('local',
     passport.use('local',

+ 1 - 0
server/authentication/microsoft.js

@@ -11,6 +11,7 @@ const WindowsLiveStrategy = require('passport-windowslive').Strategy
 module.exports = {
 module.exports = {
   key: 'microsoft',
   key: 'microsoft',
   title: 'Microsoft Account',
   title: 'Microsoft Account',
+  useForm: false,
   props: ['clientId', 'clientSecret', 'callbackURL'],
   props: ['clientId', 'clientSecret', 'callbackURL'],
   init (passport, conf) {
   init (passport, conf) {
     passport.use('windowslive',
     passport.use('windowslive',

+ 1 - 0
server/authentication/slack.js

@@ -11,6 +11,7 @@ const SlackStrategy = require('passport-slack').Strategy
 module.exports = {
 module.exports = {
   key: 'slack',
   key: 'slack',
   title: 'Slack',
   title: 'Slack',
+  useForm: false,
   props: ['clientId', 'clientSecret', 'callbackURL'],
   props: ['clientId', 'clientSecret', 'callbackURL'],
   init (passport, conf) {
   init (passport, conf) {
     passport.use('slack',
     passport.use('slack',

+ 5 - 47
server/master.js

@@ -20,7 +20,7 @@ module.exports = Promise.join(
   wiki.disk = require('./modules/disk').init()
   wiki.disk = require('./modules/disk').init()
   wiki.docs = require('./modules/documents').init()
   wiki.docs = require('./modules/documents').init()
   wiki.git = require('./modules/git').init(false)
   wiki.git = require('./modules/git').init(false)
-  wiki.lang = require('i18next')
+  wiki.lang = require('./modules/localization').init()
   wiki.mark = require('./modules/markdown')
   wiki.mark = require('./modules/markdown')
   wiki.search = require('./modules/search').init()
   wiki.search = require('./modules/search').init()
   wiki.upl = require('./modules/uploads').init()
   wiki.upl = require('./modules/uploads').init()
@@ -37,13 +37,10 @@ module.exports = Promise.join(
   const favicon = require('serve-favicon')
   const favicon = require('serve-favicon')
   const flash = require('connect-flash')
   const flash = require('connect-flash')
   const http = require('http')
   const http = require('http')
-  const i18nBackend = require('i18next-node-fs-backend')
   const path = require('path')
   const path = require('path')
-  const passportSocketIo = require('passport.socketio')
   const session = require('express-session')
   const session = require('express-session')
   const SessionRedisStore = require('connect-redis')(session)
   const SessionRedisStore = require('connect-redis')(session)
   const graceful = require('node-graceful')
   const graceful = require('node-graceful')
-  const socketio = require('socket.io')
   const graphqlApollo = require('apollo-server-express')
   const graphqlApollo = require('apollo-server-express')
   const graphqlSchema = require('./modules/graphql')
   const graphqlSchema = require('./modules/graphql')
 
 
@@ -100,23 +97,6 @@ module.exports = Promise.join(
 
 
   app.use(mw.seo)
   app.use(mw.seo)
 
 
-  // ----------------------------------------
-  // Localization Engine
-  // ----------------------------------------
-
-  wiki.lang.use(i18nBackend).init({
-    load: 'languageOnly',
-    ns: ['common', 'admin', 'auth', 'errors', 'git'],
-    defaultNS: 'common',
-    saveMissing: false,
-    preload: [wiki.config.site.lang],
-    lng: wiki.config.site.lang,
-    fallbackLng: 'en',
-    backend: {
-      loadPath: path.join(wiki.SERVERPATH, 'locales/{{lng}}/{{ns}}.json')
-    }
-  })
-
   // ----------------------------------------
   // ----------------------------------------
   // View Engine Setup
   // View Engine Setup
   // ----------------------------------------
   // ----------------------------------------
@@ -133,7 +113,7 @@ module.exports = Promise.join(
 
 
   app.locals.basedir = wiki.ROOTPATH
   app.locals.basedir = wiki.ROOTPATH
   app.locals._ = require('lodash')
   app.locals._ = require('lodash')
-  app.locals.t = wiki.lang.t.bind(wiki.lang)
+  app.locals.t = wiki.lang.engine.t.bind(wiki.lang)
   app.locals.moment = require('moment')
   app.locals.moment = require('moment')
   app.locals.moment.locale(wiki.config.site.lang)
   app.locals.moment.locale(wiki.config.site.lang)
   app.locals.config = wiki.config
   app.locals.config = wiki.config
@@ -173,11 +153,10 @@ module.exports = Promise.join(
   // Start HTTP server
   // Start HTTP server
   // ----------------------------------------
   // ----------------------------------------
 
 
-  wiki.logger.info(`HTTP/WS Server on port: ${wiki.config.port}`)
+  wiki.logger.info(`HTTP Server on port: ${wiki.config.port}`)
 
 
   app.set('port', wiki.config.port)
   app.set('port', wiki.config.port)
-  var server = http.createServer(app)
-  var io = socketio(server)
+  let server = http.createServer(app)
 
 
   server.listen(wiki.config.port)
   server.listen(wiki.config.port)
   server.on('error', (error) => {
   server.on('error', (error) => {
@@ -199,35 +178,14 @@ module.exports = Promise.join(
   })
   })
 
 
   server.on('listening', () => {
   server.on('listening', () => {
-    wiki.logger.info('HTTP/WS Server: RUNNING')
+    wiki.logger.info('HTTP Server: RUNNING')
   })
   })
 
 
-  // ----------------------------------------
-  // WebSocket
-  // ----------------------------------------
-
-  io.use(passportSocketIo.authorize({
-    key: 'wikijs.sid',
-    store: sessionStore,
-    secret: wiki.config.site.sessionSecret,
-    cookieParser,
-    success: (data, accept) => {
-      accept()
-    },
-    fail: (data, message, error, accept) => {
-      accept()
-    }
-  }))
-
-  io.on('connection', ctrl.ws)
-
   // ----------------------------------------
   // ----------------------------------------
   // Graceful shutdown
   // Graceful shutdown
   // ----------------------------------------
   // ----------------------------------------
 
 
   graceful.on('exit', () => {
   graceful.on('exit', () => {
-    // wiki.logger.info('- SHUTTING DOWN - Terminating Background Agent...')
-    // bgAgent.kill()
     wiki.logger.info('- SHUTTING DOWN - Performing git sync...')
     wiki.logger.info('- SHUTTING DOWN - Performing git sync...')
     return global.git.resync().then(() => {
     return global.git.resync().then(() => {
       wiki.logger.info('- SHUTTING DOWN - Git sync successful. Now safe to exit.')
       wiki.logger.info('- SHUTTING DOWN - Git sync successful. Now safe to exit.')

+ 2 - 0
server/modules/graphql.js

@@ -17,6 +17,7 @@ const FolderResolvers = require('../schemas/resolvers-folder')
 const GroupResolvers = require('../schemas/resolvers-group')
 const GroupResolvers = require('../schemas/resolvers-group')
 const SettingResolvers = require('../schemas/resolvers-setting')
 const SettingResolvers = require('../schemas/resolvers-setting')
 const TagResolvers = require('../schemas/resolvers-tag')
 const TagResolvers = require('../schemas/resolvers-tag')
+const TranslationResolvers = require('../schemas/resolvers-translation')
 const UserResolvers = require('../schemas/resolvers-user')
 const UserResolvers = require('../schemas/resolvers-user')
 
 
 const resolvers = _.merge(
 const resolvers = _.merge(
@@ -27,6 +28,7 @@ const resolvers = _.merge(
   GroupResolvers,
   GroupResolvers,
   SettingResolvers,
   SettingResolvers,
   TagResolvers,
   TagResolvers,
+  TranslationResolvers,
   UserResolvers,
   UserResolvers,
   DateScalar
   DateScalar
 )
 )

+ 52 - 0
server/modules/localization.js

@@ -0,0 +1,52 @@
+const _ = require('lodash')
+const dotize = require('dotize')
+const i18nBackend = require('i18next-node-fs-backend')
+const i18next = require('i18next')
+const path = require('path')
+const Promise = require('bluebird')
+
+/* global wiki */
+
+module.exports = {
+  engine: null,
+  namespaces: ['common', 'admin', 'auth', 'errors', 'git'],
+  init() {
+    this.engine = i18next
+    this.engine.use(i18nBackend).init({
+      load: 'languageOnly',
+      ns: this.namespaces,
+      defaultNS: 'common',
+      saveMissing: false,
+      preload: [wiki.config.site.lang],
+      lng: wiki.config.site.lang,
+      fallbackLng: 'en',
+      backend: {
+        loadPath: path.join(wiki.SERVERPATH, 'locales/{{lng}}/{{ns}}.json')
+      }
+    })
+    return this
+  },
+  getByNamespace(locale, namespace) {
+    if (this.engine.hasResourceBundle(locale, namespace)) {
+      let data = this.engine.getResourceBundle(locale, namespace)
+      return _.map(dotize.convert(data), (value, key) => {
+        return {
+          key,
+          value
+        }
+      })
+    } else {
+      throw new Error('Invalid locale or namespace')
+    }
+  },
+  loadLocale(locale) {
+    return Promise.fromCallback(cb => {
+      return this.engine.loadLanguages(locale, cb)
+    })
+  },
+  setCurrentLocale(locale) {
+    return Promise.fromCallback(cb => {
+      return this.engine.changeLanguage(locale, cb)
+    })
+  }
+}

+ 0 - 1
server/schemas/resolvers-comment.js

@@ -1,4 +1,3 @@
-'use strict'
 
 
 /* global wiki */
 /* global wiki */
 
 

+ 0 - 1
server/schemas/resolvers-document.js

@@ -1,4 +1,3 @@
-'use strict'
 
 
 /* global wiki */
 /* global wiki */
 
 

+ 0 - 1
server/schemas/resolvers-file.js

@@ -1,4 +1,3 @@
-'use strict'
 
 
 /* global wiki */
 /* global wiki */
 
 

+ 0 - 1
server/schemas/resolvers-folder.js

@@ -1,4 +1,3 @@
-'use strict'
 
 
 /* global wiki */
 /* global wiki */
 
 

+ 0 - 1
server/schemas/resolvers-group.js

@@ -1,4 +1,3 @@
-'use strict'
 
 
 /* global wiki */
 /* global wiki */
 
 

+ 0 - 1
server/schemas/resolvers-right.js

@@ -1,4 +1,3 @@
-'use strict'
 
 
 /* global wiki */
 /* global wiki */
 
 

+ 0 - 1
server/schemas/resolvers-setting.js

@@ -1,4 +1,3 @@
-'use strict'
 
 
 /* global wiki */
 /* global wiki */
 
 

+ 0 - 1
server/schemas/resolvers-tag.js

@@ -1,4 +1,3 @@
-'use strict'
 
 
 /* global wiki */
 /* global wiki */
 
 

+ 12 - 0
server/schemas/resolvers-translation.js

@@ -0,0 +1,12 @@
+
+/* global wiki */
+
+module.exports = {
+  Query: {
+    translations (obj, args, context, info) {
+      return wiki.lang.getByNamespace(args.locale, args.namespace)
+    }
+  },
+  Mutation: {},
+  Translation: {}
+}

+ 0 - 1
server/schemas/resolvers-user.js

@@ -1,4 +1,3 @@
-'use strict'
 
 
 /* global wiki */
 /* global wiki */
 
 

+ 0 - 1
server/schemas/scalar-date.js

@@ -1,4 +1,3 @@
-'use strict'
 
 
 const gql = require('graphql')
 const gql = require('graphql')
 
 

+ 6 - 0
server/schemas/types.graphql

@@ -114,6 +114,11 @@ type Tag implements Base {
   documents: [Document]
   documents: [Document]
 }
 }
 
 
+type Translation {
+  key: String!
+  value: String!
+}
+
 # A User
 # A User
 type User implements Base {
 type User implements Base {
   id: Int!
   id: Int!
@@ -142,6 +147,7 @@ type Query {
   rights(id: Int): [Right]
   rights(id: Int): [Right]
   settings(key: String): [Setting]
   settings(key: String): [Setting]
   tags(key: String): [Tag]
   tags(key: String): [Tag]
+  translations(locale: String!, namespace: String!): [Translation]
   users(id: Int, email: String, provider: String, providerId: String, role: UserRole): [User]
   users(id: Int, email: String, provider: String, providerId: String, role: UserRole): [User]
 }
 }
 
 

+ 2 - 28
server/views/auth/login.pug

@@ -2,31 +2,5 @@ extends ../master.pug
 
 
 block body
 block body
   body
   body
-    .login#root(class={ "is-error": flash.length > 0 })
-      .login-container(class={ "is-expanded": hasMultipleStrategies })
-        if flash.length > 0
-          .login-error
-            strong
-              i.icon-warning-outline
-              = flash[0].title
-            span= flash[0].message
-        if hasMultipleStrategies
-          .login-providers
-            button.is-active(title=t('auth:providers.local'))
-              i.nc-icon-outline.ui-1_database
-              span= t('auth:providers.local')
-            each strategy in authStrategies
-              button(onclick='window.location.assign("/login/' + strategy.key + '")', title=strategy.title)
-                != strategy.icon
-                span= strategy.title
-        .login-frame
-          h1= config.site.title
-          h2= t('auth:loginrequired')
-          form(method='post', action='/login')
-            input#login-user(type='text', name='email', placeholder=t('auth:fields.emailuser'))
-            input#login-pass(type='password', name='password', placeholder=t('auth:fields.password'))
-            button.button.is-light-blue.is-fullwidth(type='submit')
-              span= t('auth:actions.login')
-      .login-copyright
-        = t('footer.poweredby')
-        a(href='https://wiki.js.org', rel='external', title='Wiki.js') Wiki.js
+    #app.is-fullscreen
+      login

+ 1 - 1
server/views/layout.pug

@@ -2,7 +2,7 @@ extends ./master.pug
 
 
 block body
 block body
   body
   body
-    #root.has-stickynav(class=['is-primary-' + appconfig.theme.primary, 'is-alternate-' + appconfig.theme.alt])
+    #app.has-stickynav(class=['is-primary-' + appconfig.theme.primary, 'is-alternate-' + appconfig.theme.alt])
       include ./common/header.pug
       include ./common/header.pug
       alert
       alert
       main
       main

+ 82 - 226
yarn.lock

@@ -79,6 +79,10 @@
   version "1.0.2"
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-1.0.2.tgz#b02d10ab028e2928ac592a051aaa4981a1941d03"
   resolved "https://registry.yarnpkg.com/@types/geojson/-/geojson-1.0.2.tgz#b02d10ab028e2928ac592a051aaa4981a1941d03"
 
 
+"@types/graphql@0.10.2":
+  version "0.10.2"
+  resolved "https://registry.yarnpkg.com/@types/graphql/-/graphql-0.10.2.tgz#d7c79acbaa17453b6681c80c34b38fcb10c4c08c"
+
 "@types/graphql@^0.9.0":
 "@types/graphql@^0.9.0":
   version "0.9.4"
   version "0.9.4"
   resolved "https://registry.yarnpkg.com/@types/graphql/-/graphql-0.9.4.tgz#cdeb6bcbef9b6c584374b81aa7f48ecf3da404fa"
   resolved "https://registry.yarnpkg.com/@types/graphql/-/graphql-0.9.4.tgz#cdeb6bcbef9b6c584374b81aa7f48ecf3da404fa"
@@ -151,13 +155,6 @@ abstract-leveldown@~2.6.1:
   dependencies:
   dependencies:
     xtend "~4.0.0"
     xtend "~4.0.0"
 
 
-accepts@1.3.3, accepts@~1.3.3:
-  version "1.3.3"
-  resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.3.tgz#c3ca7434938648c3e0d9c1e328dd68b622c284ca"
-  dependencies:
-    mime-types "~2.1.11"
-    negotiator "0.6.1"
-
 accepts@~1.2.12:
 accepts@~1.2.12:
   version "1.2.13"
   version "1.2.13"
   resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.2.13.tgz#e5f1f3928c6d95fd96558c36ec3d9d0de4a6ecea"
   resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.2.13.tgz#e5f1f3928c6d95fd96558c36ec3d9d0de4a6ecea"
@@ -165,6 +162,13 @@ accepts@~1.2.12:
     mime-types "~2.1.6"
     mime-types "~2.1.6"
     negotiator "0.5.3"
     negotiator "0.5.3"
 
 
+accepts@~1.3.3:
+  version "1.3.3"
+  resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.3.tgz#c3ca7434938648c3e0d9c1e328dd68b622c284ca"
+  dependencies:
+    mime-types "~2.1.11"
+    negotiator "0.6.1"
+
 acorn-es7-plugin@^1.1.7:
 acorn-es7-plugin@^1.1.7:
   version "1.1.7"
   version "1.1.7"
   resolved "https://registry.yarnpkg.com/acorn-es7-plugin/-/acorn-es7-plugin-1.1.7.tgz#f2ee1f3228a90eead1245f9ab1922eb2e71d336b"
   resolved "https://registry.yarnpkg.com/acorn-es7-plugin/-/acorn-es7-plugin-1.1.7.tgz#f2ee1f3228a90eead1245f9ab1922eb2e71d336b"
@@ -209,10 +213,6 @@ acorn@^5.0.3, acorn@^5.1.1:
   version "5.1.1"
   version "5.1.1"
   resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.1.1.tgz#53fe161111f912ab999ee887a90a0bc52822fd75"
   resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.1.1.tgz#53fe161111f912ab999ee887a90a0bc52822fd75"
 
 
-after@0.8.2:
-  version "0.8.2"
-  resolved "https://registry.yarnpkg.com/after/-/after-0.8.2.tgz#fedb394f9f0e02aa9768e702bda23b505fae7e1f"
-
 ajax-request@^1.2.0:
 ajax-request@^1.2.0:
   version "1.2.3"
   version "1.2.3"
   resolved "https://registry.yarnpkg.com/ajax-request/-/ajax-request-1.2.3.tgz#99fcbec1d6d2792f85fa949535332bd14f5f3790"
   resolved "https://registry.yarnpkg.com/ajax-request/-/ajax-request-1.2.3.tgz#99fcbec1d6d2792f85fa949535332bd14f5f3790"
@@ -329,6 +329,28 @@ ap@~0.2.0:
   version "0.2.0"
   version "0.2.0"
   resolved "https://registry.yarnpkg.com/ap/-/ap-0.2.0.tgz#ae0942600b29912f0d2b14ec60c45e8f330b6110"
   resolved "https://registry.yarnpkg.com/ap/-/ap-0.2.0.tgz#ae0942600b29912f0d2b14ec60c45e8f330b6110"
 
 
+apollo-client@^1.9.3:
+  version "1.9.3"
+  resolved "https://registry.yarnpkg.com/apollo-client/-/apollo-client-1.9.3.tgz#37000b3c801f4571b7b089739e696a158896aeab"
+  dependencies:
+    apollo-link-core "^0.5.0"
+    graphql "^0.10.0"
+    graphql-anywhere "^3.0.1"
+    graphql-tag "^2.0.0"
+    redux "^3.4.0"
+    symbol-observable "^1.0.2"
+    whatwg-fetch "^2.0.0"
+  optionalDependencies:
+    "@types/graphql" "0.10.2"
+
+apollo-link-core@^0.5.0:
+  version "0.5.4"
+  resolved "https://registry.yarnpkg.com/apollo-link-core/-/apollo-link-core-0.5.4.tgz#8efd4cd747959872a32f313f0ccfc2a76b396668"
+  dependencies:
+    graphql "^0.10.3"
+    graphql-tag "^2.4.2"
+    zen-observable-ts "^0.4.4"
+
 apollo-server-core@^1.1.0:
 apollo-server-core@^1.1.0:
   version "1.1.0"
   version "1.1.0"
   resolved "https://registry.yarnpkg.com/apollo-server-core/-/apollo-server-core-1.1.0.tgz#74c3bf4394e14eae7ab60b1d999a3c5b8aa94e9a"
   resolved "https://registry.yarnpkg.com/apollo-server-core/-/apollo-server-core-1.1.0.tgz#74c3bf4394e14eae7ab60b1d999a3c5b8aa94e9a"
@@ -435,10 +457,6 @@ array-unique@^0.2.1:
   version "0.2.1"
   version "0.2.1"
   resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53"
   resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53"
 
 
-arraybuffer.slice@0.0.6:
-  version "0.0.6"
-  resolved "https://registry.yarnpkg.com/arraybuffer.slice/-/arraybuffer.slice-0.0.6.tgz#f33b2159f0532a3f3107a272c0ccfbd1ad2979ca"
-
 arrify@^1.0.0, arrify@^1.0.1:
 arrify@^1.0.0, arrify@^1.0.1:
   version "1.0.1"
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
   resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d"
@@ -1090,10 +1108,6 @@ babylon@^6.18.0:
   version "6.18.0"
   version "6.18.0"
   resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3"
   resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3"
 
 
-backo2@1.0.2:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/backo2/-/backo2-1.0.2.tgz#31ab1ac8b129363463e35b3ebb69f4dfcfba7947"
-
 backoff@^2.5.0:
 backoff@^2.5.0:
   version "2.5.0"
   version "2.5.0"
   resolved "https://registry.yarnpkg.com/backoff/-/backoff-2.5.0.tgz#f616eda9d3e4b66b8ca7fca79f695722c5f8e26f"
   resolved "https://registry.yarnpkg.com/backoff/-/backoff-2.5.0.tgz#f616eda9d3e4b66b8ca7fca79f695722c5f8e26f"
@@ -1104,10 +1118,6 @@ balanced-match@^1.0.0:
   version "1.0.0"
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
   resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
 
 
-base64-arraybuffer@0.1.5:
-  version "0.1.5"
-  resolved "https://registry.yarnpkg.com/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz#73926771923b5a19747ad666aa5cd4bf9c6e9ce8"
-
 base64-img@^1.0.3:
 base64-img@^1.0.3:
   version "1.0.3"
   version "1.0.3"
   resolved "https://registry.yarnpkg.com/base64-img/-/base64-img-1.0.3.tgz#a8c0284900047103421e1f9e0214011333866806"
   resolved "https://registry.yarnpkg.com/base64-img/-/base64-img-1.0.3.tgz#a8c0284900047103421e1f9e0214011333866806"
@@ -1119,10 +1129,6 @@ base64-js@^1.2.0:
   version "1.2.1"
   version "1.2.1"
   resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.1.tgz#a91947da1f4a516ea38e5b4ec0ec3773675e0886"
   resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.1.tgz#a91947da1f4a516ea38e5b4ec0ec3773675e0886"
 
 
-base64id@1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/base64id/-/base64id-1.0.0.tgz#47688cb99bb6804f0e06d3e763b1c32e57d8e6b6"
-
 base64url@2.0.0, base64url@^2.0.0:
 base64url@2.0.0, base64url@^2.0.0:
   version "2.0.0"
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/base64url/-/base64url-2.0.0.tgz#eac16e03ea1438eff9423d69baa36262ed1f70bb"
   resolved "https://registry.yarnpkg.com/base64url/-/base64url-2.0.0.tgz#eac16e03ea1438eff9423d69baa36262ed1f70bb"
@@ -1144,12 +1150,6 @@ bcryptjs@^2.3.0, bcryptjs@^2.4.0:
   version "2.4.3"
   version "2.4.3"
   resolved "https://registry.yarnpkg.com/bcryptjs/-/bcryptjs-2.4.3.tgz#9ab5627b93e60621ff7cdac5da9733027df1d0cb"
   resolved "https://registry.yarnpkg.com/bcryptjs/-/bcryptjs-2.4.3.tgz#9ab5627b93e60621ff7cdac5da9733027df1d0cb"
 
 
-better-assert@~1.0.0:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/better-assert/-/better-assert-1.0.2.tgz#40866b9e1b9e0b55b481894311e68faffaebc522"
-  dependencies:
-    callsite "1.0.0"
-
 bignumber.js@^2.1.0:
 bignumber.js@^2.1.0:
   version "2.4.0"
   version "2.4.0"
   resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-2.4.0.tgz#838a992da9f9d737e0f4b2db0be62bb09dd0c5e8"
   resolved "https://registry.yarnpkg.com/bignumber.js/-/bignumber.js-2.4.0.tgz#838a992da9f9d737e0f4b2db0be62bb09dd0c5e8"
@@ -1176,10 +1176,6 @@ blessed@^0.1.81:
   version "0.1.81"
   version "0.1.81"
   resolved "https://registry.yarnpkg.com/blessed/-/blessed-0.1.81.tgz#f962d687ec2c369570ae71af843256e6d0ca1129"
   resolved "https://registry.yarnpkg.com/blessed/-/blessed-0.1.81.tgz#f962d687ec2c369570ae71af843256e6d0ca1129"
 
 
-blob@0.0.4:
-  version "0.0.4"
-  resolved "https://registry.yarnpkg.com/blob/-/blob-0.0.4.tgz#bcf13052ca54463f30f9fc7e95b9a47630a94921"
-
 block-stream@*:
 block-stream@*:
   version "0.0.9"
   version "0.0.9"
   resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a"
   resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a"
@@ -1350,10 +1346,6 @@ caller-path@^0.1.0:
   dependencies:
   dependencies:
     callsites "^0.2.0"
     callsites "^0.2.0"
 
 
-callsite@1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/callsite/-/callsite-1.0.0.tgz#280398e5d664bd74038b6f0905153e6e8af1bc20"
-
 callsites@^0.2.0:
 callsites@^0.2.0:
   version "0.2.0"
   version "0.2.0"
   resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca"
   resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca"
@@ -1637,18 +1629,6 @@ commander@2.8.x:
   dependencies:
   dependencies:
     graceful-readlink ">= 1.0.0"
     graceful-readlink ">= 1.0.0"
 
 
-component-bind@1.0.0:
-  version "1.0.0"
-  resolved "https://registry.yarnpkg.com/component-bind/-/component-bind-1.0.0.tgz#00c608ab7dcd93897c0009651b1d3a8e1e73bbd1"
-
-component-emitter@1.2.1:
-  version "1.2.1"
-  resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6"
-
-component-inherit@0.0.3:
-  version "0.0.3"
-  resolved "https://registry.yarnpkg.com/component-inherit/-/component-inherit-0.0.3.tgz#645fc4adf58b72b649d5cae65135619db26ff143"
-
 compressible@~2.0.10:
 compressible@~2.0.10:
   version "2.0.10"
   version "2.0.10"
   resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.10.tgz#feda1c7f7617912732b29bf8cf26252a20b9eecd"
   resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.10.tgz#feda1c7f7617912732b29bf8cf26252a20b9eecd"
@@ -1920,18 +1900,12 @@ de-indent@^1.0.2:
   version "1.0.2"
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/de-indent/-/de-indent-1.0.2.tgz#b2038e846dc33baa5796128d0804b455b8c1e21d"
   resolved "https://registry.yarnpkg.com/de-indent/-/de-indent-1.0.2.tgz#b2038e846dc33baa5796128d0804b455b8c1e21d"
 
 
-debug@*, debug@2.6.8, debug@^2.1.1, debug@^2.1.2, debug@^2.2.0, debug@^2.4.5, debug@^2.6, debug@^2.6.3, debug@^2.6.8, debug@~2.6.4, debug@~2.6.6:
+debug@*, debug@2.6.8, debug@^2.1.1, debug@^2.1.2, debug@^2.2.0, debug@^2.4.5, debug@^2.6, debug@^2.6.3, debug@^2.6.8:
   version "2.6.8"
   version "2.6.8"
   resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.8.tgz#e731531ca2ede27d188222427da17821d68ff4fc"
   resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.8.tgz#e731531ca2ede27d188222427da17821d68ff4fc"
   dependencies:
   dependencies:
     ms "2.0.0"
     ms "2.0.0"
 
 
-debug@2.3.3:
-  version "2.3.3"
-  resolved "https://registry.yarnpkg.com/debug/-/debug-2.3.3.tgz#40c453e67e6e13c901ddec317af8986cda9eff8c"
-  dependencies:
-    ms "0.7.2"
-
 debug@2.6.7:
 debug@2.6.7:
   version "2.6.7"
   version "2.6.7"
   resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.7.tgz#92bad1f6d05bbb6bba22cca88bcd0ec894c2861e"
   resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.7.tgz#92bad1f6d05bbb6bba22cca88bcd0ec894c2861e"
@@ -2131,6 +2105,10 @@ dot-prop@^4.1.0:
   dependencies:
   dependencies:
     is-obj "^1.0.0"
     is-obj "^1.0.0"
 
 
+dotize@^0.2.0:
+  version "0.2.0"
+  resolved "https://registry.yarnpkg.com/dotize/-/dotize-0.2.0.tgz#69e52f4a2b13344c56ff23c703c3074a2d6e57c7"
+
 dottie@^2.0.0:
 dottie@^2.0.0:
   version "2.0.0"
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/dottie/-/dottie-2.0.0.tgz#da191981c8b8d713ca0115d5898cf397c2f0ddd0"
   resolved "https://registry.yarnpkg.com/dottie/-/dottie-2.0.0.tgz#da191981c8b8d713ca0115d5898cf397c2f0ddd0"
@@ -2230,46 +2208,6 @@ end-of-stream@~1.1.0:
   dependencies:
   dependencies:
     once "~1.3.0"
     once "~1.3.0"
 
 
-engine.io-client@~3.1.0:
-  version "3.1.1"
-  resolved "https://registry.yarnpkg.com/engine.io-client/-/engine.io-client-3.1.1.tgz#415a9852badb14fa008fa3ef1e31608db6761325"
-  dependencies:
-    component-emitter "1.2.1"
-    component-inherit "0.0.3"
-    debug "~2.6.4"
-    engine.io-parser "~2.1.1"
-    has-cors "1.1.0"
-    indexof "0.0.1"
-    parsejson "0.0.3"
-    parseqs "0.0.5"
-    parseuri "0.0.5"
-    ws "~2.3.1"
-    xmlhttprequest-ssl "1.5.3"
-    yeast "0.1.2"
-
-engine.io-parser@~2.1.0, engine.io-parser@~2.1.1:
-  version "2.1.1"
-  resolved "https://registry.yarnpkg.com/engine.io-parser/-/engine.io-parser-2.1.1.tgz#e0fb3f0e0462f7f58bb77c1a52e9f5a7e26e4668"
-  dependencies:
-    after "0.8.2"
-    arraybuffer.slice "0.0.6"
-    base64-arraybuffer "0.1.5"
-    blob "0.0.4"
-    has-binary2 "~1.0.2"
-
-engine.io@~3.1.0:
-  version "3.1.0"
-  resolved "https://registry.yarnpkg.com/engine.io/-/engine.io-3.1.0.tgz#5ca438e3ce9fdbc915c4a21c8dd9e1266706e57e"
-  dependencies:
-    accepts "1.3.3"
-    base64id "1.0.0"
-    cookie "0.3.1"
-    debug "~2.6.4"
-    engine.io-parser "~2.1.0"
-    ws "~2.3.1"
-  optionalDependencies:
-    uws "~0.14.4"
-
 entities@^1.1.1, entities@~1.1.1:
 entities@^1.1.1, entities@~1.1.1:
   version "1.1.1"
   version "1.1.1"
   resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0"
   resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0"
@@ -3241,6 +3179,14 @@ graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.4, graceful-fs@^4.1.6,
   version "1.0.1"
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725"
   resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725"
 
 
+graphql-anywhere@^3.0.1:
+  version "3.1.0"
+  resolved "https://registry.yarnpkg.com/graphql-anywhere/-/graphql-anywhere-3.1.0.tgz#3ea0d8e8646b5cee68035016a9a7557c15c21e96"
+
+graphql-tag@^2.0.0, graphql-tag@^2.4.2:
+  version "2.4.2"
+  resolved "https://registry.yarnpkg.com/graphql-tag/-/graphql-tag-2.4.2.tgz#6a63297d8522d03a2b72d26f1b239aab343840cd"
+
 graphql-tools@1.2.2:
 graphql-tools@1.2.2:
   version "1.2.2"
   version "1.2.2"
   resolved "https://registry.yarnpkg.com/graphql-tools/-/graphql-tools-1.2.2.tgz#ff791e91b78e05eec18a32716a7732bc7bf5cb4d"
   resolved "https://registry.yarnpkg.com/graphql-tools/-/graphql-tools-1.2.2.tgz#ff791e91b78e05eec18a32716a7732bc7bf5cb4d"
@@ -3265,6 +3211,12 @@ graphql@0.11.3:
   dependencies:
   dependencies:
     iterall "^1.1.0"
     iterall "^1.1.0"
 
 
+graphql@^0.10.0, graphql@^0.10.3:
+  version "0.10.5"
+  resolved "https://registry.yarnpkg.com/graphql/-/graphql-0.10.5.tgz#c9be17ca2bdfdbd134077ffd9bbaa48b8becd298"
+  dependencies:
+    iterall "^1.1.0"
+
 growly@^1.3.0:
 growly@^1.3.0:
   version "1.3.0"
   version "1.3.0"
   resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081"
   resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081"
@@ -3296,16 +3248,6 @@ has-ansi@^2.0.0:
   dependencies:
   dependencies:
     ansi-regex "^2.0.0"
     ansi-regex "^2.0.0"
 
 
-has-binary2@~1.0.2:
-  version "1.0.2"
-  resolved "https://registry.yarnpkg.com/has-binary2/-/has-binary2-1.0.2.tgz#e83dba49f0b9be4d026d27365350d9f03f54be98"
-  dependencies:
-    isarray "2.0.1"
-
-has-cors@1.1.0:
-  version "1.1.0"
-  resolved "https://registry.yarnpkg.com/has-cors/-/has-cors-1.1.0.tgz#5e474793f7ea9843d1bb99c23eef49ff126fff39"
-
 has-flag@^1.0.0:
 has-flag@^1.0.0:
   version "1.0.0"
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa"
   resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa"
@@ -3436,6 +3378,10 @@ i18next-express-middleware@1.0.5:
   dependencies:
   dependencies:
     cookies "0.6.1"
     cookies "0.6.1"
 
 
+i18next-localstorage-cache@^1.1.1:
+  version "1.1.1"
+  resolved "https://registry.yarnpkg.com/i18next-localstorage-cache/-/i18next-localstorage-cache-1.1.1.tgz#575256cc35e8cb2d88148f754766fdd2d24bb1b7"
+
 i18next-node-fs-backend@1.0.0:
 i18next-node-fs-backend@1.0.0:
   version "1.0.0"
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/i18next-node-fs-backend/-/i18next-node-fs-backend-1.0.0.tgz#f5a625a3b287c1d098c7171b7dd376bb07299b59"
   resolved "https://registry.yarnpkg.com/i18next-node-fs-backend/-/i18next-node-fs-backend-1.0.0.tgz#f5a625a3b287c1d098c7171b7dd376bb07299b59"
@@ -3501,10 +3447,6 @@ indent-string@^2.1.0:
   dependencies:
   dependencies:
     repeating "^2.0.0"
     repeating "^2.0.0"
 
 
-indexof@0.0.1:
-  version "0.0.1"
-  resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d"
-
 inflection@1.12.0:
 inflection@1.12.0:
   version "1.12.0"
   version "1.12.0"
   resolved "https://registry.yarnpkg.com/inflection/-/inflection-1.12.0.tgz#a200935656d6f5f6bc4dc7502e1aecb703228416"
   resolved "https://registry.yarnpkg.com/inflection/-/inflection-1.12.0.tgz#a200935656d6f5f6bc4dc7502e1aecb703228416"
@@ -3825,10 +3767,6 @@ isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0:
   version "1.0.0"
   version "1.0.0"
   resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
   resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
 
 
-isarray@2.0.1:
-  version "2.0.1"
-  resolved "https://registry.yarnpkg.com/isarray/-/isarray-2.0.1.tgz#a37d94ed9cda2d59865c9f76fe596ee1f338741e"
-
 isexe@^2.0.0:
 isexe@^2.0.0:
   version "2.0.0"
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
   resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
@@ -4573,7 +4511,7 @@ lodash-cli@4.17.4:
     semver "5.3.0"
     semver "5.3.0"
     uglify-js "2.7.5"
     uglify-js "2.7.5"
 
 
-lodash-es@4.17.4:
+lodash-es@4.17.4, lodash-es@^4.2.1:
   version "4.17.4"
   version "4.17.4"
   resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.4.tgz#dcc1d7552e150a0640073ba9cb31d70f032950e7"
   resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.4.tgz#dcc1d7552e150a0640073ba9cb31d70f032950e7"
 
 
@@ -4787,7 +4725,7 @@ lodash.values@^4.3.0:
   version "4.3.0"
   version "4.3.0"
   resolved "https://registry.yarnpkg.com/lodash.values/-/lodash.values-4.3.0.tgz#a3a6c2b0ebecc5c2cba1c17e6e620fe81b53d347"
   resolved "https://registry.yarnpkg.com/lodash.values/-/lodash.values-4.3.0.tgz#a3a6c2b0ebecc5c2cba1c17e6e620fe81b53d347"
 
 
-lodash@4.17.4, lodash@^4.0.0, lodash@^4.1.0, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.17.1, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.3.0, lodash@~4.17.4:
+lodash@4.17.4, lodash@^4.0.0, lodash@^4.1.0, lodash@^4.14.0, lodash@^4.15.0, lodash@^4.17.1, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0, lodash@~4.17.4:
   version "4.17.4"
   version "4.17.4"
   resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae"
   resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae"
 
 
@@ -4805,7 +4743,7 @@ longest@^1.0.1:
   version "1.0.1"
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097"
   resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097"
 
 
-loose-envify@^1.0.0:
+loose-envify@^1.0.0, loose-envify@^1.1.0:
   version "1.3.1"
   version "1.3.1"
   resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848"
   resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848"
   dependencies:
   dependencies:
@@ -5102,10 +5040,6 @@ ms@0.7.1:
   version "0.7.1"
   version "0.7.1"
   resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098"
   resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098"
 
 
-ms@0.7.2:
-  version "0.7.2"
-  resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.2.tgz#ae25cf2512b3885a1d95d7f037868d8431124765"
-
 ms@2.0.0, ms@^2.0.0:
 ms@2.0.0, ms@^2.0.0:
   version "2.0.0"
   version "2.0.0"
   resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
   resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8"
@@ -5377,14 +5311,10 @@ object-assign@^3.0.0:
   version "3.0.0"
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-3.0.0.tgz#9bedd5ca0897949bca47e7ff408062d549f587f2"
   resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-3.0.0.tgz#9bedd5ca0897949bca47e7ff408062d549f587f2"
 
 
-object-assign@^4, object-assign@^4.0.1, object-assign@^4.1.0, object-assign@~4.1.1:
+object-assign@^4, object-assign@^4.0.1, object-assign@^4.1.0:
   version "4.1.1"
   version "4.1.1"
   resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
   resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
 
 
-object-component@0.0.3:
-  version "0.0.3"
-  resolved "https://registry.yarnpkg.com/object-component/-/object-component-0.0.3.tgz#f0c69aa50efc95b866c186f400a33769cb2f1291"
-
 object-keys@^1.0.8:
 object-keys@^1.0.8:
   version "1.0.11"
   version "1.0.11"
   resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.11.tgz#c54601778ad560f1142ce0e01bcca8b56d13426d"
   resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.0.11.tgz#c54601778ad560f1142ce0e01bcca8b56d13426d"
@@ -5594,24 +5524,6 @@ parse5@^3.0.1:
   dependencies:
   dependencies:
     "@types/node" "^6.0.46"
     "@types/node" "^6.0.46"
 
 
-parsejson@0.0.3:
-  version "0.0.3"
-  resolved "https://registry.yarnpkg.com/parsejson/-/parsejson-0.0.3.tgz#ab7e3759f209ece99437973f7d0f1f64ae0e64ab"
-  dependencies:
-    better-assert "~1.0.0"
-
-parseqs@0.0.5:
-  version "0.0.5"
-  resolved "https://registry.yarnpkg.com/parseqs/-/parseqs-0.0.5.tgz#d5208a3738e46766e291ba2ea173684921a8b89d"
-  dependencies:
-    better-assert "~1.0.0"
-
-parseuri@0.0.5:
-  version "0.0.5"
-  resolved "https://registry.yarnpkg.com/parseuri/-/parseuri-0.0.5.tgz#80204a50d4dbb779bfdc6ebe2778d90e4bce320a"
-  dependencies:
-    better-assert "~1.0.0"
-
 parseurl@^1.3.0, parseurl@~1.3.1:
 parseurl@^1.3.0, parseurl@~1.3.1:
   version "1.3.1"
   version "1.3.1"
   resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.1.tgz#c8ab8c9223ba34888aa64a297b28853bec18da56"
   resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.1.tgz#c8ab8c9223ba34888aa64a297b28853bec18da56"
@@ -5704,12 +5616,6 @@ passport-windowslive@1.0.2:
   dependencies:
   dependencies:
     passport-oauth2 "1.x.x"
     passport-oauth2 "1.x.x"
 
 
-passport.socketio@3.7.0:
-  version "3.7.0"
-  resolved "https://registry.yarnpkg.com/passport.socketio/-/passport.socketio-3.7.0.tgz#2ee5fafe9695d4281c8cddd3fe975ecd18e6726e"
-  dependencies:
-    xtend "^4.0.0"
-
 passport@0.4.0:
 passport@0.4.0:
   version "0.4.0"
   version "0.4.0"
   resolved "https://registry.yarnpkg.com/passport/-/passport-0.4.0.tgz#c5095691347bd5ad3b5e180238c3914d16f05811"
   resolved "https://registry.yarnpkg.com/passport/-/passport-0.4.0.tgz#c5095691347bd5ad3b5e180238c3914d16f05811"
@@ -6458,6 +6364,15 @@ reduce-flatten@^1.0.1:
   version "1.0.1"
   version "1.0.1"
   resolved "https://registry.yarnpkg.com/reduce-flatten/-/reduce-flatten-1.0.1.tgz#258c78efd153ddf93cb561237f61184f3696e327"
   resolved "https://registry.yarnpkg.com/reduce-flatten/-/reduce-flatten-1.0.1.tgz#258c78efd153ddf93cb561237f61184f3696e327"
 
 
+redux@^3.4.0:
+  version "3.7.2"
+  resolved "https://registry.yarnpkg.com/redux/-/redux-3.7.2.tgz#06b73123215901d25d065be342eb026bc1c8537b"
+  dependencies:
+    lodash "^4.2.1"
+    lodash-es "^4.2.1"
+    loose-envify "^1.1.0"
+    symbol-observable "^1.0.3"
+
 regenerate@^1.2.1:
 regenerate@^1.2.1:
   version "1.3.2"
   version "1.3.2"
   resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.2.tgz#d1941c67bad437e1be76433add5b385f95b19260"
   resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.2.tgz#d1941c67bad437e1be76433add5b385f95b19260"
@@ -6651,7 +6566,7 @@ rx@^4.1.0:
   version "4.1.0"
   version "4.1.0"
   resolved "https://registry.yarnpkg.com/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782"
   resolved "https://registry.yarnpkg.com/rx/-/rx-4.1.0.tgz#a5f13ff79ef3b740fe30aa803fb09f98805d4782"
 
 
-safe-buffer@5.0.1, safe-buffer@~5.0.1:
+safe-buffer@5.0.1:
   version "5.0.1"
   version "5.0.1"
   resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.0.1.tgz#d263ca54696cd8a306b5ca6551e92de57918fbe7"
   resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.0.1.tgz#d263ca54696cd8a306b5ca6551e92de57918fbe7"
 
 
@@ -6965,50 +6880,6 @@ sntp@1.x.x:
   dependencies:
   dependencies:
     hoek "2.x.x"
     hoek "2.x.x"
 
 
-socket.io-adapter@~1.1.0:
-  version "1.1.0"
-  resolved "https://registry.yarnpkg.com/socket.io-adapter/-/socket.io-adapter-1.1.0.tgz#c7aa46501dd556c2cb8a28af8ff95c0b5e1daa4c"
-  dependencies:
-    debug "2.3.3"
-
-socket.io-client@~2.0.2:
-  version "2.0.3"
-  resolved "https://registry.yarnpkg.com/socket.io-client/-/socket.io-client-2.0.3.tgz#6caf4aff9f85b19fd91b6ce13d69adb564f8873b"
-  dependencies:
-    backo2 "1.0.2"
-    base64-arraybuffer "0.1.5"
-    component-bind "1.0.0"
-    component-emitter "1.2.1"
-    debug "~2.6.4"
-    engine.io-client "~3.1.0"
-    has-cors "1.1.0"
-    indexof "0.0.1"
-    object-component "0.0.3"
-    parseqs "0.0.5"
-    parseuri "0.0.5"
-    socket.io-parser "~3.1.1"
-    to-array "0.1.4"
-
-socket.io-parser@~3.1.1:
-  version "3.1.2"
-  resolved "https://registry.yarnpkg.com/socket.io-parser/-/socket.io-parser-3.1.2.tgz#dbc2282151fc4faebbe40aeedc0772eba619f7f2"
-  dependencies:
-    component-emitter "1.2.1"
-    debug "~2.6.4"
-    has-binary2 "~1.0.2"
-    isarray "2.0.1"
-
-socket.io@2.0.3:
-  version "2.0.3"
-  resolved "https://registry.yarnpkg.com/socket.io/-/socket.io-2.0.3.tgz#4359f06a24933ae6bd087798af78c680eae345e3"
-  dependencies:
-    debug "~2.6.6"
-    engine.io "~3.1.0"
-    object-assign "~4.1.1"
-    socket.io-adapter "~1.1.0"
-    socket.io-client "~2.0.2"
-    socket.io-parser "~3.1.1"
-
 source-map-support@^0.4.15, source-map-support@^0.4.2:
 source-map-support@^0.4.15, source-map-support@^0.4.2:
   version "0.4.15"
   version "0.4.15"
   resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.15.tgz#03202df65c06d2bd8c7ec2362a193056fef8d3b1"
   resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.15.tgz#03202df65c06d2bd8c7ec2362a193056fef8d3b1"
@@ -7235,6 +7106,10 @@ supports-color@^4.0.0, supports-color@^4.2.0:
   dependencies:
   dependencies:
     has-flag "^2.0.0"
     has-flag "^2.0.0"
 
 
+symbol-observable@^1.0.2, symbol-observable@^1.0.3:
+  version "1.0.4"
+  resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.0.4.tgz#29bf615d4aa7121bdd898b22d4b3f9bc4e2aa03d"
+
 symbol-tree@^3.2.1:
 symbol-tree@^3.2.1:
   version "3.2.2"
   version "3.2.2"
   resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.2.tgz#ae27db38f660a7ae2e1c3b7d1bc290819b8519e6"
   resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.2.tgz#ae27db38f660a7ae2e1c3b7d1bc290819b8519e6"
@@ -7399,10 +7274,6 @@ tmpl@1.0.x:
   version "1.0.4"
   version "1.0.4"
   resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1"
   resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1"
 
 
-to-array@0.1.4:
-  version "0.1.4"
-  resolved "https://registry.yarnpkg.com/to-array/-/to-array-0.1.4.tgz#17e6c11f73dd4f3d74cda7a4ff3238e9ad9bf890"
-
 to-fast-properties@^1.0.1, to-fast-properties@^1.0.3:
 to-fast-properties@^1.0.1, to-fast-properties@^1.0.3:
   version "1.0.3"
   version "1.0.3"
   resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47"
   resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47"
@@ -7551,10 +7422,6 @@ ultron@1.0.x:
   version "1.0.2"
   version "1.0.2"
   resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.0.2.tgz#ace116ab557cd197386a4e88f4685378c8b2e4fa"
   resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.0.2.tgz#ace116ab557cd197386a4e88f4685378c8b2e4fa"
 
 
-ultron@~1.1.0:
-  version "1.1.0"
-  resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.0.tgz#b07a2e6a541a815fc6a34ccd4533baec307ca864"
-
 undefsafe@0.0.3:
 undefsafe@0.0.3:
   version "0.0.3"
   version "0.0.3"
   resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-0.0.3.tgz#ecca3a03e56b9af17385baac812ac83b994a962f"
   resolved "https://registry.yarnpkg.com/undefsafe/-/undefsafe-0.0.3.tgz#ecca3a03e56b9af17385baac812ac83b994a962f"
@@ -7655,10 +7522,6 @@ uuid@^3.0.0, uuid@^3.0.1, uuid@^3.1.0:
   version "3.1.0"
   version "3.1.0"
   resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04"
   resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04"
 
 
-uws@~0.14.4:
-  version "0.14.5"
-  resolved "https://registry.yarnpkg.com/uws/-/uws-0.14.5.tgz#67aaf33c46b2a587a5f6666d00f7691328f149dc"
-
 v8flags@^2.1.1:
 v8flags@^2.1.1:
   version "2.1.1"
   version "2.1.1"
   resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-2.1.1.tgz#aab1a1fa30d45f88dd321148875ac02c0b55e5b4"
   resolved "https://registry.yarnpkg.com/v8flags/-/v8flags-2.1.1.tgz#aab1a1fa30d45f88dd321148875ac02c0b55e5b4"
@@ -7750,6 +7613,10 @@ vue-lodash@1.0.3:
   version "1.0.3"
   version "1.0.3"
   resolved "https://registry.yarnpkg.com/vue-lodash/-/vue-lodash-1.0.3.tgz#777ef3e190a4cdde0d211a614e52a0b38659c13f"
   resolved "https://registry.yarnpkg.com/vue-lodash/-/vue-lodash-1.0.3.tgz#777ef3e190a4cdde0d211a614e52a0b38659c13f"
 
 
+vue-material@^0.7.5:
+  version "0.7.5"
+  resolved "https://registry.yarnpkg.com/vue-material/-/vue-material-0.7.5.tgz#045517403c1338aceabd73030f3dd6b5c744fe55"
+
 vue-resource@1.3.4:
 vue-resource@1.3.4:
   version "1.3.4"
   version "1.3.4"
   resolved "https://registry.yarnpkg.com/vue-resource/-/vue-resource-1.3.4.tgz#9fc0bdf6a2f5cab430129fc99d347b3deae7b099"
   resolved "https://registry.yarnpkg.com/vue-resource/-/vue-resource-1.3.4.tgz#9fc0bdf6a2f5cab430129fc99d347b3deae7b099"
@@ -7826,7 +7693,7 @@ whatwg-encoding@^1.0.1:
   dependencies:
   dependencies:
     iconv-lite "0.4.13"
     iconv-lite "0.4.13"
 
 
-whatwg-fetch@^2.0.3:
+whatwg-fetch@^2.0.0, whatwg-fetch@^2.0.3:
   version "2.0.3"
   version "2.0.3"
   resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz#9c84ec2dcf68187ff00bc64e1274b442176e1c84"
   resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.3.tgz#9c84ec2dcf68187ff00bc64e1274b442176e1c84"
 
 
@@ -7951,13 +7818,6 @@ ws@^1.1.1:
     options ">=0.0.5"
     options ">=0.0.5"
     ultron "1.0.x"
     ultron "1.0.x"
 
 
-ws@~2.3.1:
-  version "2.3.1"
-  resolved "https://registry.yarnpkg.com/ws/-/ws-2.3.1.tgz#6b94b3e447cb6a363f785eaf94af6359e8e81c80"
-  dependencies:
-    safe-buffer "~5.0.1"
-    ultron "~1.1.0"
-
 xdg-basedir@^3.0.0:
 xdg-basedir@^3.0.0:
   version "3.0.0"
   version "3.0.0"
   resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4"
   resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4"
@@ -7992,10 +7852,6 @@ xmlbuilder@^4.1.0:
   dependencies:
   dependencies:
     lodash "^4.0.0"
     lodash "^4.0.0"
 
 
-xmlhttprequest-ssl@1.5.3:
-  version "1.5.3"
-  resolved "https://registry.yarnpkg.com/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.3.tgz#185a888c04eca46c3e4070d99f7b49de3528992d"
-
 xtend@4.0.1, xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.0, xtend@~4.0.1:
 xtend@4.0.1, xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.0, xtend@~4.0.1:
   version "4.0.1"
   version "4.0.1"
   resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
   resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
@@ -8094,9 +7950,9 @@ yargs@~3.10.0:
     decamelize "^1.0.0"
     decamelize "^1.0.0"
     window-size "0.1.0"
     window-size "0.1.0"
 
 
-yeast@0.1.2:
-  version "0.1.2"
-  resolved "https://registry.yarnpkg.com/yeast/-/yeast-0.1.2.tgz#008e06d8094320c372dbc2f8ed76a0ca6c8ac419"
+zen-observable-ts@^0.4.4:
+  version "0.4.4"
+  resolved "https://registry.yarnpkg.com/zen-observable-ts/-/zen-observable-ts-0.4.4.tgz#c244c71eaebef79a985ccf9895bc90307a6e9712"
 
 
 zone.js@0.7.6:
 zone.js@0.7.6:
   version "0.7.6"
   version "0.7.6"