Ver código fonte

Merge branch 'master' into files-routing

Sotaro KARASAWA 9 anos atrás
pai
commit
6d20e72733
92 arquivos alterados com 8296 adições e 591 exclusões
  1. 18 0
      CHANGES.md
  2. 4 3
      README.md
  3. 2 2
      circle.yml
  4. 10 3
      gulpfile.js
  5. 29 2
      lib/crowi/express-init.js
  6. 17 8
      lib/crowi/index.js
  7. 20 18
      lib/form/index.js
  8. 1 1
      lib/form/invited.js
  9. 1 1
      lib/form/login.js
  10. 1 2
      lib/form/me/password.js
  11. 2 1
      lib/form/me/user.js
  12. 1 1
      lib/form/register.js
  13. 1 2
      lib/models/attachment.js
  14. 6 5
      lib/models/page.js
  15. 7 0
      lib/models/revision.js
  16. 47 13
      lib/models/user.js
  17. 32 34
      lib/routes/admin.js
  18. 18 16
      lib/routes/attachment.js
  19. 7 3
      lib/routes/index.js
  20. 3 2
      lib/routes/installer.js
  21. 10 9
      lib/routes/login.js
  22. 17 15
      lib/routes/me.js
  23. 40 6
      lib/routes/page.js
  24. 30 1
      lib/routes/revision.js
  25. 19 0
      lib/util/i18nUserSettingDetector.js
  26. 2 1
      lib/util/middlewares.js
  27. 136 18
      lib/util/search.js
  28. 2 2
      lib/views/_form.html
  29. 1 20
      lib/views/admin/users.html
  30. 3 3
      lib/views/layout/2column.html
  31. 16 5
      lib/views/layout/layout.html
  32. 1 1
      lib/views/layout/single.html
  33. 25 25
      lib/views/login.html
  34. 12 12
      lib/views/me/api_token.html
  35. 34 34
      lib/views/me/index.html
  36. 14 14
      lib/views/me/password.html
  37. 8 9
      lib/views/modal/create_page.html
  38. 18 18
      lib/views/modal/help.html
  39. 6 9
      lib/views/modal/rename.html
  40. 19 40
      lib/views/page.html
  41. 40 30
      lib/views/page_list.html
  42. 3 1
      lib/views/user_page.html
  43. 4 4
      lib/views/widget/page_side_content.html
  44. 7 11
      lib/views/widget/page_side_header.html
  45. 32 0
      lib/views/widget/pager.html
  46. 1 2
      local_modules/crowi-fileupload-aws/index.js
  47. 0 1
      local_modules/crowi-fileupload-local/index.js
  48. 1 0
      locales/en
  49. 166 0
      locales/en-US/translation.json
  50. 166 0
      locales/ja/translation.json
  51. 6599 0
      npm-shrinkwrap.json
  52. 32 29
      package.json
  53. BIN
      public/android-chrome-192x192.png
  54. BIN
      public/apple-touch-icon-114x114-precomposed.png
  55. BIN
      public/apple-touch-icon-120x120.png
  56. BIN
      public/apple-touch-icon-180x180.png
  57. BIN
      public/apple-touch-icon-57x57-precomposed.png
  58. BIN
      public/apple-touch-icon-72x72-precomposed.png
  59. BIN
      public/apple-touch-icon-72x72.png
  60. BIN
      public/apple-touch-icon-precomposed.png
  61. BIN
      public/apple-touch-icon.png
  62. 1 0
      public/css/diff2html
  63. BIN
      public/favicon-16x16.png
  64. BIN
      public/favicon-32x32.png
  65. BIN
      public/favicon-96x96.png
  66. BIN
      public/favicon.ico
  67. 24 7
      public/nginx-mime.types
  68. 6 0
      resource/css/crowi.scss
  69. 18 2
      resource/js/app.js
  70. 22 0
      resource/js/components/Common/Icon.js
  71. 34 0
      resource/js/components/Common/UserDate.js
  72. 139 0
      resource/js/components/PageHistory.js
  73. 54 0
      resource/js/components/PageHistory/PageRevisionList.js
  74. 59 0
      resource/js/components/PageHistory/Revision.js
  75. 42 0
      resource/js/components/PageHistory/RevisionDiff.js
  76. 6 2
      resource/js/components/SearchPage/SearchResultList.js
  77. 53 0
      resource/js/components/SeenUserList.js
  78. 42 0
      resource/js/components/SeenUserList/UserList.js
  79. 12 1
      resource/js/components/User/UserPicture.js
  80. 8 3
      resource/js/crowi-form.js
  81. 4 105
      resource/js/crowi.js
  82. 16 1
      resource/js/util/Crowi.js
  83. 52 18
      resource/search/mappings.json
  84. 0 2
      test/bootstrap.js
  85. 3 1
      test/crowi/crowi.test.js
  86. 0 1
      test/models/config.test.js
  87. 0 1
      test/models/page.test.js
  88. 0 1
      test/models/updatePost.test.js
  89. 1 2
      test/models/user.test.js
  90. 1 0
      test/utils.js
  91. 1 0
      tmp/uploads/.gitignore
  92. 7 7
      webpack.config.js

+ 18 - 0
CHANGES.md

@@ -1,6 +1,24 @@
 CHANGES
 ========
 
+## 1.6.0
+
+- I18N
+- Improved diff view
+- - Minus search
+- - Supports Elasticsearch 5.x
+- Special thank you for the great pull requests: @b4b4r07 @kaz @hasete2 @okonomi
+- And also special thanks for the translation: @Hidsm
+
+## 1.5.3
+
+* Added node-shrinkwrap.json
+* Fix: Undo behavior after pasting (#151).
+* Feature: Password reset for admin.
+* Feature: Implement some APIs.
+* Improve: Likes on smartphone.
+* And some fixes. (Thank you @suzuki @okonomi)
+
 ## 1.5.2
 
 * Fix: Edit button on smartphone.

+ 4 - 3
README.md

@@ -4,7 +4,7 @@ Crowi - The Simple & Powerful Communication Tool Based on Wiki
 ================================================================
 
 
-[![Deploy](https://www.herokucdn.com/deploy/button.png)](https://heroku.com/deploy?template=https://github.com/crowi/crowi/tree/v1.5.2)
+[![Deploy](https://www.herokucdn.com/deploy/button.png)](https://heroku.com/deploy?template=https://github.com/crowi/crowi/tree/v1.6.0)
 
 [![Circle CI](https://circleci.com/gh/crowi/crowi.svg?style=svg)](https://circleci.com/gh/crowi/crowi)
 [![Join the chat at https://gitter.im/crowi/general](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/crowi/general)
@@ -30,14 +30,15 @@ More info are [here](https://github.com/crowi/crowi/wiki/Install-and-Configurati
 ### WARNING
 
 Don't use `master` branch because it is unstable but use released tag version expect when you want to contribute the project.
+`master` branch is prepared for v1.6. See [here](https://github.com/crowi/crowi/wiki/Roadmaps-v1.6) to know further info.
 
 
 Dependencies
 -------------
 
-* Node.js (4.x)
+* Node.js (6.x)
 * MongoDB
-* Elasticsearch (optional)
+* Elasticsearch (optional) ([Doc is here](https://github.com/crowi/crowi/wiki/Configure-Search-Functions))
 * Redis (optional)
 * Amazon S3 (optional)
 * Google Project (optional)

+ 2 - 2
circle.yml

@@ -5,9 +5,9 @@ machine:
   environment:
     MONGO_URI: mongodb://127.0.0.1/crowi_test
   node:
-      version: 4.6.2
+      version: 6.9.4
   post:
-    - npm install -g npm@3
+    - npm install -g npm@4
 notify:
   webhooks:
     - url: https://webhooks.gitter.im/e/5a035388e3274b621d20

+ 10 - 3
gulpfile.js

@@ -10,7 +10,8 @@ var concat = require('gulp-concat');
 var rename = require('gulp-rename');
 var jshint = require('gulp-jshint');
 var source = require('vinyl-source-stream');
-var webpack = require('webpack-stream');
+var webpack = require('webpack');
+var webpackStream = require('webpack-stream');
 
 var del     = require('del');
 var stylish = require('jshint-stylish');
@@ -90,7 +91,9 @@ gulp.task('js:concat', ['js:del'], function() {
 // move task for css and js to webpack over time.
 gulp.task('webpack', ['js:concat'], function() {
   return gulp.src(js.src)
-    .pipe(webpack(require('./webpack.config.js')))
+    .pipe(webpackStream(
+      require('./webpack.config.js'),
+      webpack))   // pass webpack2 to webpack-stream
     .pipe(gulp.dest(dirs.jsDist));
 });
 
@@ -129,7 +132,11 @@ gulp.task('css:sass', function() {
 });
 
 gulp.task('css:concat', ['css:sass'], function() {
-  return gulp.src([css.main, 'node_modules/highlight.js/styles/tomorrow-night.css'])
+  return gulp.src([
+      css.main,
+      'node_modules/highlight.js/styles/tomorrow-night.css',
+      'node_modules/diff2html/dist/diff2html.css',
+    ])
     .pipe(concat('crowi.css'))
     .pipe(gulp.dest(dirs.cssDist))
 });

+ 29 - 2
lib/crowi/express-init.js

@@ -4,7 +4,6 @@ module.exports = function(crowi, app) {
   var debug = require('debug')('crowi:crowi:express-init')
     , express        = require('express')
     , bodyParser     = require('body-parser')
-    , multer         = require('multer')
     , cookieParser   = require('cookie-parser')
     , methodOverride = require('method-override')
     , session        = require('express-session')
@@ -12,10 +11,37 @@ module.exports = function(crowi, app) {
     , flash          = require('connect-flash')
     , cons           = require('consolidate')
     , swig           = require('swig')
+    , i18next        = require('i18next')
+    , i18nFsBackend  = require('i18next-node-fs-backend')
+    , i18nSprintf    = require('i18next-sprintf-postprocessor')
+    , i18nMiddleware = require('i18next-express-middleware')
+    , i18nUserSettingDetector  = require('../util/i18nUserSettingDetector')
     , env            = crowi.node_env
     , middleware     = require('../util/middlewares')
+
+    , User = crowi.model('User')
     ;
 
+  var lngDetector = new i18nMiddleware.LanguageDetector();
+  lngDetector.addDetector(i18nUserSettingDetector);
+
+  i18next
+    .use(lngDetector)
+    .use(i18nFsBackend)
+    .use(i18nSprintf)
+    .init({
+      debug: (crowi.node_env === 'development'),
+      fallbackLng: [User.LANG_EN_US],
+      whitelist: Object.keys(User.getLanguageLabels()).map((k) => User[k]),
+      backend: {
+        loadPath: crowi.localeDir + '{{lng}}/translation.json'
+      },
+      detection: {
+        order: ['userSettingDetector', 'header', 'navigator'],
+      },
+      overloadTranslationOptionHandler: i18nSprintf.overloadTranslationOptionHandler
+    });
+
   app.use(function(req, res, next) {
     var now = new Date()
       , baseUrl
@@ -42,6 +68,7 @@ module.exports = function(crowi, app) {
     res.locals.consts   = {
         pageGrants: Page.getGrantLabels(),
         userStatus: User.getUserStatusLabels(),
+        language:   User.getLanguageLabels(),
         registrationMode: Config.getRegistrationModeLabels(),
     };
 
@@ -71,7 +98,6 @@ module.exports = function(crowi, app) {
   app.use(bodyParser.urlencoded({ extended: true, limit: '50mb' }));
   app.use(bodyParser.json({limit: '50mb'}));
   app.use(cookieParser());
-  app.use(multer());
   app.use(session(crowi.sessionConfig));
   app.use(flash());
 
@@ -80,4 +106,5 @@ module.exports = function(crowi, app) {
 
   app.use(middleware.loginChecker(crowi, app));
 
+  app.use(i18nMiddleware.handle(i18next));
 };

+ 17 - 8
lib/crowi/index.js

@@ -6,7 +6,6 @@ var debug = require('debug')('crowi:crowi')
   , path = require('path')
   , fs = require('fs')
   , sep = path.sep
-  , Promise = require('bluebird')
 
   , mongoose    = require('mongoose')
 
@@ -24,6 +23,7 @@ function Crowi (rootdir, env)
   this.publicDir = path.join(this.rootDir, 'public') + sep;
   this.libDir    = path.join(this.rootDir, 'lib') + sep;
   this.eventsDir = path.join(this.libDir, 'events') + sep;
+  this.localeDir = path.join(this.rootDir, 'locales') + sep;
   this.resourceDir = path.join(this.rootDir, 'resource') + sep;
   this.viewsDir  = path.join(this.libDir, 'views') + sep;
   this.mailDir   = path.join(this.viewsDir, 'mail') + sep;
@@ -55,16 +55,13 @@ function Crowi (rootdir, env)
   };
 
   if (this.node_env == 'development') {
-    Promise.longStackTraces();
   }
-
-  //time.tzset('Asia/Tokyo');
 };
 
 Crowi.prototype.init = function() {
   var self = this;
 
-  return new Promise.resolve()
+  return Promise.resolve()
   .then(function() {
     // setup database server and load all modesl
     return self.setupDatabase();
@@ -94,11 +91,21 @@ Crowi.prototype.init = function() {
     return self.setupSlack();
   }).then(function() {
     return self.setupCsrf();
-  }).then(function() {
-    return self.buildServer();
   });
 }
 
+Crowi.prototype.isPageId = function(pageId) {
+  if (!pageId) {
+    return false;
+  }
+
+  if (typeof pageId === 'string' && pageId.match(/^[\da-f]{24}$/)) {
+    return true;
+  }
+
+  return false;
+};
+
 Crowi.prototype.setConfig = function(config) {
   this.config = config;
 };
@@ -143,6 +150,8 @@ Crowi.prototype.event = function(name, event) {
 
 Crowi.prototype.setupDatabase = function() {
   // mongoUri = mongodb://user:password@host/dbname
+  mongoose.Promise = global.Promise;
+
   var mongoUri = this.env.MONGOLAB_URI || // for B.C.
     this.env.MONGODB_URI || // MONGOLAB changes their env name
     this.env.MONGOHQ_URL ||
@@ -328,7 +337,7 @@ Crowi.prototype.buildServer = function() {
     });
   }
 
-  return new Promise.resolve(app);
+  return Promise.resolve(app);
 };
 
 Crowi.prototype.exitOnError = function(err) {

+ 20 - 18
lib/form/index.js

@@ -1,19 +1,21 @@
-exports.login = require('./login');
-exports.register = require('./register');
-exports.invited = require('./invited');
-exports.revision = require('./revision');
-exports.comment = require('./comment');
-exports.me = {
-  user: require('./me/user'),
-  password: require('./me/password'),
-  apiToken: require('./me/apiToken'),
-};
-exports.admin = {
-  app: require('./admin/app'),
-  sec: require('./admin/sec'),
-  mail: require('./admin/mail'),
-  aws: require('./admin/aws'),
-  google: require('./admin/google'),
-  userInvite: require('./admin/userInvite'),
-  slackSetting: require('./admin/slackSetting'),
+module.exports = {
+  login: require('./login'),
+  register: require('./register'),
+  invited: require('./invited'),
+  revision: require('./revision'),
+  comment: require('./comment'),
+  me: {
+    user: require('./me/user'),
+    password: require('./me/password'),
+    apiToken: require('./me/apiToken'),
+  },
+  admin: {
+    app: require('./admin/app'),
+    sec: require('./admin/sec'),
+    mail: require('./admin/mail'),
+    aws: require('./admin/aws'),
+    google: require('./admin/google'),
+    userInvite: require('./admin/userInvite'),
+    slackSetting: require('./admin/slackSetting'),
+  },
 };

+ 1 - 1
lib/form/invited.js

@@ -6,6 +6,6 @@ var form = require('express-form')
 module.exports = form(
   field('invitedForm.username').required().is(/^[\da-zA-Z\-_]+$/),
   field('invitedForm.name').required(),
-  field('invitedForm.password').required().is(/^[\da-zA-Z@#$%-_&\+\*\?]{6,64}$/)
+  field('invitedForm.password').required().is(/^[\x20-\x7F]{6,}$/)
 );
 

+ 1 - 1
lib/form/login.js

@@ -5,5 +5,5 @@ var form = require('express-form')
 
 module.exports = form(
   field('loginForm.email').required(),
-  field('loginForm.password').required().is(/^[\x20-\x7F]{6,40}$/)
+  field('loginForm.password').required().is(/^[\x20-\x7F]{6,}$/)
 );

+ 1 - 2
lib/form/me/password.js

@@ -5,7 +5,6 @@ var form = require('express-form')
 
 module.exports = form(
   field('mePassword.oldPassword'),
-  field('mePassword.newPassword').required().is(/^[\x20-\x7F]{6,40}$/),
+  field('mePassword.newPassword').required().is(/^[\x20-\x7F]{6,}$/),
   field('mePassword.newPasswordConfirm').required()
 );
-  //[}m943&T^x7.2kB%98;9CD2Kx[kr{/v!4

+ 2 - 1
lib/form/me/user.js

@@ -5,5 +5,6 @@ var form = require('express-form')
 
 module.exports = form(
   field('userForm.name').trim().required(),
-  field('userForm.email').trim().isEmail().required()
+  field('userForm.email').trim().isEmail().required(),
+  field('userForm.lang').required()
 );

+ 1 - 1
lib/form/register.js

@@ -7,7 +7,7 @@ module.exports = form(
   field('registerForm.username').required().is(/^[\da-zA-Z\-_\.]+$/),
   field('registerForm.name').required(),
   field('registerForm.email').required(),
-  field('registerForm.password').required().is(/^[\x20-\x7F]{6,40}$/),
+  field('registerForm.password').required().is(/^[\x20-\x7F]{6,}$/),
   field('registerForm.googleId'),
   field('registerForm.googleImage')
 );

+ 1 - 2
lib/models/attachment.js

@@ -2,7 +2,6 @@ module.exports = function(crowi) {
   var debug = require('debug')('crowi:models:attachment')
     , mongoose = require('mongoose')
     , ObjectId = mongoose.Schema.Types.ObjectId
-    , Promise = require('bluebird')
     , fileUploader = require('../util/fileUploader')(crowi)
   ;
 
@@ -101,7 +100,7 @@ module.exports = function(crowi) {
   };
 
   attachmentSchema.statics.createAttachmentFilePath = function (pageId, fileName, fileType) {
-    var ext = '.' + fileName.match(/(.*)(?:\.([^.]+$))/)[2];
+    var ext = '.' + fileName.match(/(.*)(?:\.([^.]+$))/)[2] || '';
 
     return 'attachment/' + pageId + '/' + generateFileHash(fileName) + ext;
   };

+ 6 - 5
lib/models/page.js

@@ -329,10 +329,10 @@ module.exports = function(crowi) {
 
   pageSchema.statics.getGrantLabels = function() {
     var grantLabels = {};
-    grantLabels[GRANT_PUBLIC]     = '公開';
-    grantLabels[GRANT_RESTRICTED] = 'リンクを知っている人のみ';
-    //grantLabels[GRANT_SPECIFIED]  = '特定ユーザーのみ';
-    grantLabels[GRANT_OWNER]      = '自分のみ';
+    grantLabels[GRANT_PUBLIC]     = 'Public'; // 公開
+    grantLabels[GRANT_RESTRICTED] = 'Anyone with the link'; // リンクを知っている人のみ
+    //grantLabels[GRANT_SPECIFIED]  = 'Specified users only'; // 特定ユーザーのみ
+    grantLabels[GRANT_OWNER]      = 'Just me'; // 自分のみ
 
     return grantLabels;
   };
@@ -383,6 +383,7 @@ module.exports = function(crowi) {
       /^\/_r\/.*/,
       /^\/user\/[^\/]+\/(bookmarks|comments|activities|pages|recent-create|recent-edit)/, // reserved
       /^\/?https?:\/\/.+$/, // avoid miss in renaming
+      /\/{2,}/,             // avoid miss in renaming
       /.+\/edit$/,
       /.+\.md$/,
       /^\/(installer|register|login|logout|admin|me|files|trash|paste|comments)(\/.*|$)/,
@@ -579,7 +580,7 @@ module.exports = function(crowi) {
         {path: 'revision', model: 'Revision'},
       ])
       .sort({updatedAt: -1})
-      .stream();
+      .cursor();
   };
 
   /**

+ 7 - 0
lib/models/revision.js

@@ -60,6 +60,13 @@ module.exports = function(crowi) {
     });
   };
 
+  revisionSchema.statics.findRevisionIdList = function(path) {
+    return this.find({path: path})
+      .select('_id author createdAt')
+      .sort({createdAt: -1})
+      .exec();
+  };
+
   revisionSchema.statics.findRevisionList = function(path, options) {
     var Revision = this,
         User = crowi.model('User');

+ 47 - 13
lib/models/user.js

@@ -11,7 +11,12 @@ module.exports = function(crowi) {
     , STATUS_SUSPENDED  = 3
     , STATUS_DELETED    = 4
     , STATUS_INVITED    = 5
-    , USER_PUBLIC_FIELDS = '_id image googleId name username email introduction status createdAt admin' // TODO: どこか別の場所へ...
+    , USER_PUBLIC_FIELDS = '_id image googleId name username email introduction status lang createdAt admin' // TODO: どこか別の場所へ...
+
+    , LANG_EN    = 'en'
+    , LANG_EN_US = 'en-US'
+    , LANG_EN_GB = 'en-GB'
+    , LANG_JA    = 'ja'
 
     , PAGE_ITEMS        = 50
 
@@ -29,6 +34,11 @@ module.exports = function(crowi) {
     introduction: { type: String },
     password: String,
     apiToken: String,
+    lang: {
+      type: String,
+      enum: Object.keys(getLanguageLabels()).map((k) => eval(k)),
+      default: LANG_EN_US
+    },
     status: { type: Number, required: true, default: STATUS_ACTIVE, index: true  },
     createdAt: { type: Date, default: Date.now },
     admin: { type: Boolean, default: 0, index: true  }
@@ -84,6 +94,16 @@ module.exports = function(crowi) {
     return hasher.digest('base64');
   }
 
+  function getLanguageLabels() {
+    var lang = {};
+    lang.LANG_EN    = LANG_EN;
+    lang.LANG_EN_US = LANG_EN_US;
+    lang.LANG_EN_GB = LANG_EN_GB;
+    lang.LANG_JA    = LANG_JA;
+
+    return lang;
+  }
+
   userSchema.methods.isPasswordSet = function() {
     if (this.password) {
       return true;
@@ -107,9 +127,11 @@ module.exports = function(crowi) {
     return false;
   };
 
-  userSchema.methods.update = function(name, email, callback) {
+  userSchema.methods.update = function(name, email, lang, callback) {
     this.name = name;
     this.email = email;
+    this.lang = lang;
+
     this.save(function(err, userData) {
       return callback(err, userData);
     });
@@ -232,6 +254,7 @@ module.exports = function(crowi) {
     });
   };
 
+  userSchema.statics.getLanguageLabels = getLanguageLabels;
   userSchema.statics.getUserStatusLabels = function() {
     var userStatus = {};
     userStatus[STATUS_REGISTERED] = '承認待ち';
@@ -292,13 +315,18 @@ module.exports = function(crowi) {
     var User = this;
     var option = option || {}
       , sort = option.sort || {createdAt: -1}
-      , status = option.status || STATUS_ACTIVE
+      , status = option.status || [STATUS_ACTIVE, STATUS_SUSPENDED]
       , fields = option.fields || USER_PUBLIC_FIELDS
       ;
 
+    if (!Array.isArray(status)) {
+      status = [status];
+    }
+
     return new Promise(function(resolve, reject) {
       User
-        .find({status: status })
+        .find()
+        .or(status.map(s => { return {status: s}; }))
         .select(fields)
         .sort(sort)
         .exec(function (err, userData) {
@@ -347,13 +375,13 @@ module.exports = function(crowi) {
   userSchema.statics.findUsersWithPagination = function(options, callback) {
     var sort = options.sort || {status: 1, username: 1, createdAt: 1};
 
-    this.paginate({}, { page: options.page || 1, limit: PAGE_ITEMS }, function(err, paginatedResults, pageCount, itemCount) {
+    this.paginate({}, { page: options.page || 1, limit: options.limit || PAGE_ITEMS }, function(err, result) {
       if (err) {
         debug('Error on pagination:', err);
         return callback(err, null);
       }
 
-      return callback(err, paginatedResults, pageCount, itemCount);
+      return callback(err, result);
     }, { sortBy : sort });
   };
 
@@ -612,7 +640,7 @@ module.exports = function(crowi) {
     );
   };
 
-  userSchema.statics.createUserByEmailAndPassword = function(name, username, email, password, callback) {
+  userSchema.statics.createUserByEmailAndPassword = function(name, username, email, password, lang, callback) {
     var User = this
       , newUser = new User();
 
@@ -620,6 +648,7 @@ module.exports = function(crowi) {
     newUser.username = username;
     newUser.email = email;
     newUser.setPassword(password);
+    newUser.lang = lang;
     newUser.createdAt = Date.now();
     newUser.status = decideUserStatusOnRegistration();
 
@@ -647,13 +676,18 @@ module.exports = function(crowi) {
   };
 
 
-  userSchema.statics.STATUS_REGISTERED = STATUS_REGISTERED;
-  userSchema.statics.STATUS_ACTIVE = STATUS_ACTIVE;
-  userSchema.statics.STATUS_SUSPENDED = STATUS_SUSPENDED;
-  userSchema.statics.STATUS_DELETED = STATUS_DELETED;
-  userSchema.statics.STATUS_INVITED = STATUS_INVITED;
+  userSchema.statics.STATUS_REGISTERED  = STATUS_REGISTERED;
+  userSchema.statics.STATUS_ACTIVE      = STATUS_ACTIVE;
+  userSchema.statics.STATUS_SUSPENDED   = STATUS_SUSPENDED;
+  userSchema.statics.STATUS_DELETED     = STATUS_DELETED;
+  userSchema.statics.STATUS_INVITED     = STATUS_INVITED;
   userSchema.statics.USER_PUBLIC_FIELDS = USER_PUBLIC_FIELDS;
-  userSchema.statics.PAGE_ITEMS = PAGE_ITEMS;
+  userSchema.statics.PAGE_ITEMS         = PAGE_ITEMS;
+
+  userSchema.statics.LANG_EN            = LANG_EN;
+  userSchema.statics.LANG_EN_US         = LANG_EN_US;
+  userSchema.statics.LANG_EN_GB         = LANG_EN_US;
+  userSchema.statics.LANG_JA            = LANG_JA;
 
   return mongoose.model('User', userSchema);
 };

+ 32 - 34
lib/routes/admin.js

@@ -11,33 +11,36 @@ module.exports = function(crowi, app) {
     , MAX_PAGE_LIST = 5
     , actions = {};
 
-  function createPager(currentPage, pageCount, itemCount, maxPageList) {
-    var pager = {};
-    pager.currentPage = currentPage;
-    pager.pageCount = pageCount;
-    pager.itemCount = itemCount;
-
-    pager.previous = null;
-    if (currentPage > 1) {
-      pager.previous = currentPage - 1;
+  function createPager(total, limit, page, pagesCount, maxPageList) {
+    const pager = {
+      page: page,
+      pagesCount: pagesCount,
+      pages: [],
+      total: total,
+      previous: null,
+      previousDots: false,
+      next: null,
+      nextDots: false,
+    };
+
+    if (page > 1) {
+      pager.previous = page - 1;
     }
 
-    pager.next = null;
-    if (currentPage < pageCount) {
-      pager.next = currentPage + 1;
+    if (page < pagesCount) {
+      pager.next = page + 1;
     }
 
-    pager.pages = [];
-    var pagerMin = Math.max(1, Math.ceil(currentPage - maxPageList/2));
-    var pagerMax = Math.min(pageCount, Math.floor(currentPage + maxPageList/2));
-    if (pagerMin == 1) {
-      if (MAX_PAGE_LIST < pageCount) {
+    let pagerMin = Math.max(1, Math.ceil(page - maxPageList/2));
+    let pagerMax = Math.min(pagesCount, Math.floor(page + maxPageList/2));
+    if (pagerMin === 1) {
+      if (MAX_PAGE_LIST < pagesCount) {
         pagerMax = MAX_PAGE_LIST;
       } else {
-        pagerMax = pageCount;
+        pagerMax = pagesCount;
       }
     }
-    if (pagerMax == pageCount) {
+    if (pagerMax === pagesCount) {
       if ((pagerMax - MAX_PAGE_LIST) < 1) {
         pagerMin = 1;
       } else {
@@ -51,13 +54,11 @@ module.exports = function(crowi, app) {
     }
 
     pager.nextDots = null;
-    if (pagerMax < pageCount) {
+    if (pagerMax < pagesCount) {
       pager.nextDots = true;
     }
 
-    for (var i = pagerMin;
-      i <= pagerMax;
-      i++) {
+    for (let i = pagerMin; i <= pagerMax; i++) {
       pager.pages.push(i);
     }
 
@@ -208,19 +209,15 @@ module.exports = function(crowi, app) {
           if (!data.errors) {
             debug('Data is successfully indexed.');
           } else {
-            debug('Data index error.', data);
+            debug('Data index error.', data.errors);
           }
-
-          //return res.json(ApiResponse.success({}));
-          req.flash('successMessage', 'Successfully re-build index.');
-          return res.redirect('/admin/search');
         })
         .catch(function(err) {
           debug('Error', err);
-          req.flash('errorMessage', 'Error');
-          return res.redirect('/admin/search');
-          //return res.json(ApiResponse.error(err));
         });
+
+      req.flash('successMessage', 'Now re-building index ... this takes a while.');
+      return res.redirect('/admin/search');
     });
   };
 
@@ -228,10 +225,11 @@ module.exports = function(crowi, app) {
   actions.user.index = function(req, res) {
     var page = parseInt(req.query.page) || 1;
 
-    User.findUsersWithPagination({page: page}, function(err, users, pageCount, itemCount) {
-      var pager = createPager(page, pageCount, itemCount, MAX_PAGE_LIST);
+    User.findUsersWithPagination({page: page}, function(err, result) {
+      const pager = createPager(result.total, result.limit, result.page, result.pages, MAX_PAGE_LIST);
+
       return res.render('admin/users', {
-        users: users,
+        users: result.docs,
         pager: pager
       });
     });

+ 18 - 16
lib/routes/attachment.js

@@ -5,7 +5,6 @@ module.exports = function(crowi, app) {
     , Attachment = crowi.model('Attachment')
     , User = crowi.model('User')
     , Page = crowi.model('Page')
-    , Promise = require('bluebird')
     , config = crowi.getConfig()
     , fs = require('fs')
     , fileUploader = require('../util/fileUploader')(crowi, app)
@@ -61,14 +60,14 @@ module.exports = function(crowi, app) {
    * @apiParam {File} file
    */
   api.add = function(req, res){
-    var id = req.body.page_id,
-      path = decodeURIComponent(req.body.path),
+    var id = req.body.page_id || 0,
+      path = decodeURIComponent(req.body.path) || null,
       pageCreated = false,
       page = {};
 
     debug('id and path are: ', id, path);
 
-    var tmpFile = req.files.file || null;
+    var tmpFile = req.file || null;
     debug('Uploaded tmpFile: ', tmpFile);
     if (!tmpFile) {
       return res.json(ApiResponse.error('File error.'));
@@ -76,6 +75,9 @@ module.exports = function(crowi, app) {
 
     new Promise(function(resolve, reject) {
       if (id == 0) {
+        if (path === null) {
+          throw new Error('path required if page_id is not specified.');
+        }
         debug('Create page before file upload');
         Page.create(path, '# '  + path, req.user, {grant: Page.GRANT_OWNER})
           .then(function(page) {
@@ -92,7 +94,7 @@ module.exports = function(crowi, app) {
 
       var tmpPath = tmpFile.path,
         originalName = tmpFile.originalname,
-        fileName = tmpFile.name,
+        fileName = tmpFile.filename + tmpFile.originalname,
         fileType = tmpFile.mimetype,
         fileSize = tmpFile.size,
         filePath = Attachment.createAttachmentFilePath(id, fileName, fileType),
@@ -110,29 +112,29 @@ module.exports = function(crowi, app) {
             page: page.toObject(),
             attachment: data.toObject(),
             filename: imageUrl,
-            pageCreatet: pageCreated,
+            pageCreated: pageCreated,
           };
 
-          debug('atta creator', data.creator);
-          debug('atta creator', result.attachment.creator);
           result.page.creator = User.filterToPublicFields(result.page.creator);
           result.attachment.creator = User.filterToPublicFields(result.attachment.creator);
-          debug('atta creator', result.attachment.creator);
+
+          // delete anyway
+          fs.unlink(tmpPath, function (err) { if (err) { debug('Error while deleting tmp file.'); } });
+
           return res.json(ApiResponse.success(result));
         }).catch(function (err) {
           debug('Error on saving attachment data', err);
           // @TODO
           // Remove from S3
+
+          // delete anyway
+          fs.unlink(tmpPath, function (err) { if (err) { debug('Error while deleting tmp file.'); } });
+
           return res.json(ApiResponse.error('Error while uploading.'));
-        }).finally(function() {
-          fs.unlink(tmpPath, function (err) {
-            if (err) {
-              debug('Error while deleting tmp file.');
-            }
-          });
-        })
+        });
       ;
     }).catch(function(err) {
+      debug('Attachement upload error', err);
       return res.json(ApiResponse.error('Error.'));
     });
   };

+ 7 - 3
lib/routes/index.js

@@ -1,5 +1,7 @@
 module.exports = function(crowi, app) {
   var middleware = require('../util/middlewares')
+    , multer    = require('multer')
+    , uploads   = multer({dest: crowi.tmpDir + 'uploads'})
     , form      = require('../form')
     , page      = require('./page')(crowi, app)
     , login     = require('./login')(crowi, app)
@@ -85,7 +87,7 @@ module.exports = function(crowi, app) {
   app.get( '/_api/search'             , accessTokenParser , loginRequired(crowi, app) , search.api.search);
 
   app.get( '/_api/check_username'     , user.api.checkUsername);
-  app.post('/_api/me/picture/upload'  , loginRequired(crowi, app) , me.api.uploadPicture);
+  app.post('/_api/me/picture/upload'  , loginRequired(crowi, app) , uploads.single('userPicture'), me.api.uploadPicture);
   app.get( '/_api/user/bookmarks'     , loginRequired(crowi, app) , user.api.bookmarks);
 
   app.get( '/user/:username([^/]+)/bookmarks'      , loginRequired(crowi, app) , page.userBookmarkList);
@@ -94,6 +96,7 @@ module.exports = function(crowi, app) {
   // HTTP RPC Styled API (に徐々に移行していいこうと思う)
   app.get('/_api/users.list'          , accessTokenParser , loginRequired(crowi, app) , user.api.list);
   app.post('/_api/pages.create'       , accessTokenParser , loginRequired(crowi, app) , csrf, page.api.create);
+  app.post('/_api/pages.update'       , accessTokenParser , loginRequired(crowi, app) , csrf, page.api.update);
   app.get('/_api/pages.get'           , accessTokenParser , loginRequired(crowi, app) , page.api.get);
   app.get('/_api/pages.updatePost'    , accessTokenParser , loginRequired(crowi, app) , page.api.getUpdatePost);
   app.post('/_api/pages.seen'         , accessTokenParser , loginRequired(crowi, app) , page.api.seen);
@@ -108,11 +111,12 @@ module.exports = function(crowi, app) {
   app.post('/_api/likes.add'          , accessTokenParser , loginRequired(crowi, app) , csrf, page.api.like);
   app.post('/_api/likes.remove'       , accessTokenParser , loginRequired(crowi, app) , csrf, page.api.unlike);
   app.get( '/_api/attachments.list'   , accessTokenParser , loginRequired(crowi, app) , attachment.api.list);
-  app.post('/_api/attachments.add'    , accessTokenParser , loginRequired(crowi, app) , csrf, attachment.api.add);
+  app.post('/_api/attachments.add'    , uploads.single('file'), accessTokenParser, loginRequired(crowi, app) ,csrf, attachment.api.add);
   app.post('/_api/attachments.remove' , accessTokenParser , loginRequired(crowi, app) , csrf, attachment.api.remove);
 
   app.get( '/_api/revisions.get'      , accessTokenParser , loginRequired(crowi, app) , revision.api.get);
-  app.get( '/_api/revisions.list'     , accessTokenParser , loginRequired(crowi, app) ,revision.api.list);
+  app.get( '/_api/revisions.ids'      , accessTokenParser , loginRequired(crowi, app) , revision.api.ids);
+  app.get( '/_api/revisions.list'     , accessTokenParser , loginRequired(crowi, app) , revision.api.list);
 
   //app.get('/_api/revision/:id'     , user.useUserData()         , revision.api.get);
   //app.get('/_api/r/:revisionId'    , user.useUserData()         , page.api.get);

+ 3 - 2
lib/routes/installer.js

@@ -14,6 +14,7 @@ module.exports = function(crowi, app) {
 
   actions.createAdmin = function(req, res) {
     var registerForm = req.body.registerForm || {};
+    var language = req.language || 'en';
 
     if (req.form.isValid) {
       var name = registerForm.name;
@@ -21,7 +22,7 @@ module.exports = function(crowi, app) {
       var email = registerForm.email;
       var password = registerForm.password;
 
-      User.createUserByEmailAndPassword(name, username, email, password, function(err, userData) {
+      User.createUserByEmailAndPassword(name, username, email, password, language, function(err, userData) {
         if (err) {
           req.form.errors.push('管理ユーザーの作成に失敗しました。' + err.message);
           // TODO
@@ -38,7 +39,7 @@ module.exports = function(crowi, app) {
             // login処理
             req.user = req.session.user = userData;
             req.flash('successMessage', 'Crowi のインストールが完了しました!はじめに、このページでこの Wiki の各種設定を確認してください。');
-            return res.redirect('admin/app');
+            return res.redirect('/admin/app');
           });
         });
       });

+ 10 - 9
lib/routes/login.js

@@ -39,7 +39,7 @@ module.exports = function(crowi, app) {
   };
 
   var loginFailure = function(req, res) {
-    req.flash('warningMessage', 'ログインに失敗しました');
+    req.flash('warningMessage', 'Sign in failure.');
     return res.redirect('/login');
   };
 
@@ -59,9 +59,9 @@ module.exports = function(crowi, app) {
       ;
 
     if (reason === 'suspended') {
-      reasonMessage = 'このアカウントは停止されています。';
+      reasonMessage = 'This account is suspended.';
     } else if (reason === 'registered') {
-      reasonMessage = '管理者の承認をお待ちください。';
+      reasonMessage = 'Wait for approved by administrators.';
     } else {
     }
 
@@ -129,6 +129,7 @@ module.exports = function(crowi, app) {
 
   actions.register = function(req, res) {
     var googleAuth = require('../util/googleAuth')(config);
+    var lang= req.lang || User.LANG_EN_US;
 
     // ログイン済みならさようなら
     if (req.user) {
@@ -155,16 +156,16 @@ module.exports = function(crowi, app) {
         var isError = false;
         if (!User.isEmailValid(email)) {
           isError = true;
-          req.flash('registerWarningMessage', 'このメールアドレスは登録できません。(ホワイトリストなどを確認してください)');
+          req.flash('registerWarningMessage', 'This email address could not be used. (Make sure the allowed email address)');
         }
         if (!isRegisterable) {
           if (!errOn.username) {
             isError = true;
-            req.flash('registerWarningMessage', 'このユーザーIDは利用できません。');
+            req.flash('registerWarningMessage', 'This User ID is not available.');
           }
           if (!errOn.email) {
             isError = true;
-            req.flash('registerWarningMessage', 'このメールアドレスは登録済みです。');
+            req.flash('registerWarningMessage', 'This email address is already registered.');
           }
 
         }
@@ -173,9 +174,9 @@ module.exports = function(crowi, app) {
           return res.redirect('/register');
         }
 
-        User.createUserByEmailAndPassword(name, username, email, password, function(err, userData) {
+        User.createUserByEmailAndPassword(name, username, email, password, lang, function(err, userData) {
           if (err) {
-            req.flash('registerWarningMessage', 'ユーザー登録に失敗しました。');
+            req.flash('registerWarningMessage', 'Failed to register.');
             return res.redirect('/register');
           } else {
 
@@ -272,7 +273,7 @@ module.exports = function(crowi, app) {
           req.session.googleAuthCode = null;
 
           if (err) {
-            req.flash('registerWarningMessage', 'Googleコネクト中にエラーが発生しました。');
+            req.flash('registerWarningMessage', 'Error on connectiong Google');
             return res.redirect('/login?register=1'); // TODO Handling
           }
 

+ 17 - 15
lib/routes/me.js

@@ -20,7 +20,7 @@ module.exports = function(crowi, app) {
     //var storagePlugin = new pluginService('storage');
     //var storage = require('../service/storage').StorageService(config);
 
-    var tmpFile = req.files.userPicture || null;
+    var tmpFile = req.file || null;
     if (!tmpFile) {
       return res.json({
         'status': false,
@@ -29,7 +29,7 @@ module.exports = function(crowi, app) {
     }
 
     var tmpPath = tmpFile.path;
-    var filePath = User.createUserPictureFilePath(req.user, tmpFile.name);
+    var filePath = User.createUserPictureFilePath(req.user, tmpFile.filename + tmpFile.originalname);
     var acceptableFileType = /image\/.+/;
 
     if (!tmpFile.mimetype.match(acceptableFileType)) {
@@ -82,13 +82,14 @@ module.exports = function(crowi, app) {
     if (req.method == 'POST' && req.form.isValid) {
       var name = userForm.name;
       var email = userForm.email;
+      var lang= userForm.lang;
 
       if (!User.isEmailValid(email)) {
-        req.form.errors.push('このメールアドレスは登録できません。(ホワイトリストなどを確認してください)');
+        req.form.errors.push('You can\'t update to that email address');
         return res.render('me/index', {});
       }
 
-      userData.update(name, email, function(err, userData) {
+      userData.update(name, email, lang, function(err, userData) {
         if (err) {
           for (var e in err.errors) {
             if (err.errors.hasOwnProperty(e)) {
@@ -98,7 +99,8 @@ module.exports = function(crowi, app) {
           return res.render('me/index', {});
         }
 
-        req.flash('successMessage', '更新しました');
+        req.i18n.changeLanguage(lang);
+        req.flash('successMessage', req.t('Updated'));
         return res.redirect('/me');
       });
     } else { // method GET
@@ -128,14 +130,14 @@ module.exports = function(crowi, app) {
       var oldPassword = passwordForm.oldPassword;
 
       if (userData.isPasswordSet() && !userData.isPasswordValid(oldPassword)) {
-        req.form.errors.push('現在のパスワードが違います。');
+        req.form.errors.push('Wrong current password');
         return res.render('me/password', {
         });
       }
 
       // check password confirm
       if (newPassword != newPasswordConfirm) {
-        req.form.errors.push('確認用パスワードが一致しません');
+        req.form.errors.push('Failed to verify passwords');
       } else {
         userData.updatePassword(newPassword, function(err, userData) {
           if (err) {
@@ -147,7 +149,7 @@ module.exports = function(crowi, app) {
             return res.render('me/password', {});
           }
 
-          req.flash('successMessage', 'パスワードを変更しました');
+          req.flash('successMessage', 'Password updated');
           return res.redirect('/me/password');
         });
       }
@@ -164,12 +166,12 @@ module.exports = function(crowi, app) {
     if (req.method == 'POST' && req.form.isValid) {
       userData.updateApiToken()
       .then(function(userData) {
-          req.flash('successMessage', 'API Token を更新しました');
+          req.flash('successMessage', 'API Token updated');
           return res.redirect('/me/apiToken');
       })
       .catch(function(err) {
           //req.flash('successMessage',);
-          req.form.errors.push('API Token の更新に失敗しました');
+          req.form.errors.push('Failed to update API Token');
           return res.render('me/api_token', {
           });
       });
@@ -187,7 +189,7 @@ module.exports = function(crowi, app) {
   actions.deletePicture = function(req, res) {
     // TODO: S3 からの削除
     req.user.deleteImage(function(err, data) {
-      req.flash('successMessage', 'プロフィール画像を削除しました');
+      req.flash('successMessage', 'Deleted profile picture');
       res.redirect('/me');
     });
   };
@@ -201,7 +203,7 @@ module.exports = function(crowi, app) {
     var toConnect = req.body.connectGoogle ? true : false;
     if (toDisconnect) {
       userData.deleteGoogleId(function(err, userData) {
-        req.flash('successMessage', 'Googleコネクトを解除しました。');
+        req.flash('successMessage', 'Disconnected from Google account');
 
         return res.redirect('/me');
       });
@@ -232,13 +234,13 @@ module.exports = function(crowi, app) {
       var googleId = tokenInfo.user_id;
       var googleEmail = tokenInfo.email;
       if (!User.isEmailValid(googleEmail)) {
-        req.flash('warningMessage.auth.google', 'このメールアドレスのGoogleアカウントはコネクトできません。');
+        req.flash('warningMessage.auth.google', 'You can\'t connect with this  Google\'s account');
         return res.redirect('/me');
       }
 
       User.findUserByGoogleId(googleId, function(err, googleUser) {
         if (!err && googleUser) {
-          req.flash('warningMessage.auth.google', 'このGoogleアカウントは他のユーザーがコネクト済みです。');
+          req.flash('warningMessage.auth.google', 'This Google\'s account is connected by another user');
           return res.redirect('/me');
         } else {
           userData.updateGoogleId(googleId, function(err, userData) {
@@ -249,7 +251,7 @@ module.exports = function(crowi, app) {
             }
 
             // TODO if err
-            req.flash('successMessage', 'Googleコネクトを設定しました。');
+            req.flash('successMessage', 'Connected with Google');
             return res.redirect('/me');
           });
         }

+ 40 - 6
lib/routes/page.js

@@ -12,6 +12,14 @@ module.exports = function(crowi, app) {
 
     , actions = {};
 
+  // register page events
+
+  var pageEvent = crowi.event('page');
+  pageEvent.on('update', function(page, user) {
+    crowi.getIo().sockets.emit('page edited', {page, user});
+  });
+
+
   function getPathFromRequest(req) {
     var path = '/' + (req.params[0] || '');
     return path.replace(/\.md$/, '');
@@ -395,7 +403,6 @@ module.exports = function(crowi, app) {
         throw new Error('Data not found');
       }
       // TODO: move to events
-      crowi.getIo().sockets.emit('page edited', {page: data, user: req.user});
       if (notify.slack) {
         if (notify.slack.on && notify.slack.channel) {
           data.updateSlackChannel(notify.slack.channel).then(function(){}).catch(function(){});
@@ -568,16 +575,43 @@ module.exports = function(crowi, app) {
    * @apiParam {String} body
    * @apiParam {String} page_id
    * @apiParam {String} revision_id
+   * @apiParam {String} grant
    *
    * In the case of the page exists:
    * - If revision_id is specified => update the page,
-   * - If revision_id is not specified => error.
+   * - If revision_id is not specified => force update by the new contents.
    */
   api.update = function(req, res){
-    var pagePath = req.query.path || null;
-    var pageId = req.query.page_id || null;
-    var revisionId = req.query.revision_id || null;
+    var pageBody = req.body.body || null;
+    var pageId = req.body.page_id || null;
+    var revisionId = req.body.revision_id || null;
+    var grant = req.body.grant || null;
 
+    if (pageId === null || pageBody === null) {
+      return res.json(ApiResponse.error('page_id and body are required.'));
+    }
+
+    Page.findPageByIdAndGrantedUser(pageId, req.user)
+    .then(function(pageData) {
+      if (pageData && revisionId !== null && !pageData.isUpdatable(revisionId)) {
+        throw new Error('Revision error.');
+      };
+
+      var grantOption = {grant: pageData.grant};
+      if (grant !== null) {
+        grantOption.grant = grant;
+      }
+      return Page.updatePage(pageData, pageBody, req.user, grantOption);
+    }).then(function(pageData) {
+      var result = {
+        page: pageData.toObject(),
+      };
+      result.page.lastUpdateUser = User.filterToPublicFields(result.page.lastUpdateUser);
+      return res.json(ApiResponse.success(result));
+    }).catch(function(err) {
+      debug('error on _api/pages.update', err);
+      return res.json(ApiResponse.error(err));
+    });
   };
 
   /**
@@ -809,7 +843,7 @@ module.exports = function(crowi, app) {
 
         return res.json(ApiResponse.success(result));
       }).catch(function(err) {
-        return res.json(ApiResponse.error('エラーが発生しました。ページを更新できません。'));
+        return res.json(ApiResponse.error('Failed to update page.'));
       });
     });
   };

+ 30 - 1
lib/routes/revision.js

@@ -22,13 +22,42 @@ module.exports = function(crowi, app) {
     Revision
       .findRevision(revisionId)
       .then(function(revisionData) {
-        return res.json(ApiResponse.success(revisionData));
+        var result = {
+          revision: revisionData,
+        }
+        return res.json(ApiResponse.success(result));
       })
       .catch(function(err) {
+        debug('Error revisios.get', err);
         return res.json(ApiResponse.error(err));
       });
   };
 
+  /**
+   * @api {get} /revisions.ids Get revision id list of the page
+   * @apiName ids
+   * @apiGroup Revision
+   *
+   * @apiParam {String} page_id      Page Id.
+   */
+  actions.api.ids = function(req, res) {
+    var pageId = req.query.page_id || null;
+
+    if (pageId && crowi.isPageId(pageId)) {
+      Page.findPageByIdAndGrantedUser(pageId, req.user)
+      .then(function(pageData) {
+        debug('Page found', pageData._id, pageData.path);
+        return Revision.findRevisionIdList(pageData.path);
+      }).then(function(revisions) {
+        return res.json(ApiResponse.success({revisions}));
+      }).catch(function(err) {
+        return res.json(ApiResponse.error(err));
+      });
+    } else {
+      return res.json(ApiResponse.error('Parameter error.'));
+    }
+  };
+
   /**
    * @api {get} /revisions.list Get revisions
    * @apiName ListRevision

+ 19 - 0
lib/util/i18nUserSettingDetector.js

@@ -0,0 +1,19 @@
+module.exports = {
+  name: 'userSettingDetector',
+
+  lookup: function(req, res, options) {
+    var lang = null;
+
+    if (req.user) {
+      if ('lang' in req.user) {
+        lang = req.user.lang || null;
+      }
+    }
+
+    return lang;
+  },
+
+  cacheUserlanguage: function(req, res, lng, options) {
+    // nothing to do
+  }
+};

+ 2 - 1
lib/util/middlewares.js

@@ -43,6 +43,7 @@ exports.csrfVerify = function(crowi, app) {
       return next();
     }
 
+    debug('csrf verification failed. return 403', csrfKey, token);
     return res.sendStatus(403);
   };
 };
@@ -188,7 +189,7 @@ exports.loginRequired = function(crowi, app) {
 
 exports.accessTokenParser = function(crowi, app) {
   return function(req, res, next) {
-    var accessToken = req.query.access_token || req.body.access_token || null;
+    var accessToken = req.query.access_token || req.body.access_token || req.get('Authorization') || null;
     if (!accessToken) {
       return next();
     }

+ 136 - 18
lib/util/search.js

@@ -19,6 +19,7 @@ function SearchClient(crowi, esUri) {
   this.client = new elasticsearch.Client({
     host: this.host,
     requestTimeout: 5000,
+    //log: 'debug',
   });
 
   this.registerUpdateEvent();
@@ -208,11 +209,13 @@ SearchClient.prototype.addAllPages = function()
   var self = this;
   var offset = 0;
   var Page = this.crowi.model('Page');
-  var stream = Page.getStreamOfFindAll();
+  var cursor = Page.getStreamOfFindAll();
   var body = [];
 
+  var counter = 0;
+
   return new Promise(function(resolve, reject) {
-    stream.on('data', function (doc) {
+    cursor.on('data', function (doc) {
       if (!doc.creator || !doc.revision || !self.shouldIndexed(doc)) {
         debug('Skipped', doc.path);
         return ;
@@ -221,7 +224,7 @@ SearchClient.prototype.addAllPages = function()
       self.prepareBodyForCreate(body, doc);
     }).on('error', function (err) {
       // TODO: handle err
-      debug('Error stream:', err);
+      debug('Error cursor:', err);
     }).on('close', function () {
       // all done
 
@@ -276,7 +279,7 @@ SearchClient.prototype.search = function(query)
 SearchClient.prototype.createSearchQuerySortedByUpdatedAt = function(option)
 {
   // getting path by default is almost for debug
-  var fields = ['path', '_id'];
+  var fields = ['path'];
   if (option) {
     fields = option.fields || fields;
   }
@@ -286,9 +289,9 @@ SearchClient.prototype.createSearchQuerySortedByUpdatedAt = function(option)
     index: this.index_name,
     type: 'pages',
     body: {
-      fields: fields,
       sort: [{ updated_at: { order: 'desc'}}],
       query: {}, // query
+      _source: fields,
     }
   };
   this.appendResultSize(query);
@@ -298,7 +301,7 @@ SearchClient.prototype.createSearchQuerySortedByUpdatedAt = function(option)
 
 SearchClient.prototype.createSearchQuerySortedByScore = function(option)
 {
-  var fields = ['path', '_id'];
+  var fields = ['path'];
   if (option) {
     fields = option.fields || fields;
   }
@@ -308,9 +311,9 @@ SearchClient.prototype.createSearchQuerySortedByScore = function(option)
     index: this.index_name,
     type: 'pages',
     body: {
-      fields: fields,
       sort: [ {_score: { order: 'desc'} }],
       query: {}, // query
+      _source: fields,
     }
   };
   this.appendResultSize(query);
@@ -330,21 +333,88 @@ SearchClient.prototype.appendCriteriaForKeywordContains = function(query, keywor
   if (!query.body.query.bool) {
     query.body.query.bool = {};
   }
-
   if (!query.body.query.bool.must || !Array.isArray(query.body.query.must)) {
     query.body.query.bool.must = [];
   }
+  if (!query.body.query.bool.must_not || !Array.isArray(query.body.query.must_not)) {
+    query.body.query.bool.must_not = [];
+  }
 
-  query.body.query.bool.must.push({
-    multi_match: {
-      query: keyword,
-      fields: [
-        "path.ja^2", // ためしに。
-        "body.ja"
-      ],
-      operator: "and"
+  var appendMultiMatchQuery = function(query, type, keywords) {
+    var target;
+    var operator = 'and';
+    switch (type) {
+      case 'not_match':
+        target = query.body.query.bool.must_not;
+        operator = 'or';
+        break;
+      case 'match':
+      default:
+        target = query.body.query.bool.must;
     }
-  });
+
+    target.push({
+      multi_match: {
+        query: keywords.join(' '),
+        // TODO: By user's i18n setting, change boost or search target fields
+        fields: [
+          "path_ja^2",
+          "body_ja",
+          // "path_en",
+          // "body_en",
+        ],
+        operator: operator,
+      }
+    });
+
+    return query;
+  };
+
+  var parsedKeywords = this.getParsedKeywords(keyword);
+
+  if (parsedKeywords.match.length > 0) {
+    query = appendMultiMatchQuery(query, 'match', parsedKeywords.match);
+  }
+
+  if (parsedKeywords.not_match.length > 0) {
+    query = appendMultiMatchQuery(query, 'not_match', parsedKeywords.not_match);
+  }
+
+  if (parsedKeywords.phrase.length > 0) {
+    var phraseQueries = [];
+    parsedKeywords.phrase.forEach(function(phrase) {
+      phraseQueries.push({
+        multi_match: {
+          query: phrase, // each phrase is quoteted words
+          type: 'phrase',
+          fields: [ // Not use "*.ja" fields here, because we want to analyze (parse) search words
+            "path_raw^2",
+            "body_raw",
+          ],
+        }
+      });
+    });
+
+    query.body.query.bool.must.push(phraseQueries);
+  }
+
+  if (parsedKeywords.not_phrase.length > 0) {
+    var notPhraseQueries = [];
+    parsedKeywords.not_phrase.forEach(function(phrase) {
+      notPhraseQueries.push({
+        multi_match: {
+          query: phrase, // each phrase is quoteted words
+          type: 'phrase',
+          fields: [ // Not use "*.ja" fields here, because we want to analyze (parse) search words
+            "path_raw^2",
+            "body_raw",
+          ],
+        }
+      });
+    });
+
+    query.body.query.bool.must_not.push(notPhraseQueries);
+  }
 };
 
 SearchClient.prototype.appendCriteriaForPathFilter = function(query, path)
@@ -363,7 +433,7 @@ SearchClient.prototype.appendCriteriaForPathFilter = function(query, path)
   }
   query.body.query.bool.filter.push({
     wildcard: {
-      "path.raw": path + "/*"
+      "path": path + "/*"
     }
   });
 };
@@ -396,6 +466,54 @@ SearchClient.prototype.searchKeywordUnderPath = function(keyword, path, option)
   return this.search(query);
 };
 
+SearchClient.prototype.getParsedKeywords = function(keyword)
+{
+  var matchWords = [];
+  var notMatchWords = [];
+  var phraseWords = [];
+  var notPhraseWords = [];
+
+  keyword.trim();
+  keyword = keyword.replace(/\s+/g, ' ');
+
+  // First: Parse phrase keywords
+  var phraseRegExp = new RegExp(/(-?"[^"]+")/g);
+  var phrases = keyword.match(phraseRegExp);
+
+  if (phrases !== null) {
+    keyword = keyword.replace(phraseRegExp, '');
+
+    phrases.forEach(function(phrase) {
+      phrase.trim();
+      if (phrase.match(/^\-/)) {
+        notPhraseWords.push(phrase.replace(/^\-/, ''));
+      } else {
+        phraseWords.push(phrase);
+      }
+    });
+  }
+
+  // Second: Parse other keywords (include minus keywords)
+  keyword.split(' ').forEach(function(word) {
+    if (word === '') {
+      return;
+    }
+
+    if (word.match(/^\-(.+)$/)) {
+      notMatchWords.push((RegExp.$1));
+    } else {
+      matchWords.push(word);
+    }
+  });
+
+  return {
+    match: matchWords,
+    not_match: notMatchWords,
+    phrase: phraseWords,
+    not_phrase: notPhraseWords,
+  };
+}
+
 SearchClient.prototype.syncPageCreated = function(page, user)
 {
   debug('SearchClient.syncPageCreated', page.path);

+ 2 - 2
lib/views/_form.html

@@ -45,12 +45,12 @@
         {% else %}
         <select name="pageForm[grant]" class="form-control">
           {% for grantId, grantLabel in consts.pageGrants %}
-          <option value="{{ grantId }}" {% if pageForm.grant|default(page.grant) == grantId %}selected{% endif %}>{{ grantLabel }}</option>
+          <option value="{{ grantId }}" {% if pageForm.grant|default(page.grant) == grantId %}selected{% endif %}>{{ t(grantLabel) }}</option>
           {% endfor %}
         </select>
         {% endif %}
         <input type="hidden" id="edit-form-csrf" name="_csrf" value="{{ csrf() }}">
-        <input type="submit" class="btn btn-primary" id="edit-form-submit" value="ページを更新" />
+        <input type="submit" class="btn btn-primary" id="edit-form-submit" value="{{ t('Update Page') }}" />
       </div>
     </div>
   </form>

+ 1 - 20
lib/views/admin/users.html

@@ -256,26 +256,7 @@
         </tbody>
       </table>
 
-      <ul class="pagination">
-
-        <li {% if pager.currentPage == 1 %}class="disabled"{% endif %}>
-          <a href="/admin/users?page={{ pager.previous|default(1) }}">&laquo;</a>
-        </li>
-        {% if pager.previousDots %}
-        <li><a href="#">...</a></li>
-        {% endif  %}
-        {% for page in pager.pages %}
-        <li {% if pager.currentPage == page %}class="active"{% endif %}>
-          <a href="/admin/users?page={{ page }}">{{ page }}</a>
-        </li>
-        {% endfor %}
-        {% if pager.nextDots %}
-        <li><a href="#">...</a></li>
-        {% endif  %}
-        <li {% if pager.currentPage == pager.pageCount %}class="disabled"{% endif %}>
-          <a href="/admin/users?page={{ pager.next|default(pager.pageCount) }}">&raquo;</a>
-        </li>
-      </ul>
+      {% include '../widget/pager.html' with {path: "/admin/users", pager: pager} %}
 
     </div>
   </div>

+ 3 - 3
lib/views/layout/2column.html

@@ -19,7 +19,7 @@
   <div id="footer-container" class="footer">
     <footer class="">
       <p>
-      <a href="" data-target="#help-modal" data-toggle="modal"><i class="fa fa-question-circle"> ヘルプ</i></a>
+      <a href="" data-target="#help-modal" data-toggle="modal"><i class="fa fa-question-circle"></i> {{ t('Help') }}</a>
       &copy; {{ now|date('Y') }} {{ config.crowi['app:title']|default('Crowi') }} <img src="/logo/100x11_g.png" alt="powered by Crowi"> </p>
     </footer>
   </div>
@@ -31,12 +31,12 @@
 <div id="main" class="main col-md-9 {% if page %}{{ css.grant(page) }}{% endif %} {% block main_css_class %}{% endblock %}">
   {% if page && page.grant != 1 %}
   <p class="page-grant">
-    <i class="fa fa-lock"></i> {{ consts.pageGrants[page.grant] }} (このページの閲覧は制限されています)
+    <i class="fa fa-lock"></i> {{ consts.pageGrants[page.grant] }} ({{ t('Browsing of this page is restricted') }})
   </p>
   {% endif %}
   {% if page && page.grant == 2 %}
   <p class="alert alert-info">
-    このページの共有用URL
+    {{ t('Shareable Link') }}
     <input type="text" class="copy-link form-control" value="{{ baseUrl }}/{{ page._id.toString() }}" readonly>
   </p>
   {% endif %}

+ 16 - 5
lib/views/layout/layout.html

@@ -11,6 +11,17 @@
 
   <meta name="viewport" content="width=device-width,initial-scale=1">
 
+  <meta name="apple-mobile-web-app-title" content="{{ config.crowi['app:title']|default('Crowi') }}">
+
+  <link rel="shortcut icon" href="/favicon.ico" type="image/x-icon" />
+  <link rel="apple-touch-icon"                 href="/apple-touch-icon.png">
+  <link rel="apple-touch-icon" sizes="72x72"   href="/apple-touch-icon-72x72.png">
+  <link rel="apple-touch-icon" sizes="120x120" href="/apple-touch-icon-120x120.png">
+  <link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon-180x180.png">
+  <link rel="icon" type="image/png" href="/favicon-32x32.png" sizes="32x32">
+  <link rel="icon" type="image/png" href="/favicon-96x96.png" sizes="96x96">
+  <link rel="icon" type="image/png" href="/android-chrome-192x192.png" sizes="192x192">
+
   <link rel="stylesheet" href="/css/crowi{% if env  == 'production' %}.min{% endif %}.css">
 
   <script src="{{ assets('/js/bundled.js') }}"></script>
@@ -54,7 +65,7 @@
       {% if user and user.admin %}
       <li id="">
         <a href="/admin" id="link-mypage">
-          <i class="fa fa-cube"></i> 管理
+          <i class="fa fa-cube"></i> {{ t('Admin') }}
         </a>
       </li>
       {% endif %}
@@ -75,7 +86,7 @@
       #}
       <li id="" class="dropdown">
         <button class="btn btn-default create-page-button" data-target="#create-page" data-toggle="modal">
-          <i class="fa fa-pencil"></i> 作成
+          <i class="fa fa-pencil"></i> {{ t('New') }}
         </button>
       </li>
       <li id="login-user">
@@ -86,11 +97,11 @@
       <li class="dropdown">
         <a href="#" class="dropdown-toggle" data-toggle="dropdown"><i class="fa fa-bars"></i> <label class="sr-only">メニュー</label></a>
         <ul class="dropdown-menu">
-          <li><a href="/me"><i class="fa fa-gears"></i> ユーザー設定</a></li>
+          <li><a href="/me"><i class="fa fa-gears"></i> {{ t('User Settings') }}</a></li>
           <li class="divider"></li>
-          <li><a href="/trash/"><i class="fa fa-trash-o"></i> 削除済みページ</a></li>
+          <li><a href="/trash/"><i class="fa fa-trash-o"></i> {{ t('Deleted Pages') }}</a></li>
           <li class="divider"></li>
-          <li><a href="/logout"><i class="fa fa-sign-out"></i> ログアウト</a></li>
+          <li><a href="/logout"><i class="fa fa-sign-out"></i> {{ t('Sign out') }}</a></li>
           {# <li><a href="#">今日の日報を作成</a></li> #}
           {# <li class="divider"></li> #}
           {# <li class="divider"></li> #}

+ 1 - 1
lib/views/layout/single.html

@@ -20,7 +20,7 @@
 <div id="footer-container" class="footer">
   <footer class="">
     <p>
-    <a href="" data-target="#help-modal" data-toggle="modal"><i class="fa fa-question-circle"> ヘルプ</i></a>
+    <a href="" data-target="#help-modal" data-toggle="modal"><i class="fa fa-question-circle"></i> {{ t('Help') }}</a>
     &copy; {{ now|date('Y') }} {{ config.crowi['app:title'] }} <img src="/logo/100x11_g.png" alt="powered by Crowi"> </p>
   </footer>
 </div>

+ 25 - 25
lib/views/login.html

@@ -1,6 +1,6 @@
 {% extends 'layout/single-nologin.html' %}
 
-{% block html_title %}Login · {% endblock %}
+{% block html_title %}{{ t('Sign in') }} · {% endblock %}
 
 {% block content_main %}
 
@@ -18,7 +18,7 @@
 <div class="login-dialog flipper {% if req.query.register or req.body.registerForm or isRegistering or googleId %}to-flip{% endif %}" id="login-dialog">
 
   <div class="login-dialog-inner front">
-    <h2>ログイン</h2>
+    <h2>{{ t('Sign in') }}</h2>
 
     <div id="login-form-errors">
       {% set message = req.flash('warningMessage') %}
@@ -50,17 +50,17 @@
       </div>
 
       <input type="hidden" name="_csrf" value="{{ csrf() }}">
-      <input type="submit" class="btn btn-primary btn-lg btn-block" value="Login">
+      <input type="submit" class="btn btn-primary btn-lg btn-block" value="{{ t('Sign in') }}">
     </form>
 
     <hr>
 
     <div class="row">
       {% if googleLoginEnabled() %}
-      <div class="col-md-6">
-        <p>Google でログイン</p>
+      <div class="col-md-8">
+        <p>{{ t('Sign in by Google Account') }}</p>
         <form role="form" action="/login/google" method="get">
-          <button type="submit" class="btn btn-block btn-google"><i class="fa fa-google-plus-square"></i> Login</button>
+          <button type="submit" class="btn btn-block btn-google"><i class="fa fa-google-plus-square"></i> {{ t('Sign in') }}</button>
           <input type="hidden" name="_csrf" value="{{ csrf() }}">
         </form>
       </div>
@@ -68,19 +68,19 @@
     </div>
 
     {% if config.crowi['security:registrationMode'] != 'Closed' %}
-    <p class="bottom-text"><a href="#register" id="register"><i class="fa fa-pencil"></i> 新規登録はこちら</a></p>
+    <p class="bottom-text"><a href="#register" id="register"><i class="fa fa-pencil"></i> {{ t('Sign up is here') }}</a></p>
     {% endif %}
   </div>
 
   {% if config.crowi['security:registrationMode'] != 'Closed' %}
   <div class="register-dialog-inner back">
 
-    <h2>新規登録</h2>
+    <h2>{{ t('Sign up') }}</h2>
 
     {% if config.crowi['security:registrationMode'] == 'Restricted' %}
     <p class="alert alert-warning">
-    この Wiki への新規登録は制限されています。<br>
-    利用を開始するには、新規登録後、管理者による承認が必要です。
+      {{ t('page_register.notice.restricted') }}<br>
+      {{ t('page_register.notice.restricted_defail') }}
     </p>
     {% endif %}
 
@@ -91,8 +91,8 @@
         <img src="{{ googleImage }}" class="picture picture-rounded picture-lg">
       </p>
       {% endif %}
-      <code>{{ googleEmail }}</code> この Google アカウントで登録します<br>
-      ユーザーID、名前、パスワードを決めて登録を継続してください。
+      <code>{{ googleEmail }}</code> {{ t('page_register with this Google Account') }}<br>
+      {{ t('page_register.notice.google_account_continue') }}
     </div>
     {% endif %}
 
@@ -120,30 +120,30 @@
     <form role="form" method="post" action="/register" id="register-form">
       <input type="hidden" class="form-control" name="registerForm[googleId]" value="{{ googleId|default(req.body.registerForm.googleId) }}">
 
-      <label>ユーザーID</label>
+      <label>{{ t('User ID') }}</label>
       <div class="input-group" id="input-group-username">
         <span class="input-group-addon"><strong>@</strong></span>
-        <input type="text" class="form-control" placeholder="記入例: taroyama" name="registerForm[username]" value="{{ req.body.registerForm.username }}" required>
+        <input type="text" class="form-control" placeholder="{{ t('Example') }}: taroyama" name="registerForm[username]" value="{{ req.body.registerForm.username }}" required>
       </div>
       <p class="help-block">
       <span id="help-block-username" class="text-danger"></span>
-      ユーザーIDは、ユーザーページのURLなどに利用されます。半角英数字と一部の記号のみ利用できます。
+      {{ t('page_register.form_help.user_id') }}
       </p>
 
-      <label>名前</label>
+      <label>{{ t('Name') }}</label>
       <div class="input-group">
         <span class="input-group-addon"><i class="fa fa-user"></i></span>
-        <input type="text" class="form-control" placeholder="記入例: 山田 太郎" name="registerForm[name]" value="{{ googleName|default(req.body.registerForm.name) }}" required>
+        <input type="text" class="form-control" placeholder="{{ t('Example') }}: {{ t('Taro Yamada') }}" name="registerForm[name]" value="{{ googleName|default(req.body.registerForm.name) }}" required>
       </div>
 
-      <label >メールアドレス</label>
+      <label>{{ t('Email') }}</label>
       <div class="input-group">
         <span class="input-group-addon"><i class="fa fa-envelope"></i></span>
         <input type="email" class="form-control" placeholder="E-mail" name="registerForm[email]" value="{{ googleEmail|default(req.body.registerForm.email) }}" required>
       </div>
       {% if config.crowi['security:registrationWhiteList'] && config.crowi['security:registrationWhiteList'].length %}
       <p class="help-block">
-      この Wiki では以下のメールアドレスのみ登録可能です。
+        {{ t('page_register.form_help.email') }}
       </p>
       <ul>
         {% for em in config.crowi['security:registrationWhiteList'] %}
@@ -152,20 +152,20 @@
       </ul>
       {% endif %}
 
-      <label>パスワード</label>
+      <label>{{ t('Password') }}</label>
       <div class="input-group">
         <span class="input-group-addon"><i class="fa fa-key"></i></span>
         <input type="password" class="form-control" placeholder="Password" name="registerForm[password]" required>
       </div>
       <p class="help-block">
-      パスワードは6文字以上の半角英数字または記号
+        {{ t('page_register.form_help.password') }}
       </p>
 
       {% if googleImage %}
         <input type="hidden" name="registerForm[googleImage]" value="{{ googleImage }}">
       {% endif  %}
       <input type="hidden" name="_csrf" value="{{ csrf() }}">
-      <input type="submit" class="btn btn-primary btn-lg btn-block" value="新規登録">
+      <input type="submit" class="btn btn-primary btn-lg btn-block" value="{{ t('Sign up') }}">
     </form>
 
     <hr>
@@ -173,16 +173,16 @@
     <div class="row">
       {% if googleLoginEnabled() %}
       <div class="col-md-6">
-        <p>Google で登録</p>
+        <p>{{ t('Sign up with Google Account') }}</p>
         <form role="form" method="post" action="/register/google">
           <input type="hidden" name="_csrf" value="{{ csrf() }}">
-          <button type="submit" class="btn btn-block btn-google"><i class="fa fa-google-plus-square"></i> Login</button>
+          <button type="submit" class="btn btn-block btn-google"><i class="fa fa-google-plus-square"></i> {{ t('Login') }}</button>
         </form>
       </div>
       {% endif %}
     </div>
 
-    <p class="bottom-text"><a href="#login" id="login"><i class="fa fa-sign-out"></i> ログインはこちら</a></p>
+    <p class="bottom-text"><a href="#login" id="login"><i class="fa fa-sign-out"></i> {{ t('Sign in is here') }}</a></p>
   </div>
   {% endif %} {# if registrationMode == Closed #}
 

+ 12 - 12
lib/views/me/api_token.html

@@ -1,12 +1,12 @@
 {% extends '../layout/2column.html' %}
 
 
-{% block html_title %}APIの設定 · {{ path }}{% endblock %}
+{% block html_title %}{{ t('API Settings') }} · {{ path }}{% endblock %}
 
 {% block content_head %}
 <div class="header-wrap">
   <header id="page-header">
-  <h1 class="title" id="">ユーザー設定</h1>
+  <h1 class="title" id="">{{ t('User Settings') }}</h1>
   </header>
 </div>
 {% endblock %}
@@ -15,9 +15,9 @@
 <div class="content-main">
 
   <ul class="nav nav-tabs">
-    <li><a href="/me"><i class="fa fa-gears"></i> ユーザー情報</a></li>
-    <li><a href="/me/password"><i class="fa fa-key"></i> パスワード設定</a></li>
-    <li class="active"><a href="/me/apiToken"><i class="fa fa-rocket"></i> API設定</a></li>
+    <li><a href="/me"><i class="fa fa-gears"></i> {{ t('User Information') }}</a></li>
+    <li><a href="/me/password"><i class="fa fa-key"></i> {{ t('Password Setting') }}</a></li>
+    <li class="active"><a href="/me/apiToken"><i class="fa fa-rocket"></i> {{ t('API Settings') }}</a></li>
   </ul>
 
   <div class="tab-content">
@@ -43,29 +43,29 @@
 
     <form action="/me/apiToken" method="post" class="form-horizontal" role="form">
     <fieldset>
-      <legend>API Token 設定</legend>
+      <legend>{{ t('API Token Settings') }}</legend>
       <div class="form-group {% if not user.password %}has-error{% endif %}">
-        <label for="" class="col-xs-2 control-label">現在のAPI Token</label>
+        <label for="" class="col-xs-3 control-label">{{ t('Current API Token') }}</label>
         <div class="col-xs-6">
           {% if user.apiToken %}
             <input class="form-control" type="text" value="{{ user.apiToken }}">
           {% else %}
           <p class="form-control-static">
-            API Token が設定されていません。更新するボタンから発行してください。
+            {{ t('page_me_apitoken.notice.apitoken_issued') }}
           </p>
           {% endif %}
         </div>
       </div>
 
       <div class="form-group">
-        <div class="col-xs-offset-2 col-xs-10">
+        <div class="col-xs-offset-3 col-xs-10">
 
           <p class="alert alert-warning">
-          API Token を更新すると、自動的に新しい Token が生成されます。<br>
-          現在の Token を利用している処理は動かなくなります。
+            {{ t('page_me_apitoken.notice.update_token1') }}<br>
+            {{ t('page_me_apitoken.notice.update_token2') }}
           </p>
 
-          <button type="submit" value="1" name="apiTokenForm[confirm]" class="btn btn-primary">API Tokenを更新する</button>
+          <button type="submit" value="1" name="apiTokenForm[confirm]" class="btn btn-primary">{{ t('Update API Token') }}</button>
         </div>
       </div>
 

+ 34 - 34
lib/views/me/index.html

@@ -1,11 +1,11 @@
 {% extends '../layout/2column.html' %}
 
-{% block html_title %}ユーザー設定 · {{ path }}{% endblock %}
+{% block html_title %}{{ t('User Settings') }} · {{ path }}{% endblock %}
 
 {% block content_head %}
 <div class="header-wrap">
   <header id="page-header">
-    <h1 class="title" id="">ユーザー設定</h1>
+    <h1 class="title" id="">{{ t('User Settings') }}</h1>
   </header>
 </div>
 {% endblock %}
@@ -14,9 +14,9 @@
 <div class="content-main">
 
   <ul class="nav nav-tabs">
-    <li class="active"><a href="/me"><i class="fa fa-gears"></i> ユーザー情報</a></li>
-    <li><a href="/me/password"><i class="fa fa-key"></i> パスワード設定</a></li>
-    <li><a href="/me/apiToken"><i class="fa fa-rocket"></i> API設定</a></li>
+    <li class="active"><a href="/me"><i class="fa fa-gears"></i> {{ t('User Information') }}</a></li>
+    <li><a href="/me/password"><i class="fa fa-key"></i> {{ t('Password Settings') }}</a></li>
+    <li><a href="/me/apiToken"><i class="fa fa-rocket"></i> {{ t('API Settings') }}</a></li>
   </ul>
 
   <div class="tab-content">
@@ -49,31 +49,22 @@
   <div class="form-box">
     <form action="/me" method="post" class="form-horizontal" role="form">
       <fieldset>
-        <legend>ユーザーの基本情報</legend>
+        <legend>{{ t('Basic Info') }}</legend>
       <div class="form-group">
-        <label for="userForm[name]" class="col-sm-2 control-label">名前</label>
+        <label for="userForm[name]" class="col-sm-2 control-label">{{ t('Name') }}</label>
         <div class="col-sm-4">
           <input class="form-control" type="text" name="userForm[name]" value="{{ user.name }}" required>
         </div>
       </div>
       <div class="form-group {% if not user.email %}has-error{% endif %}">
-        <label for="userForm[email]" class="col-sm-2 control-label">メールアドレス</label>
+        <label for="userForm[email]" class="col-sm-2 control-label">{{ t('Email') }}</label>
         <div class="col-sm-4">
           <input class="form-control" type="email" name="userForm[email]" value="{{ user.email }}" required>
         </div>
         <div class="col-sm-offset-2 col-sm-10">
-          {# ↓ そのうちこのコードは削除する #}
-          {% if not user.email %}
-          <p class="help-block help-danger">
-          メールアドレスは登録必須項目です。<br>
-          (以前のバージョンのWikiで作成されたユーザー情報の場合、メールアドレスが登録されていません)<br>
-          更新ボタンを押して新規登録してください。
-          </p>
-          {% endif %}
-
           {% if config.crowi['security:registrationWhiteList'] && config.crowi['security:registrationWhiteList'].length %}
           <p class="help-block">
-          この Wiki では以下のメールアドレスのみ登録可能です。
+            {{ t('page_register.form_help.email') }}
           <ul>
             {% for em in config.crowi['security:registrationWhiteList'] %}
             <li><code>{{ em }}</code></li>
@@ -82,11 +73,20 @@
           </p>
           {% endif %}
         </div>
+        <div class="form-group {% if not user.lang %}has-error{% endif %}">
+          <label for="userForm[lang]" class="col-sm-2 control-label">{{ t('Language') }}</label>
+          <div class="col-sm-4 radio">
+            <label><input type="radio" name="userForm[lang]" value="{{ consts.language.LANG_EN_US }}" {% if user.lang == consts.language.LANG_EN_US %}checked="checked"{% endif %}>{{ t('English') }}</label>
+            <label><input type="radio" name="userForm[lang]" value="{{ consts.language.LANG_JA }}" {% if user.lang == consts.language.LANG_JA %}checked="checked"{% endif %}>{{ t('Japanese') }}</label>
+          </div>
+          <div class="col-sm-offset-2 col-sm-10">
+          </div>
+        </div>
       </div>
 
       <div class="form-group">
         <div class="col-sm-offset-2 col-sm-10">
-          <button type="submit" class="btn btn-primary">更新</button>
+          <button type="submit" class="btn btn-primary">{{ t('Update') }}</button>
         </div>
       </div>
     </fieldset>
@@ -95,11 +95,11 @@
 
   <div class="form-box">
     <fieldset>
-      <legend>プロフィール画像の設定</legend>
+      <legend>{{ t('Set Profile Image') }}</legend>
         <div class="form-group">
           <div id="pictureUploadFormMessage"></div>
           <label for="" class="col-sm-3 control-label">
-            現在の画像
+            {{ t('Current Image') }}
           </label>
           <div class="col-sm-9">
             <p>
@@ -107,8 +107,8 @@
             </p>
             <p>
             {% if user.image %}
-            <form action="/me/picture/delete" method="post" class="form-horizontal" role="form" onsubmit="return window.confirm('削除してよろしいですか?');">
-              <button type="submit" class="btn btn-danger">画像を削除</button>
+            <form action="/me/picture/delete" method="post" class="form-horizontal" role="form" onsubmit="return window.confirm('{{ t('Delete this image?') }}');">
+              <button type="submit" class="btn btn-danger">{{ t('Delete Image') }}</button>
             </form>
             {% endif %}
             </p>
@@ -117,7 +117,7 @@
 
         <div class="form-group">
           <label for="" class="col-sm-3 control-label">
-            新しい画像をアップロード
+            {{ t('Upload new image') }}
           </label>
           <div class="col-sm-9">
             {% if isUploadable() %}
@@ -127,8 +127,8 @@
               </div>
             </form>
             {% else %}
-            * 画像をアップロードをするための設定がされていません。<br>
-            * アップロードできるようにするには、AWS またはローカルアップロードの設定をしてください。<br>
+            * {{ t('page_me.form_help.profile_image1') }}<br>
+            * {{ t('page_me.form_help.profile_image2') }}<br>
             {% endif %}
           </div>
         </div>
@@ -178,7 +178,7 @@
       <div class="form-box">
         <form action="/me/auth/google" method="post" class="form-horizontal" role="form">
           <fieldset>
-            <legend><i class="fa fa-google-plus-square"></i> Google設定</legend>
+            <legend><i class="fa fa-google-plus-square"></i> {{ t('Google Setting') }}</legend>
 
             {% set wmessage = req.flash('warningMessage.auth.google') %}
             {% if wmessage.length %}
@@ -192,13 +192,13 @@
 
             <div class="col-sm-12">
               <p>
-                接続されています
+                {{ t('Connected') }}
 
-                <input type="submit" name="disconnectGoogle" class="btn btn-default" value="接続を解除">
+                <input type="submit" name="disconnectGoogle" class="btn btn-default" value="{{ t('Disconnect') }}">
               </p>
               <p class="help-block">
-              接続を解除すると、Googleでログインができなくなります。<br>
-              解除後はメールアドレスとパスワードでログインすることができます。
+                {{ t('page_me.form_help.google_disconnect1') }}<br>
+                {{ t('page_me.form_help.google_disconnect2') }}
               </p>
             </div>
 
@@ -209,11 +209,12 @@
                 <input type="submit" name="connectGoogle" class="btn btn-google" value="Googleコネクト">
               </div>
               <p class="help-block">
-              Googleコネクトをすると、Googleアカウントでログイン可能になります。<br>
+                {{ t('page_me.form_help.google_connect1') }}<br>
               </p>
               {% if config.crowi['security:registrationWhiteList'] && config.crowi['security:registrationWhiteList'].length %}
               <p class="help-block">
-              この Wiki では、登録可能なメールアドレスが限定されているため、コネクト可能なGoogleアカウントは、以下のメールアドレスの発行できるGoogle Appsアカウントに限られます。
+                {{ t('page_register.form_help.email') }}<br>
+                {{ t('page_me.form_help.google_connect2') }}
               </p>
               <ul>
                 {% for em in config.crowi['security:registrationWhiteList'] %}
@@ -271,4 +272,3 @@
 
 {% block footer %}
 {% endblock footer %}
-

+ 14 - 14
lib/views/me/password.html

@@ -1,11 +1,11 @@
 {% extends '../layout/2column.html' %}
 
-{% block html_title %}パスワードの設定 · {{ path }}{% endblock %}
+{% block html_title %}{{ t('Password Settings') }} · {{ path }}{% endblock %}
 
 {% block content_head %}
 <div class="header-wrap">
   <header id="page-header">
-    <h1 class="title" id="">ユーザー設定</h1>
+    <h1 class="title" id="">{{ t('User Settings') }}</h1>
   </header>
 </div>
 {% endblock %}
@@ -14,16 +14,16 @@
 <div class="content-main">
 
   <ul class="nav nav-tabs">
-    <li><a href="/me"><i class="fa fa-gears"></i> ユーザー情報</a></li>
-    <li class="active"><a href="/me/password"><i class="fa fa-key"></i> パスワード設定</a></li>
-    <li><a href="/me/apiToken"><i class="fa fa-rocket"></i> API設定</a></li>
+    <li><a href="/me"><i class="fa fa-gears"></i> {{ t('User Information') }}</a></li>
+    <li class="active"><a href="/me/password"><i class="fa fa-key"></i> {{ t('Password Settings') }}</a></li>
+    <li><a href="/me/apiToken"><i class="fa fa-rocket"></i> {{ t('API Settings') }}</a></li>
   </ul>
 
   <div class="tab-content">
 
   {% if not user.password %}
   <div class="alert alert-danger">
-    パスワードを設定してください
+    {{ t('Please set a password') }}
   </div>
   {% endif %}
 
@@ -46,7 +46,7 @@
 
   {% if user.email %}
   <p>
-  <code>{{ user.email }}</code> と設定されたパスワードの組み合わせでログイン可能になります。
+    {{ t('You can sign in with email and password', user.email) }}
   </p>
   {% endif %}
 
@@ -55,37 +55,37 @@
     <form action="/me/password" method="post" class="form-horizontal" role="form">
     <fieldset>
       {% if user.password %}
-      <legend>パスワードを更新</legend>
+      <legend>{{ t('Update Password') }}</legend>
       {% else %}
-      <legend>パスワードを新規に設定</legend>
+      <legend>{{ t('Set new Password') }}</legend>
       {% endif %}
       {% if user.password %}
       <div class="form-group">
-        <label for="mePassword[oldPassword]" class="col-xs-2 control-label">現在のパスワード</label>
+        <label for="mePassword[oldPassword]" class="col-xs-3 control-label">{{ t('Current password') }}</label>
         <div class="col-xs-6">
           <input class="form-control" type="password" name="mePassword[oldPassword]">
         </div>
       </div>
       {% endif %}
       <div class="form-group {% if not user.password %}has-error{% endif %}">
-        <label for="mePassword[newPassword]" class="col-xs-2 control-label">新しいパスワード</label>
+        <label for="mePassword[newPassword]" class="col-xs-3 control-label">{{ t('New password') }}</label>
         <div class="col-xs-6">
           <input class="form-control" type="password" name="mePassword[newPassword]" required>
         </div>
       </div>
       <div class="form-group">
-        <label for="mePassword[newPasswordConfirm]" class="col-xs-2 control-label">確認</label>
+        <label for="mePassword[newPasswordConfirm]" class="col-xs-3 control-label">{{ t('Re-enter new password') }}</label>
         <div class="col-xs-6">
           <input class="form-control col-xs-4" type="password" name="mePassword[newPasswordConfirm]" required>
 
-          <p class="help-block">パスワードには、6文字以上の半角英数字または記号等を設定してください。</p>
+          <p class="help-block">{{ t('page_register.form_help.password') }}</p>
         </div>
       </div>
 
 
       <div class="form-group">
         <div class="col-xs-offset-2 col-xs-10">
-          <button type="submit" class="btn btn-primary">更新</button>
+          <button type="submit" class="btn btn-primary">{{ t('Update') }}</button>
         </div>
       </div>
 

+ 8 - 9
lib/views/modal/create_page.html

@@ -4,7 +4,7 @@
 
       <div class="modal-header">
         <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
-        <h4 class="modal-title">New Page</h4>
+        <h4 class="modal-title">{{ t('New Page') }}</h4>
       </div>
 
       <div class="modal-body">
@@ -12,16 +12,16 @@
         <form class="form-horizontal" id="create-page-today" role="form">
           <fieldset>
             <div class="col-xs-12">
-              <h4>今日の◯◯を作成</h4>
+              <h4>{{ t("Create today's") }}</h4>
             </div>
             <div class="col-xs-10">
               <span class="page-today-prefix">{{ userPageRoot(user) }}/</span>
-              <input type="text" data-prefix="{{ userPageRoot(user) }}/" class="page-today-input1 form-control" value="メモ" id="" name="">
+              <input type="text" data-prefix="{{ userPageRoot(user) }}/" class="page-today-input1 form-control" value="{{ t('Memo') }}" id="" name="">
               <span class="page-today-suffix">/{{ now|datetz('Y/m/d') }}/</span>
-              <input type="text" data-prefix="/{{ now|datetz('Y/m/d') }}/" class="page-today-input2 form-control" id="page-today-input2" name="" placeholder="ページ名を入力(空欄OK)">
+              <input type="text" data-prefix="/{{ now|datetz('Y/m/d') }}/" class="page-today-input2 form-control" id="page-today-input2" name="" placeholder="{{ t('Input page name (optional)') }}">
             </div>
             <div class="col-xs-2">
-              <button type="submit" class="btn btn-primary">作成</button>
+              <button type="submit" class="btn btn-primary">{{ t('Create') }}</button>
             </div>
           </fieldset>
         </form>
@@ -31,13 +31,13 @@
         <form class="form-horizontal" id="create-page-under-tree" role="form">
           <fieldset>
             <div class="col-xs-12">
-              <h4><code>{{ parentPath(path) }}</code>以下に作成</h4>
+              <h4>{{ t('Create under', parentPath(path)) }}</h4>
             </div>
             <div class="col-xs-10">
-              <input type="text" value="{{ parentPath(path) }}" class="page-name-input form-control " placeholder="ページ名を入力" required>
+              <input type="text" value="{{ parentPath(path) }}" class="page-name-input form-control " placeholder="{{ t('Input page name') }}" required>
             </div>
             <div class="col-xs-2">
-              <button type="submit" class="btn btn-primary">作成</button>
+              <button type="submit" class="btn btn-primary">{{ t('Create') }}</button>
             </div>
           </fieldset>
         </form>
@@ -49,4 +49,3 @@
     </div><!-- /.modal-content -->
   </div><!-- /.modal-dialog -->
 </div><!-- /.modal -->
-

+ 18 - 18
lib/views/modal/help.html

@@ -4,50 +4,50 @@
 
       <div class="modal-header">
         <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
-        <h4 class="modal-title">ヘルプ</h4>
+        <h4 class="modal-title">{{ t('Help') }}</h4>
       </div>
       <div class="modal-body">
-        <h4>基本的な機能</h4>
+        <h4>{{ t('modal_help.basic.title') }}</h4>
         <br>
         <ul>
-          <li>表示される画面には、「一覧ページ」と「ページ」の2種類があります</li>
-          <li>スラッシュ <code>/</code> で終わるページは、その階層の一覧ページとなります。</li>
-          <li>ページでの変更はすべて記録されています。サイドバーには、変更の履歴が一覧となっていて、クリックするとそのページの過去の状態を見ることができます。</li>
+          <li>{{ t('modal_help.basic.body1') }}</li>
+          <li>{{ t('modal_help.basic.body2') }}</li>
+          <li>{{ t('modal_help.basic.body3') }}</li>
         </ul>
         <br>
 
-        <h4>編集のコツ</h4>
+        <h4>{{ t('modal_help.tips.title') }}</h4>
         <br>
         <p>
-        文章の <strong>構造</strong> を意識しましょう。本を書くように、内容と文脈を整理してセクション・サブセクション...と構造的に書くと、わかりやすく他人に伝わりやすいページがになります。
+        {{ t('modal_help.tips.body1') }}
         </p>
         <br>
 
-        <h4>記法</h4>
+        <h4>{{ t('modal_help.markdown.title') }}</h4>
         <br>
         <div class="wiki">
-        <pre># セクション</pre>
-        <h1>セクション</h1>
+        <pre># Section</pre>
+        <h1>Section</h1>
         </div>
         <hr>
 
         <div class="wiki">
-        <pre>## サブセクション</pre>
-        <h2>サブセクション</h2>
+        <pre>## Sub section</pre>
+        <h2>Sub Section</h2>
         </div>
         <hr>
 
         <div class="wiki">
-        <pre>### サブサブセクション</pre>
-        <h3>サブサブセクション</h3>
+        <pre>### Sub sub section</pre>
+        <h3>Sub Sub Section</h3>
         </div>
         <hr>
 
         <div class="wiki">
-        <pre>* このようにアスタリスクと半角スペースを先頭に書くと、
-* 箇条書きのリストにになります
-    * タブキーを押すと半角スペース4つが挿入され、インデントされます
-    * インデントはリストにも反映されます</pre>
+        <pre>- このようにハイフンと半角スペースを先頭に書くと、
+- 箇条書きのリストにになります
+    - タブキーを押すと半角スペース4つが挿入され、インデントされます
+    - インデントはリストにも反映されます</pre>
           <ul>
             <li>リスト記法はこのように</li>
             <li>箇条書きになります

+ 6 - 9
lib/views/modal/rename.html

@@ -6,19 +6,15 @@
 
         <div class="modal-header">
           <button type="button" class="close" data-dismiss="modal" aria-hidden="true">&times;</button>
-          <h4 class="modal-title">ページを移動する</h4>
+          <h4 class="modal-title">{{ t('Rename page') }}</h4>
         </div>
         <div class="modal-body">
-          <ul>
-           <li>移動先にページが存在する場合は、移動できません。</li>
-           <li>過去の履歴も含めてすべて移動されます。</li>
-          </ul>
             <div class="form-group">
-              <label for="">このページ</label><br>
+              <label for="">{{ t('Current page name') }}</label><br>
               <code>{{ page.path }}</code>
             </div>
             <div class="form-group">
-              <label for="newPageName">移動先のページ名</label><br>
+              <label for="newPageName">{{ t('New page name') }}</label><br>
               <div class="input-group">
                 <span class="input-group-addon">{{ config.crowi['app:url'] }}</span>
                 <input type="text" class="form-control" name="new_path" id="newPageName" value="{{ page.path }}">
@@ -26,9 +22,10 @@
             </div>
             <div class="checkbox">
                <label>
-                 <input name="create_redirect" value="1"  type="checkbox"> リダイレクトページを作成
+                 <input name="create_redirect" value="1"  type="checkbox"> {{ t('Redirect') }}
                </label>
-               <p class="help-block">チェックを入れると、<code>{{ page.path }}</code>にアクセスされた際に自動的に新しいページにジャンプします。</p>
+               <p class="help-block"> {{ t('modal_rename.help.redirect', page.path) }}
+               </p>
             </div>
             {# <div class="checkbox"> #}
             {#    <label> #}

+ 19 - 40
lib/views/page.html

@@ -26,14 +26,18 @@
             class="like-button btn btn-default btn-sm {% if page.isLiked(user) %}active{% endif %}"
         ><i class="fa fa-thumbs-o-up"></i></button>
       </div>
+      {% endif %}
     </div>
-    {% endif %}
   </header>
   {% else %}
   {# trash/* #}
   <header id="page-header">
-    <a href="#" title="Bookmark" class="bookmark-link" id="bookmark-button" data-csrftoken="{{ csrf() }}" data-bookmarked="0"><i class="fa fa-star-o"></i></a>
-    <h1 class="title">{{ path|insertSpaceToEachSlashes }}</h1>
+    <div class="flex-title-line">
+      <h1 class="title flex-item-title">{{ path|insertSpaceToEachSlashes }}</h1>
+      <div class="flex-item-action">
+        <a href="#" title="Bookmark" class="bookmark-link" id="bookmark-button" data-csrftoken="{{ csrf() }}" data-bookmarked="0"><i class="fa fa-star-o"></i></a>
+      </div>
+    </div>
   </header>
   {% endif %}
 </div>
@@ -63,7 +67,7 @@
   <ul class="nav nav-tabs hidden-print">
     <li><a>Create: {{ path }}</a></li>
     <li class="dropdown pull-right">
-      <a href="#" onclick="history.back();"><i class="fa fa-times"></i> キャンセル</a>
+      <a href="#" onclick="history.back();"><i class="fa fa-times"></i> {{ t('Cancel') }}</a>
     </li>
   </ul>
   <div class="tab-content">
@@ -103,7 +107,7 @@
       </a>
     </li>
 
-    <li {% if req.body.pageForm %}class="active"{% endif %}><a href="#edit-form" data-toggle="tab"><i class="fa fa-pencil-square-o"></i> 編集</a></li>
+    <li {% if req.body.pageForm %}class="active"{% endif %}><a href="#edit-form" data-toggle="tab"><i class="fa fa-pencil-square-o"></i> {{ t('Edit') }}</a></li>
 
 
     <li class="dropdown pull-right">
@@ -111,11 +115,11 @@
         <i class="fa fa-wrench"></i> <span class="caret"></span>
       </a>
       <ul class="dropdown-menu">
-       <li><a href="#" data-target="#renamePage" data-toggle="modal"><i class="fa fa-share"></i> 移動</a></li>
-       <li><a href="?presentation=1" class="toggle-presentation"><i class="fa fa-arrows-alt"></i> プレゼンモード (beta)</a></li>
+       <li><a href="#" data-target="#renamePage" data-toggle="modal"><i class="fa fa-share"></i> {{ t('Move') }}</a></li>
+       <li><a href="?presentation=1" class="toggle-presentation"><i class="fa fa-arrows-alt"></i> {{ t('Presentation Mode') }} (beta)</a></li>
        {% if isDeletablePage() %}
        <li class="divider"></li>
-       <li class=""><a href="#" data-target="#deletePage" data-toggle="modal"><i class="fa fa-trash-o text-danger"></i> 削除</a></li>
+       <li class=""><a href="#" data-target="#deletePage" data-toggle="modal"><i class="fa fa-trash-o text-danger"></i> {{ t('Delete') }}</a></li>
        {% endif %}
       </ul>
     </li>
@@ -128,12 +132,12 @@
   <div class="tab-content wiki-content">
   {% if req.query.renamed and not page.isDeleted() %}
   <div class="alert alert-info">
-    <strong>移動しました: </strong> このページは <code>{{ req.query.renamed }}</code> から移動しました。
+    <strong>{{ t('Moved') }}: </strong> {{ t('page_page.notice.moved', req.query.renamed) }}
   </div>
   {% endif %}
   {% if not page.isLatestRevision() %}
   <div class="alert alert-warning">
-    <strong>注意: </strong> これは現在の版ではありません。 <i class="fa fa-magic"></i> <a href="{{ page.path }}">最新のページを表示</a>
+    <strong>{{ t('Warning') }}: </strong> {{ t('page_page.notice.version') }} <i class="fa fa-magic"></i> <a href="{{ page.path }}">{{ t('Show latest') }}</a>
   </div>
   {% endif %}
 
@@ -150,7 +154,7 @@
     {# formatted text #}
     <div class="tab-pane {% if not req.body.pageForm %}active{% endif %}" id="revision-body">
       <div class="revision-toc" id="revision-toc">
-        <a data-toggle="collapse" data-parent="#revision-toc" href="#revision-toc-content" class="revision-toc-head collapsed">目次</a>
+        <a data-toggle="collapse" data-parent="#revision-toc" href="#revision-toc-content" class="revision-toc-head collapsed">{{ t('Table of Contents') }}</a>
 
       </div>
       <div class="wiki" id="revision-body-content"></div>
@@ -164,41 +168,16 @@
     {% endif %}
 
     {# raw revision history #}
+    {% if not page %}
+    {% else %}
     <div class="tab-pane revision-history" id="revision-history">
-      <h1><i class="fa fa-history"></i> History</h1>
-      {% if not page %}
-      {% else %}
-      <div class="revision-history-list">
-        {% for t in tree %}
-        <div class="revision-hisory-outer">
-          <img src="{{ t.author|picture }}" class="picture picture-rounded">
-          <div class="revision-history-main">
-            <div class="revision-history-author">
-              <strong>{% if t.author %}{{ t.author.username }}{% else %}-{% endif %}</strong>
-            </div>
-            <div class="revision-history-comment">
-            </div>
-            <div class="revision-history-meta">
-              {{ t.createdAt|datetz('Y-m-d H:i:s') }}
-              <br>
-              <a href="?revision={{ t._id.toString() }}"><i class="fa fa-history"></i> このバージョンを見る</a>
-              <a class="diff-view" data-revision-id="{{ t._id.toString() }}">
-                <i id="diff-icon-{{ t._id.toString() }}" class="fa fa-arrow-circle-right"></i> 差分を見る
-              </a>
-              <pre class="" id="diff-display-{{ t._id.toString()}}" style="display: none"></pre>
-            </div>
-          </div>
-        </div>
-        {% endfor %}
-      </div>
-      {% endif %}
-
     </div>
+    {% endif %}
 
   </div>
   {% endif %}
 
-<div id="notifPageEdited" class="fk-notif fk-notif-danger"><i class="fa fa-exclamation-triangle"></i> <span class="edited-user"></span>さんがこのページを編集しました。 <a href="javascript:location.reload();"><i class="fa fa-angle-double-right"></i> 最新版を読み込む</a></div>
+  <div id="notifPageEdited" class="fk-notif fk-notif-danger"><i class="fa fa-exclamation-triangle"></i> <span class="edited-user"></span> {{ t('edited this page') }} <a href="javascript:location.reload();"><i class="fa fa-angle-double-right"></i> {{ t('Load latest') }}</a></div>
 </div>
 
 {% block content_main_after %}

+ 40 - 30
lib/views/page_list.html

@@ -14,24 +14,34 @@
 
 <div class="header-wrap">
   <header class="portal-header {% if page %}has-page{% endif %}">
-    {% if page %}
-      <a href="#" title="Bookmark" class="bookmark-link" id="bookmark-button" data-csrftoken="{{ csrf() }}" data-bookmarked="0"><i class="fa fa-star-o"></i></a>
-
-    {% endif %}
-    <h1 class="title">
-      <span class="" id="revision-path">{{ path|insertSpaceToEachSlashes }}</span>
-      {% if searchConfigured() && !isTopPage() && !isTrashPage() %}
-      <form class="input-group search-input-group hidden-xs hidden-sm" data-toggle="tooltip" data-placement="bottom" title="{{ path }} 以下から検索" id="search-listpage-form">
-        <input type="text" class="search-listpage-input form-control" data-path="{{ path }}" id="search-listpage-input">
-        <span class="input-group-btn search-listpage-submit-group">
-          <button type="submit" class="btn btn-default" id="search-listpage-submit">
-            <i class="fa fa-search"></i>
-          </button>
-        </span>
-        <a class="search-listpage-clear" id="search-listpage-clear"><i class="fa fa-times-circle"></i></a>
-      </form>
+    <div class="flex-title-line">
+      <h1 class="title flex-item-title">
+        <span id="revision-path">{{ path|insertSpaceToEachSlashes }}</span>
+        {% if searchConfigured() && !isTopPage() && !isTrashPage() %}
+        <form class="input-group search-input-group hidden-xs hidden-sm" data-toggle="tooltip" data-placement="bottom" title="{{ path }} 以下から検索" id="search-listpage-form">
+          <input type="text" class="search-listpage-input form-control" data-path="{{ path }}" id="search-listpage-input">
+          <span class="input-group-btn search-listpage-submit-group">
+            <button type="submit" class="btn btn-default" id="search-listpage-submit">
+              <i class="fa fa-search"></i>
+            </button>
+          </span>
+          <a class="search-listpage-clear" id="search-listpage-clear"><i class="fa fa-times-circle"></i></a>
+        </form>
+        {% endif %}
+      </h1>
+      {% if page %}
+      <div class="flex-item-action">
+        <a href="#" title="Bookmark" class="bookmark-link" id="bookmark-button" data-csrftoken="{{ csrf() }}" data-bookmarked="0"><i class="fa fa-star-o"></i></a>
+      </div>
+      <div class="flex-item-action visible-xs visible-sm">
+        <button
+            data-csrftoken="{{ csrf() }}"
+            data-liked="{% if page.isLiked(user) %}1{% else %}0{% endif %}"
+            class="like-button btn btn-default btn-sm {% if page.isLiked(user) %}active{% endif %}"
+        ><i class="fa fa-thumbs-o-up"></i></button>
+      </div>
       {% endif %}
-    </h1>
+    </div>
   </header>
 </div>
 
@@ -78,7 +88,7 @@
       <a>Create Portal: {{ path }}</a>
       {% endif %}
     </li>
-    <li {% if req.body.pageForm %}class="active"{% endif %}><a href="#edit-form" data-toggle="tab"><i class="fa fa-pencil-square-o"></i> 編集</a></li>
+    <li {% if req.body.pageForm %}class="active"{% endif %}><a href="#edit-form" data-toggle="tab"><i class="fa fa-pencil-square-o"></i> {{ t('Edit') }}</a></li>
 
     {% if not page %}
     <li class="pull-right close-button">
@@ -92,7 +102,7 @@
         <i class="fa fa-wrench"></i> <span class="caret"></span>
       </a>
       <ul class="dropdown-menu">
-       <li><a href="#" data-target="#unportalize" data-toggle="modal"><i class="fa fa-share"></i> ポータル解除</a></li>
+        <li><a href="#" data-target="#unportalize" data-toggle="modal"><i class="fa fa-share"></i> {{ t('Unportalize') }}</a></li>
       </ul>
     </li>
     <li class="pull-right"><a href="#revision-history" data-toggle="tab"><i class="fa fa-history"></i> History</a></li>
@@ -102,7 +112,7 @@
   <div class="tab-content">
   {% if page and not page.isLatestRevision() %}
   <div class="alert alert-warning">
-    <strong>注意: </strong> これは現在の版ではありません。 <i class="fa fa-magic"></i> <a href="{{ page.path }}">最新のポータルを表示</a>
+    <strong>{{ t('Warning') }}: </strong> {{ t('page.notice.version') }} <i class="fa fa-magic"></i> <a href="{{ page.path }}">最新のポータルを表示</a>
   </div>
   {% endif %}
     <div class="tab-pane {% if not req.body.pageForm %}active{% endif %}" id="revision-body">
@@ -122,23 +132,23 @@
       {% if not page %}
       {% else %}
       <div class="revision-history-list">
-        {% for t in tree %}
+        {% for tr in tree %}
         <div class="revision-hisory-outer">
-          <img src="{{ t.author|picture }}" class="picture picture-rounded">
+          <img src="{{ tr.author|picture }}" class="picture picture-rounded">
           <div class="revision-history-main">
             <div class="revision-history-author">
-              <strong>{% if t.author %}{{ t.author.username }}{% else %}-{% endif %}</strong>
+              <strong>{% if tr.author %}{{ tr.author.username }}{% else %}-{% endif %}</strong>
             </div>
             <div class="revision-history-comment">
             </div>
             <div class="revision-history-meta">
-              {{ t.createdAt|datetz('Y-m-d H:i:s') }}
+              {{ tr.createdAt|datetz('Y-m-d H:i:s') }}
               <br>
-              <a href="?revision={{ t._id.toString() }}"><i class="fa fa-history"></i> このバージョンを見る</a>
-              <a class="diff-view" data-revision-id="{{ t._id.toString() }}">
-                <i id="diff-icon-{{ t._id.toString() }}" class="fa fa-arrow-circle-right"></i> 差分を見る
+              <a href="?revision={{ tr._id.toString() }}"><i class="fa fa-history"></i> {{ t('View this version') }}</a>
+              <a class="diff-view" data-revision-id="{{ tr._id.toString() }}">
+                <i id="diff-icon-{{ tr._id.toString() }}" class="fa fa-arrow-circle-right"></i> {{ t('View diff') }}
               </a>
-              <pre class="" id="diff-display-{{ t._id.toString()}}" style="display: none"></pre>
+              <div class="" id="diff-display-{{ tr._id.toString()}}" style="display: none"></div>
             </div>
           </div>
         </div>
@@ -152,8 +162,8 @@
 
 <div class="page-list-container">
   <ul class="nav nav-tabs">
-      <li class="active"><a href="#view-list" data-toggle="tab">リスト表示</a></li>
-      <li><a href="#view-timeline" data-toggle="tab">タイムライン表示</a></li>
+      <li class="active"><a href="#view-list" data-toggle="tab">{{ t('List View') }}</a></li>
+      <li><a href="#view-timeline" data-toggle="tab">{{ t('Timeline View') }}</a></li>
   </ul>
 
   <div class="tab-content">

+ 3 - 1
lib/views/user_page.html

@@ -36,9 +36,11 @@
       <li>
         <a href="#user-created-list" data-toggle="tab"><i class="fa fa-pencil"></i> Recent Created</a>
       </li>
+      {% if user._id.toString() == pageUser._id.toString() %}
       <li>
-        <a href="/me"><i class="fa fa-gears"></i> Setting</a>
+        <a href="/me"><i class="fa fa-gears"></i> Settings</a>
       </li>
+      {% endif %}
     </ul>
     <div class="user-page-content-tab tab-content">
 

+ 4 - 4
lib/views/widget/page_side_content.html

@@ -1,10 +1,10 @@
-<h3><i class="fa fa-link"></i> Share</h3>
+<h3><i class="fa fa-link"></i> {{ t('Share') }}</h3>
 <ul class="fitted-list">
-  <li data-toggle="tooltip" data-placement="bottom" title="共有用リンク" class="input-group">
-    <span class="input-group-addon">共有用</span>
+  <li class="input-group">
+    <span class="input-group-addon">{{ t('Share Link') }}</span>
     <input readonly class="copy-link form-control" type="text" value="{{ config.crowi['app:title']|default('Crowi') }} {{ path }}  {{ baseUrl }}/{{ page._id.toString() }}">
   </li>
-  <li data-toggle="tooltip" data-placement="bottom" title="Markdown形式のリンク" class="input-group">
+  <li class="input-group">
     <span class="input-group-addon">Markdown</span>
     <input readonly class="copy-link form-control" type="text" value="[{{ path }}]({{ baseUrl }}/{{ page._id.toString() }})">
   </li>

+ 7 - 11
lib/views/widget/page_side_header.html

@@ -12,13 +12,13 @@
         <a href="{{ userPageRoot(page.creator) }}">{{ page.creator.name|default(author.name) }}</a>
       </p>
       <p class="created-at">
-        作成日: {{ page.createdAt|datetz('Y/m/d H:i:s') }}<br>
+        {{ t('Created') }}: {{ page.createdAt|datetz('Y/m/d H:i:s') }}<br>
 
         {% if page.lastUpdateUser %}
-          最終更新: {{ page.updatedAt|datetz('Y/m/d H:i:s') }} <a href="/user/{{ page.lastUpdateUser.username }}"><img src="{{ page.lastUpdateUser|picture }}" class="picture picture-xs picture-rounded" alt="{{ page.lastUpdateUser.name }}"></a>
+          {{ t('Last updated') }}: {{ page.updatedAt|datetz('Y/m/d H:i:s') }} <a href="/user/{{ page.lastUpdateUser.username }}"><img src="{{ page.lastUpdateUser|picture }}" class="picture picture-xs picture-rounded" alt="{{ page.lastUpdateUser.name }}"></a>
         {% else %}
           {# for BC 1.5.x #}
-          最終更新: {{ page.updatedAt|datetz('Y/m/d H:i:s') }} <a href="/user/{{ page.revision.author.username }}"><img src="{{ page.revision.author|picture }}" class="picture picture-xs picture-rounded" alt="{{ page.revision.author.name }}"></a>
+          {{ t('Last updated') }}: {{ page.updatedAt|datetz('Y/m/d H:i:s') }} <a href="/user/{{ page.revision.author.username }}"><img src="{{ page.revision.author|picture }}" class="picture picture-xs picture-rounded" alt="{{ page.revision.author.name }}"></a>
         {% endif %}
       </p>
     </div>
@@ -27,7 +27,7 @@
   <div class="like-box">
     <dl class="dl-horizontal">
       <dt>
-        <i class="fa fa-thumbs-o-up"></i> いいね!
+        <i class="fa fa-thumbs-o-up"></i> {{ t('Like!') }}
       </dt>
       <dd>
         <p class="liker-count">
@@ -36,19 +36,15 @@
           data-csrftoken="{{ csrf() }}"
           data-liked="{% if page.isLiked(user) %}1{% else %}0{% endif %}"
           class="like-button btn btn-default btn-sm {% if page.isLiked(user) %}active{% endif %}"
-          ><i class="fa fa-thumbs-o-up"></i> いいね!</button>
+          ><i class="fa fa-thumbs-o-up"></i> {{ t('Like!') }}</button>
         </p>
         <p id="liker-list" class="liker-list" data-likers="{{ page.liker|default([])|join(',') }}">
         </p>
       </dd>
 
-      <dt><i class="fa fa-paw"></i> 見た人</dt>
+      <dt><i class="fa fa-paw"></i> {{ t('Seen by') }}</dt>
       <dd>
-        <p class="seen-user-count">
-          {{ page.seenUsers.length }}
-        </p>
-        <p id="seen-user-list" class="seen-user-list" data-seen-users="{{ page.seenUsers|default([])|join(',') }}">
-        </p>
+        <div id="seen-user-list" data-seen-users="{{ page.seenUsers|default([])|join(',') }}"></div>
       </dd>
     </dl>
   </div>

+ 32 - 0
lib/views/widget/pager.html

@@ -0,0 +1,32 @@
+<ul class="pagination">
+
+  <li {% if pager.page == 1 %}class="disabled"{% endif %}>
+    <a href="{{ path }}?page={{ pager.previous|default(1) }}">&laquo;</a>
+  </li>
+  {% if pager.previousDots %}
+    {% if pager.page !== 1 %}
+    <li>
+      <a href="{{ path }}?page=1">1</a>
+    </li>
+    {% endif %}
+  <li><a href="#">...</a></li>
+  {% endif  %}
+
+  {% for page in pager.pages %}
+  <li {% if pager.page == page %}class="active"{% endif %}>
+    <a href="{{ path }}?page={{ page }}">{{ page }}</a>
+  </li>
+  {% endfor %}
+
+  {% if pager.nextDots %}
+  <li><a href="#">...</a></li>
+    {% if pager.page !== pager.pagesCount %}
+    <li>
+      <a href="{{ path }}?page={{ pager.pagesCount }}">{{ pager.pagesCount }}</a>
+    </li>
+    {% endif %}
+  {% endif  %}
+  <li {% if pager.page == pager.pagesCount %}class="disabled"{% endif %}>
+    <a href="{{ path }}?page={{ pager.next|default(pager.pagesCount) }}">&raquo;</a>
+  </li>
+</ul>

+ 1 - 2
local_modules/crowi-fileupload-aws/index.js

@@ -5,7 +5,6 @@ module.exports = function(crowi) {
 
   var aws = require('aws-sdk')
     , debug = require('debug')('crowi:lib:fileUploaderAws')
-    , Promise = require('bluebird')
     , Config = crowi.model('Config')
     , config = crowi.getConfig()
     , lib = {}
@@ -29,7 +28,7 @@ module.exports = function(crowi) {
   lib.uploadFile = function(filePath, contentType, fileStream, options) {
     var awsConfig = getAwsConfig();
     if (!Config.isUploadable(config)) {
-      return new Promise.reject(new Error('AWS is not configured.'));
+      return Promise.reject(new Error('AWS is not configured.'));
     }
 
     aws.config.update({

+ 0 - 1
local_modules/crowi-fileupload-local/index.js

@@ -7,7 +7,6 @@ module.exports = function(crowi) {
     , fs = require('fs')
     , path = require('path')
     , mkdir = require('mkdirp')
-    , Promise = require('bluebird')
     , Config = crowi.model('Config')
     , config = crowi.getConfig()
     , lib = {}

+ 1 - 0
locales/en

@@ -0,0 +1 @@
+en-US

+ 166 - 0
locales/en-US/translation.json

@@ -0,0 +1,166 @@
+{
+  "Help": "Help",
+  "Edit": "Edit",
+  "Delete": "Delete",
+  "Move": "Move",
+  "Moved": "Moved",
+  "Like!": "Like!",
+  "Seen by": "Seen by",
+  "Cancel": "Cancel",
+  "Create": "Create",
+  "Admin": "Admin",
+  "New": "New",
+
+  "Update": "Update",
+  "Update Page": "Update Page",
+  "Warning": "Warning",
+
+  "Sign in": "Sign in",
+  "Sign up is here": "Sign up",
+  "Sign in is here": "Sign in",
+  "Sign up": "Sign up",
+  "Sign up with Google Account": "Sign up with Google Account",
+  "Sign in with Google Account": "Sign in with Google Account",
+  "Sign up with this Google Account": "Sign up with this Google Account",
+  "Example": "Example",
+  "Taro Yamada": "James Bond",
+
+  "List View": "List",
+  "Timeline View": "Timeline",
+  "Presentation Mode": "Presentation Mode",
+
+  "Created": "Created",
+  "Last updated": "Updated",
+
+  "Share": "Share",
+  "Share Link": "Share Link",
+  "Markdown Link": "Markdown Link",
+
+  "Unportalize": "Unportalize",
+
+  "View this version": "View this version",
+  "View diff": "View diff",
+
+  "User ID": "User ID",
+  "User Settings": "User Settings",
+  "User Information": "User Information",
+  "Basic Info": "Basic Info",
+  "Name": "Name",
+  "Email": "Email",
+  "Language": "Language",
+  "English": "English",
+  "Japanese": "Japanese",
+  "Set Profile Image": "Set Profile Image",
+  "Current Image": "Current Image",
+  "Delete Image": "Delete Image",
+  "Delete this image?": "Delete this image?",
+  "Updated": "Updated",
+  "Upload new image": "Upload new image",
+  "Google Setting": "Google Setting",
+  "Connected": "Connected",
+  "Disconnect": "Disconnect",
+
+  "Create today's": "Create today's ...",
+  "Memo": "memo",
+  "Input page name": "Input page name",
+  "Input page name (optional)": "Input page name (optional)",
+  "New Page": "New Page",
+  "Create under": "Create page under: <code>%s</code>",
+
+  "Table of Contents": "Table of Contents",
+
+  "Public": "Public",
+  "Anyone with the link": "Anyone with the link",
+  "Specified users only": "Specified users only",
+  "Just me": "Just me",
+  "Shareable link": "Shareable link",
+
+  "Show latest": "Show latest",
+  "Load latest": "Load latest",
+  "edited this page": "edited this page.",
+
+  "Deleted Pages": "Deleted Pages",
+  "Sign out": "Logout",
+
+  "page_register": {
+    "notice": {
+      "restricted": "Admin approval required.",
+      "restricted_defail": "Once the admin approves your sign up, you'll be able to access this wiki.",
+      "google_account_continue": "Enter your user ID, name and password to continue."
+    },
+    "form_help": {
+      "email": "You must have email address which listed below to sign up to this wiki.",
+      "password": "Your password must be at least 6 characters long.",
+      "user_id": "The URL of pages you create will contain your User ID. Your User ID can consist of letters, numbers, and some symbols."
+    }
+  },
+
+  "page_me": {
+    "form_help": {
+      "profile_image1": "Image upload settings not completed.",
+      "profile_image2": "Set up AWS or enable local uploads.",
+      "google_connect1": "With Google Connect, you can sign in with your Google Account.",
+      "google_connect2": "Only Google Apps accounts with the following email addresses are connectable Google accounts:",
+      "google_disconnect1": "If you disconnect your Google account, you will be unable to sign in using Google Authentication",
+      "google_disconnect2": "After disconnecting your Google account, you can sign in normally using your email and password"
+    }
+  },
+  "page_me_apitoken": {
+    "notice": {
+      "apitoken_issued": "API Token is not issued.",
+      "update_token1": "You can update to generate a new API Token.",
+      "update_token2": "You will need to update the API Token in any existing processes."
+    },
+    "form_help": {
+    }
+  },
+
+  "Password": "Password",
+  "Password Settings": "Password Settings",
+  "Set new Password": "Set new Password",
+  "Update Password": "Update Password",
+  "Current password": "Current password",
+  "New password": "New password",
+  "Re-enter new password": "Re-enter new password",
+  "Please set a password": "Please set a password",
+  "You can sign in with email and password": "You can sign in with <code>%s</code> and password",
+
+  "API Settings": "API Settings",
+  "API Token Settings": "API Token Settings",
+  "Current API Token": "Current API Token",
+  "Update API Token": "Update API Token",
+
+  "page_page": {
+      "notice": {
+          "version": "This is not the current version.",
+          "moved": "This page was moved from <code>%s</code>",
+          "restricted": "Access to this page is restricted"
+      }
+  },
+
+  "Rename page": "Rename page",
+  "New page name": "New page name",
+  "Current page name": "Current page name",
+  "Redirect": "Redirect",
+  "modal_rename": {
+    "help": {
+      "redirect": "Redirect to new page if someone accesses <code>%s</code>"
+    }
+  },
+
+  "modal_help": {
+      "basic": {
+          "title": "Basics",
+          "body1": "There are 2 types of pages: List pages (showing lists of links to other pages) and normal pages.",
+          "body2": "Pages that end with a slash / are List pages for anything following the slash.",
+          "body3": "You can view older versions of a page from the History tab. Any changes made will be stored here."
+      },
+      "tips": {
+          "title": "Quick Tips on Editing",
+          "body1": "Use sections and subsections to make it easier for your friends to read your pages."
+      },
+      "markdown": {
+          "title": "Markdown Rules"
+      }
+  }
+}

+ 166 - 0
locales/ja/translation.json

@@ -0,0 +1,166 @@
+{
+  "Help": "ヘルプ",
+  "Edit": "編集",
+  "Delete": "削除",
+  "Move": "移動",
+  "Moved": "移動しました",
+  "Like!": "いいね!",
+  "Seen by": "見た人",
+  "Cancel": "キャンセル",
+  "Create": "作成",
+  "Admin": "管理",
+  "New": "作成",
+
+  "Update": "更新",
+  "Update Page": "ページを更新",
+  "Warning": "注意",
+
+  "Sign in": "ログイン",
+  "Sign up is here": "新規登録はこちら",
+  "Sign in is here": "ログインはこちら",
+  "Sign up": "新規登録",
+  "Sign up with Google Account": "Google で登録",
+  "Sign in with Google Account": "Google でログイン",
+  "Sign up with this Google Account": "この Google アカウントで登録します",
+  "Example": "例",
+  "Taro Yamada": "山田 太郎",
+
+  "List View": "リスト表示",
+  "Timeline View": "タイムライン表示",
+  "Presentation Mode": "プレゼンモード",
+
+  "Created": "作成日",
+  "Last updated": "最終更新",
+
+  "Share": "共有",
+  "Share Link": "共有用リンク",
+  "Markdown Link": "Markdown形式のリンク",
+
+  "Unportalize": "ポータル解除",
+
+  "View this version": "このバージョンを見る",
+  "View diff": "差分を見る",
+
+  "User ID": "ユーザーID",
+  "User Settings": "ユーザー設定",
+  "User Information": "ユーザー情報",
+  "Basic Info": "ユーザーの基本情報",
+  "Name": "名前",
+  "Email": "メールアドレス",
+  "Language": "言語",
+  "English": "英語",
+  "Japanese": "日本語",
+  "Set Profile Image": "プロフィール画像の設定",
+  "Current Image": "現在の画像",
+  "Delete Image": "画像を削除",
+  "Delete this image?": "削除してよろしいですか?",
+  "Updated": "更新しました",
+  "Upload new image": "新しい画像をアップロード",
+  "Google Setting": "Google設定",
+  "Connected": "接続されています",
+  "Disconnect": "接続を解除",
+
+  "Create today's": "今日の◯◯を作成",
+  "Memo": "メモ",
+  "Input page name": "ページ名を入力",
+  "Input page name (optional)": "ページ名を入力(空欄OK)",
+  "New Page": "新規ページ",
+  "Create under": "<code>%s</code>以下に作成",
+
+  "Table of Contents": "目次",
+
+  "Public": "公開",
+  "Anyone with the link": "リンクを知っている人のみ",
+  "Specified users": "特定ユーザーのみ",
+  "Just me": "自分のみ",
+  "Shareable link": "このページの共有用URL",
+
+  "Show latest": "最新のページを表示",
+  "Load latest": "最新版を読み込む",
+  "edited this page": "さんがこのページを編集しました。",
+
+  "Deleted Pages": "削除済みページ",
+  "Sign out": "ログアウト",
+
+  "page_register": {
+    "notice": {
+       "restricted": "この Wiki への新規登録は制限されています。",
+       "restricted_defail": "利用を開始するには、新規登録後、管理者による承認が必要です。",
+       "google_account_continue": "ユーザーID、名前、パスワードを決めて登録を継続してください。"
+    },
+    "form_help": {
+      "email": "この Wiki では以下のメールアドレスのみ登録可能です。",
+      "password": "パスワードには、6文字以上の半角英数字または記号等を設定してください。",
+      "user_id": "ユーザーIDは、ユーザーページのURLなどに利用されます。半角英数字と一部の記号のみ利用できます。"
+    }
+  },
+
+  "page_me": {
+    "form_help": {
+      "profile_image1": "画像をアップロードをするための設定がされていません。",
+      "profile_image2": "アップロードできるようにするには、AWS またはローカルアップロードの設定をしてください。",
+      "google_connect1": "Googleコネクトをすると、Googleアカウントでログイン可能になります。",
+      "google_connect2": "コネクト可能なGoogleアカウントは、以下のメールアドレスの発行できるGoogle Appsアカウントに限られます。",
+      "google_disconnect1": "接続を解除すると、Googleでログインができなくなります。",
+      "google_disconnect2": "解除後はメールアドレスとパスワードでログインすることができます。"
+    }
+  },
+  "page_me_apitoken": {
+    "notice": {
+      "apitoken_issued": "API Token が設定されていません。",
+      "update_token1": "API Token を更新すると、自動的に新しい Token が生成されます。",
+      "update_token2": "現在の Token を利用している処理は動かなくなります。"
+    },
+    "form_help": {
+    }
+  },
+
+  "Password": "パスワード",
+  "Password Settings": "パスワード設定",
+  "Set new Password": "パスワードを新規に設定",
+  "Update Password": "パスワードを更新",
+  "Current password": "現在のパスワード",
+  "New password": "新しいパスワード",
+  "Re-enter new password": "(確認用)",
+  "Please set a password": "パスワードを設定してください",
+  "You can sign in with email and password": "<code>%s</code> と設定されたパスワードの組み合わせでログイン可能になります。",
+
+  "API Settings": "API設定",
+  "API Token Settings": "API Token設定",
+  "Current API Token": "現在のAPI Token",
+  "Update API Token": "API Tokenを更新",
+
+  "page_page": {
+      "notice": {
+          "version": "これは現在の版ではありません。",
+          "moved": "このページは <code>%s</code> から移動しました。",
+          "restricted": "このページの閲覧は制限されています"
+      }
+  },
+
+  "Rename page": "ページを移動する",
+  "New page name": "移動先のページ名",
+  "Current page name": "現在のページ名",
+  "Redirect": "リダイレクトする",
+  "modal_rename": {
+    "help": {
+      "redirect": "チェックを入れると、<code>%s</code>にアクセスされた際に自動的に新しいページにジャンプします。"
+    }
+  },
+
+  "modal_help": {
+      "basic": {
+          "title": "基本的な機能",
+          "body1": "表示される画面には、「一覧ページ」と「ページ」の2種類があります",
+          "body2": "スラッシュ <code>/</code> で終わるページは、その階層の一覧ページとなります。",
+          "body3": "ページでの変更はすべて記録されています。History からそのページの過去の状態を見ることができます。"
+      },
+      "tips": {
+          "title": "編集のコツ",
+          "body1": "文章の <strong>構造</strong> を意識しましょう。本を書くように、内容と文脈を整理してセクション・サブセクション...と構造的に書くと、わかりやすく他人に伝わりやすいページがになります。"
+      },
+      "markdown": {
+          "title": "記法"
+      }
+  }
+}

+ 6599 - 0
npm-shrinkwrap.json

@@ -0,0 +1,6599 @@
+{
+  "name": "crowi",
+  "version": "1.6.0",
+  "dependencies": {
+    "abbrev": {
+      "version": "1.0.9",
+      "from": "abbrev@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.9.tgz"
+    },
+    "accepts": {
+      "version": "1.3.3",
+      "from": "accepts@>=1.3.3 <1.4.0",
+      "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.3.tgz"
+    },
+    "acorn": {
+      "version": "4.0.11",
+      "from": "acorn@>=4.0.4 <5.0.0",
+      "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.11.tgz"
+    },
+    "acorn-dynamic-import": {
+      "version": "2.0.2",
+      "from": "acorn-dynamic-import@>=2.0.0 <3.0.0",
+      "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-2.0.2.tgz"
+    },
+    "addressparser": {
+      "version": "1.0.1",
+      "from": "addressparser@1.0.1",
+      "resolved": "https://registry.npmjs.org/addressparser/-/addressparser-1.0.1.tgz"
+    },
+    "after": {
+      "version": "0.8.1",
+      "from": "after@0.8.1",
+      "resolved": "https://registry.npmjs.org/after/-/after-0.8.1.tgz"
+    },
+    "agent-base": {
+      "version": "2.0.1",
+      "from": "agent-base@>=2.0.0 <3.0.0",
+      "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-2.0.1.tgz"
+    },
+    "ajv": {
+      "version": "4.11.4",
+      "from": "ajv@>=4.7.0 <5.0.0",
+      "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.4.tgz",
+      "dependencies": {
+        "co": {
+          "version": "4.6.0",
+          "from": "co@>=4.6.0 <5.0.0",
+          "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz"
+        }
+      }
+    },
+    "ajv-keywords": {
+      "version": "1.5.1",
+      "from": "ajv-keywords@>=1.1.1 <2.0.0",
+      "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-1.5.1.tgz"
+    },
+    "align-text": {
+      "version": "0.1.4",
+      "from": "align-text@>=0.1.3 <0.2.0",
+      "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz"
+    },
+    "amdefine": {
+      "version": "1.0.1",
+      "from": "amdefine@>=0.0.4",
+      "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz"
+    },
+    "ansi-escape-sequences": {
+      "version": "2.2.2",
+      "from": "ansi-escape-sequences@>=2.2.2 <3.0.0",
+      "resolved": "https://registry.npmjs.org/ansi-escape-sequences/-/ansi-escape-sequences-2.2.2.tgz"
+    },
+    "ansi-regex": {
+      "version": "2.1.1",
+      "from": "ansi-regex@>=2.0.0 <3.0.0",
+      "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz"
+    },
+    "ansi-styles": {
+      "version": "2.2.1",
+      "from": "ansi-styles@>=2.2.1 <3.0.0",
+      "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz"
+    },
+    "anymatch": {
+      "version": "1.3.0",
+      "from": "anymatch@>=1.3.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.0.tgz"
+    },
+    "append-field": {
+      "version": "0.1.0",
+      "from": "append-field@>=0.1.0 <0.2.0",
+      "resolved": "https://registry.npmjs.org/append-field/-/append-field-0.1.0.tgz"
+    },
+    "aproba": {
+      "version": "1.0.4",
+      "from": "aproba@>=1.0.3 <2.0.0",
+      "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.0.4.tgz"
+    },
+    "archy": {
+      "version": "1.0.0",
+      "from": "archy@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz"
+    },
+    "are-we-there-yet": {
+      "version": "1.1.2",
+      "from": "are-we-there-yet@>=1.1.2 <1.2.0",
+      "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.2.tgz"
+    },
+    "argparse": {
+      "version": "1.0.9",
+      "from": "argparse@>=1.0.7 <2.0.0",
+      "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz"
+    },
+    "arr-diff": {
+      "version": "2.0.0",
+      "from": "arr-diff@>=2.0.0 <3.0.0",
+      "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz"
+    },
+    "arr-flatten": {
+      "version": "1.0.1",
+      "from": "arr-flatten@>=1.0.1 <2.0.0",
+      "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.0.1.tgz"
+    },
+    "array-back": {
+      "version": "1.0.4",
+      "from": "array-back@>=1.0.2 <2.0.0",
+      "resolved": "https://registry.npmjs.org/array-back/-/array-back-1.0.4.tgz"
+    },
+    "array-differ": {
+      "version": "1.0.0",
+      "from": "array-differ@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz"
+    },
+    "array-find-index": {
+      "version": "1.0.2",
+      "from": "array-find-index@>=1.0.1 <2.0.0",
+      "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz"
+    },
+    "array-flatten": {
+      "version": "1.1.1",
+      "from": "array-flatten@1.1.1",
+      "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz"
+    },
+    "array-union": {
+      "version": "1.0.2",
+      "from": "array-union@>=1.0.1 <2.0.0",
+      "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz"
+    },
+    "array-uniq": {
+      "version": "1.0.3",
+      "from": "array-uniq@>=1.0.1 <2.0.0",
+      "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz"
+    },
+    "array-unique": {
+      "version": "0.2.1",
+      "from": "array-unique@>=0.2.1 <0.3.0",
+      "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz"
+    },
+    "arraybuffer.slice": {
+      "version": "0.0.6",
+      "from": "arraybuffer.slice@0.0.6",
+      "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.6.tgz"
+    },
+    "arrify": {
+      "version": "1.0.1",
+      "from": "arrify@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz"
+    },
+    "asap": {
+      "version": "2.0.5",
+      "from": "asap@>=2.0.3 <2.1.0",
+      "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.5.tgz"
+    },
+    "asn1": {
+      "version": "0.2.3",
+      "from": "asn1@>=0.2.3 <0.3.0",
+      "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz"
+    },
+    "asn1.js": {
+      "version": "4.9.1",
+      "from": "asn1.js@>=4.0.0 <5.0.0",
+      "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.9.1.tgz"
+    },
+    "assert": {
+      "version": "1.4.1",
+      "from": "assert@>=1.1.1 <2.0.0",
+      "resolved": "https://registry.npmjs.org/assert/-/assert-1.4.1.tgz"
+    },
+    "assert-plus": {
+      "version": "0.2.0",
+      "from": "assert-plus@>=0.2.0 <0.3.0",
+      "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz"
+    },
+    "assertion-error": {
+      "version": "1.0.0",
+      "from": "assertion-error@1.0.0",
+      "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.0.0.tgz",
+      "dev": true
+    },
+    "async": {
+      "version": "1.5.2",
+      "from": "async@>=1.5.0 <1.6.0",
+      "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz"
+    },
+    "async-each": {
+      "version": "1.0.1",
+      "from": "async-each@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz"
+    },
+    "async-foreach": {
+      "version": "0.1.3",
+      "from": "async-foreach@>=0.1.3 <0.2.0",
+      "resolved": "https://registry.npmjs.org/async-foreach/-/async-foreach-0.1.3.tgz"
+    },
+    "asynckit": {
+      "version": "0.4.0",
+      "from": "asynckit@>=0.4.0 <0.5.0",
+      "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz"
+    },
+    "aws-sdk": {
+      "version": "2.2.48",
+      "from": "aws-sdk@>=2.2.26 <2.3.0",
+      "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.2.48.tgz"
+    },
+    "aws-sign2": {
+      "version": "0.6.0",
+      "from": "aws-sign2@>=0.6.0 <0.7.0",
+      "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz"
+    },
+    "aws4": {
+      "version": "1.5.0",
+      "from": "aws4@>=1.2.1 <2.0.0",
+      "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.5.0.tgz"
+    },
+    "axios": {
+      "version": "0.15.3",
+      "from": "axios@>=0.15.0 <0.16.0",
+      "resolved": "https://registry.npmjs.org/axios/-/axios-0.15.3.tgz"
+    },
+    "babel-code-frame": {
+      "version": "6.22.0",
+      "from": "babel-code-frame@>=6.7.7 <7.0.0",
+      "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.22.0.tgz"
+    },
+    "babel-core": {
+      "version": "6.7.7",
+      "from": "babel-core@>=6.7.6 <6.8.0",
+      "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.7.7.tgz",
+      "dependencies": {
+        "lodash": {
+          "version": "3.10.1",
+          "from": "lodash@>=3.10.0 <4.0.0",
+          "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz"
+        }
+      }
+    },
+    "babel-generator": {
+      "version": "6.22.0",
+      "from": "babel-generator@>=6.7.7 <7.0.0",
+      "resolved": "https://registry.npmjs.org/babel-generator/-/babel-generator-6.22.0.tgz",
+      "dependencies": {
+        "babel-runtime": {
+          "version": "6.22.0",
+          "from": "babel-runtime@>=6.22.0 <7.0.0",
+          "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.22.0.tgz"
+        },
+        "lodash": {
+          "version": "4.17.4",
+          "from": "lodash@>=4.2.0 <5.0.0",
+          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz"
+        }
+      }
+    },
+    "babel-helper-builder-react-jsx": {
+      "version": "6.23.0",
+      "from": "babel-helper-builder-react-jsx@>=6.23.0 <7.0.0",
+      "resolved": "https://registry.npmjs.org/babel-helper-builder-react-jsx/-/babel-helper-builder-react-jsx-6.23.0.tgz",
+      "dependencies": {
+        "babel-runtime": {
+          "version": "6.23.0",
+          "from": "babel-runtime@^6.22.0",
+          "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz"
+        },
+        "babel-types": {
+          "version": "6.23.0",
+          "from": "babel-types@^6.23.0",
+          "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.23.0.tgz"
+        },
+        "lodash": {
+          "version": "4.17.4",
+          "from": "lodash@>=4.2.0 <5.0.0",
+          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz"
+        }
+      }
+    },
+    "babel-helper-call-delegate": {
+      "version": "6.22.0",
+      "from": "babel-helper-call-delegate@>=6.22.0 <7.0.0",
+      "resolved": "https://registry.npmjs.org/babel-helper-call-delegate/-/babel-helper-call-delegate-6.22.0.tgz",
+      "dependencies": {
+        "babel-runtime": {
+          "version": "6.23.0",
+          "from": "babel-runtime@^6.22.0",
+          "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz"
+        }
+      }
+    },
+    "babel-helper-define-map": {
+      "version": "6.23.0",
+      "from": "babel-helper-define-map@>=6.23.0 <7.0.0",
+      "resolved": "https://registry.npmjs.org/babel-helper-define-map/-/babel-helper-define-map-6.23.0.tgz",
+      "dependencies": {
+        "babel-runtime": {
+          "version": "6.23.0",
+          "from": "babel-runtime@^6.22.0",
+          "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz"
+        },
+        "babel-types": {
+          "version": "6.23.0",
+          "from": "babel-types@^6.23.0",
+          "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.23.0.tgz"
+        },
+        "lodash": {
+          "version": "4.17.4",
+          "from": "lodash@>=4.2.0 <5.0.0",
+          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz"
+        }
+      }
+    },
+    "babel-helper-function-name": {
+      "version": "6.23.0",
+      "from": "babel-helper-function-name@>=6.23.0 <7.0.0",
+      "resolved": "https://registry.npmjs.org/babel-helper-function-name/-/babel-helper-function-name-6.23.0.tgz",
+      "dependencies": {
+        "babel-messages": {
+          "version": "6.23.0",
+          "from": "babel-messages@^6.23.0",
+          "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz"
+        },
+        "babel-runtime": {
+          "version": "6.23.0",
+          "from": "babel-runtime@^6.22.0",
+          "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz"
+        },
+        "babel-template": {
+          "version": "6.23.0",
+          "from": "babel-template@^6.23.0",
+          "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.23.0.tgz"
+        },
+        "babel-traverse": {
+          "version": "6.23.1",
+          "from": "babel-traverse@^6.23.0",
+          "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.23.1.tgz"
+        },
+        "babel-types": {
+          "version": "6.23.0",
+          "from": "babel-types@^6.23.0",
+          "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.23.0.tgz"
+        },
+        "lodash": {
+          "version": "4.17.4",
+          "from": "lodash@^4.2.0",
+          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz"
+        }
+      }
+    },
+    "babel-helper-get-function-arity": {
+      "version": "6.22.0",
+      "from": "babel-helper-get-function-arity@>=6.22.0 <7.0.0",
+      "resolved": "https://registry.npmjs.org/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.22.0.tgz",
+      "dependencies": {
+        "babel-runtime": {
+          "version": "6.23.0",
+          "from": "babel-runtime@^6.22.0",
+          "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz"
+        }
+      }
+    },
+    "babel-helper-hoist-variables": {
+      "version": "6.22.0",
+      "from": "babel-helper-hoist-variables@>=6.22.0 <7.0.0",
+      "resolved": "https://registry.npmjs.org/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.22.0.tgz",
+      "dependencies": {
+        "babel-runtime": {
+          "version": "6.23.0",
+          "from": "babel-runtime@^6.22.0",
+          "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz"
+        }
+      }
+    },
+    "babel-helper-optimise-call-expression": {
+      "version": "6.23.0",
+      "from": "babel-helper-optimise-call-expression@>=6.23.0 <7.0.0",
+      "resolved": "https://registry.npmjs.org/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.23.0.tgz",
+      "dependencies": {
+        "babel-runtime": {
+          "version": "6.23.0",
+          "from": "babel-runtime@^6.22.0",
+          "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz"
+        },
+        "babel-types": {
+          "version": "6.23.0",
+          "from": "babel-types@^6.23.0",
+          "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.23.0.tgz"
+        },
+        "lodash": {
+          "version": "4.17.4",
+          "from": "lodash@^4.2.0",
+          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz"
+        }
+      }
+    },
+    "babel-helper-regex": {
+      "version": "6.22.0",
+      "from": "babel-helper-regex@>=6.22.0 <7.0.0",
+      "resolved": "https://registry.npmjs.org/babel-helper-regex/-/babel-helper-regex-6.22.0.tgz",
+      "dependencies": {
+        "babel-runtime": {
+          "version": "6.23.0",
+          "from": "babel-runtime@^6.22.0",
+          "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz"
+        },
+        "lodash": {
+          "version": "4.17.4",
+          "from": "lodash@>=4.2.0 <5.0.0",
+          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz"
+        }
+      }
+    },
+    "babel-helper-replace-supers": {
+      "version": "6.23.0",
+      "from": "babel-helper-replace-supers@>=6.23.0 <7.0.0",
+      "resolved": "https://registry.npmjs.org/babel-helper-replace-supers/-/babel-helper-replace-supers-6.23.0.tgz",
+      "dependencies": {
+        "babel-messages": {
+          "version": "6.23.0",
+          "from": "babel-messages@^6.23.0",
+          "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz"
+        },
+        "babel-runtime": {
+          "version": "6.23.0",
+          "from": "babel-runtime@^6.22.0",
+          "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz"
+        },
+        "babel-template": {
+          "version": "6.23.0",
+          "from": "babel-template@^6.23.0",
+          "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.23.0.tgz"
+        },
+        "babel-traverse": {
+          "version": "6.23.1",
+          "from": "babel-traverse@^6.23.0",
+          "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.23.1.tgz"
+        },
+        "babel-types": {
+          "version": "6.23.0",
+          "from": "babel-types@^6.23.0",
+          "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.23.0.tgz"
+        },
+        "lodash": {
+          "version": "4.17.4",
+          "from": "lodash@^4.2.0",
+          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz"
+        }
+      }
+    },
+    "babel-helpers": {
+      "version": "6.22.0",
+      "from": "babel-helpers@>=6.6.0 <7.0.0",
+      "resolved": "https://registry.npmjs.org/babel-helpers/-/babel-helpers-6.22.0.tgz",
+      "dependencies": {
+        "babel-runtime": {
+          "version": "6.22.0",
+          "from": "babel-runtime@>=6.22.0 <7.0.0",
+          "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.22.0.tgz"
+        }
+      }
+    },
+    "babel-loader": {
+      "version": "6.3.2",
+      "from": "babel-loader@>=6.3.0 <6.4.0",
+      "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-6.3.2.tgz"
+    },
+    "babel-messages": {
+      "version": "6.22.0",
+      "from": "babel-messages@>=6.7.2 <7.0.0",
+      "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.22.0.tgz",
+      "dependencies": {
+        "babel-runtime": {
+          "version": "6.22.0",
+          "from": "babel-runtime@>=6.22.0 <7.0.0",
+          "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.22.0.tgz"
+        }
+      }
+    },
+    "babel-plugin-check-es2015-constants": {
+      "version": "6.22.0",
+      "from": "babel-plugin-check-es2015-constants@>=6.3.13 <7.0.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz",
+      "dependencies": {
+        "babel-runtime": {
+          "version": "6.23.0",
+          "from": "babel-runtime@>=6.22.0 <7.0.0",
+          "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz"
+        }
+      }
+    },
+    "babel-plugin-syntax-flow": {
+      "version": "6.18.0",
+      "from": "babel-plugin-syntax-flow@>=6.3.13 <7.0.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-syntax-flow/-/babel-plugin-syntax-flow-6.18.0.tgz"
+    },
+    "babel-plugin-syntax-jsx": {
+      "version": "6.18.0",
+      "from": "babel-plugin-syntax-jsx@>=6.3.13 <7.0.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-syntax-jsx/-/babel-plugin-syntax-jsx-6.18.0.tgz"
+    },
+    "babel-plugin-transform-es2015-arrow-functions": {
+      "version": "6.22.0",
+      "from": "babel-plugin-transform-es2015-arrow-functions@>=6.3.13 <7.0.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz",
+      "dependencies": {
+        "babel-runtime": {
+          "version": "6.23.0",
+          "from": "babel-runtime@^6.22.0",
+          "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz"
+        }
+      }
+    },
+    "babel-plugin-transform-es2015-block-scoped-functions": {
+      "version": "6.22.0",
+      "from": "babel-plugin-transform-es2015-block-scoped-functions@>=6.3.13 <7.0.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz",
+      "dependencies": {
+        "babel-runtime": {
+          "version": "6.23.0",
+          "from": "babel-runtime@^6.22.0",
+          "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz"
+        }
+      }
+    },
+    "babel-plugin-transform-es2015-block-scoping": {
+      "version": "6.23.0",
+      "from": "babel-plugin-transform-es2015-block-scoping@>=6.22.0 <7.0.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.23.0.tgz",
+      "dependencies": {
+        "babel-messages": {
+          "version": "6.23.0",
+          "from": "babel-messages@>=6.23.0 <7.0.0",
+          "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz"
+        },
+        "babel-runtime": {
+          "version": "6.23.0",
+          "from": "babel-runtime@^6.22.0",
+          "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz"
+        },
+        "babel-template": {
+          "version": "6.23.0",
+          "from": "babel-template@>=6.23.0 <7.0.0",
+          "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.23.0.tgz"
+        },
+        "babel-traverse": {
+          "version": "6.23.1",
+          "from": "babel-traverse@>=6.23.0 <7.0.0",
+          "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.23.1.tgz"
+        },
+        "babel-types": {
+          "version": "6.23.0",
+          "from": "babel-types@>=6.23.0 <7.0.0",
+          "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.23.0.tgz"
+        },
+        "lodash": {
+          "version": "4.17.4",
+          "from": "lodash@>=4.2.0 <5.0.0",
+          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz"
+        }
+      }
+    },
+    "babel-plugin-transform-es2015-classes": {
+      "version": "6.23.0",
+      "from": "babel-plugin-transform-es2015-classes@>=6.22.0 <7.0.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.23.0.tgz",
+      "dependencies": {
+        "babel-messages": {
+          "version": "6.23.0",
+          "from": "babel-messages@^6.23.0",
+          "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz"
+        },
+        "babel-runtime": {
+          "version": "6.23.0",
+          "from": "babel-runtime@^6.22.0",
+          "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz"
+        },
+        "babel-template": {
+          "version": "6.23.0",
+          "from": "babel-template@^6.23.0",
+          "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.23.0.tgz"
+        },
+        "babel-traverse": {
+          "version": "6.23.1",
+          "from": "babel-traverse@^6.23.0",
+          "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.23.1.tgz"
+        },
+        "babel-types": {
+          "version": "6.23.0",
+          "from": "babel-types@^6.23.0",
+          "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.23.0.tgz"
+        },
+        "lodash": {
+          "version": "4.17.4",
+          "from": "lodash@^4.2.0",
+          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz"
+        }
+      }
+    },
+    "babel-plugin-transform-es2015-computed-properties": {
+      "version": "6.22.0",
+      "from": "babel-plugin-transform-es2015-computed-properties@>=6.3.13 <7.0.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.22.0.tgz",
+      "dependencies": {
+        "babel-runtime": {
+          "version": "6.23.0",
+          "from": "babel-runtime@^6.22.0",
+          "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz"
+        }
+      }
+    },
+    "babel-plugin-transform-es2015-destructuring": {
+      "version": "6.23.0",
+      "from": "babel-plugin-transform-es2015-destructuring@>=6.22.0 <7.0.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz",
+      "dependencies": {
+        "babel-runtime": {
+          "version": "6.23.0",
+          "from": "babel-runtime@^6.22.0",
+          "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz"
+        }
+      }
+    },
+    "babel-plugin-transform-es2015-duplicate-keys": {
+      "version": "6.22.0",
+      "from": "babel-plugin-transform-es2015-duplicate-keys@>=6.6.0 <7.0.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.22.0.tgz",
+      "dependencies": {
+        "babel-runtime": {
+          "version": "6.23.0",
+          "from": "babel-runtime@^6.22.0",
+          "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz"
+        }
+      }
+    },
+    "babel-plugin-transform-es2015-for-of": {
+      "version": "6.23.0",
+      "from": "babel-plugin-transform-es2015-for-of@>=6.22.0 <7.0.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz",
+      "dependencies": {
+        "babel-runtime": {
+          "version": "6.23.0",
+          "from": "babel-runtime@^6.22.0",
+          "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz"
+        }
+      }
+    },
+    "babel-plugin-transform-es2015-function-name": {
+      "version": "6.22.0",
+      "from": "babel-plugin-transform-es2015-function-name@>=6.3.13 <7.0.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.22.0.tgz",
+      "dependencies": {
+        "babel-runtime": {
+          "version": "6.23.0",
+          "from": "babel-runtime@^6.22.0",
+          "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz"
+        }
+      }
+    },
+    "babel-plugin-transform-es2015-literals": {
+      "version": "6.22.0",
+      "from": "babel-plugin-transform-es2015-literals@>=6.3.13 <7.0.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz",
+      "dependencies": {
+        "babel-runtime": {
+          "version": "6.23.0",
+          "from": "babel-runtime@^6.22.0",
+          "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz"
+        }
+      }
+    },
+    "babel-plugin-transform-es2015-modules-amd": {
+      "version": "6.22.0",
+      "from": "babel-plugin-transform-es2015-modules-amd@>=6.22.0 <7.0.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.22.0.tgz",
+      "dependencies": {
+        "babel-runtime": {
+          "version": "6.23.0",
+          "from": "babel-runtime@^6.22.0",
+          "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz"
+        }
+      }
+    },
+    "babel-plugin-transform-es2015-modules-commonjs": {
+      "version": "6.23.0",
+      "from": "babel-plugin-transform-es2015-modules-commonjs@>=6.22.0 <7.0.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.23.0.tgz",
+      "dependencies": {
+        "babel-messages": {
+          "version": "6.23.0",
+          "from": "babel-messages@^6.23.0",
+          "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz"
+        },
+        "babel-runtime": {
+          "version": "6.23.0",
+          "from": "babel-runtime@^6.22.0",
+          "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz"
+        },
+        "babel-template": {
+          "version": "6.23.0",
+          "from": "babel-template@^6.23.0",
+          "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.23.0.tgz"
+        },
+        "babel-traverse": {
+          "version": "6.23.1",
+          "from": "babel-traverse@^6.23.0",
+          "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.23.1.tgz"
+        },
+        "babel-types": {
+          "version": "6.23.0",
+          "from": "babel-types@^6.23.0",
+          "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.23.0.tgz"
+        },
+        "lodash": {
+          "version": "4.17.4",
+          "from": "lodash@^4.2.0",
+          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz"
+        }
+      }
+    },
+    "babel-plugin-transform-es2015-modules-systemjs": {
+      "version": "6.23.0",
+      "from": "babel-plugin-transform-es2015-modules-systemjs@>=6.22.0 <7.0.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.23.0.tgz",
+      "dependencies": {
+        "babel-messages": {
+          "version": "6.23.0",
+          "from": "babel-messages@^6.23.0",
+          "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz"
+        },
+        "babel-runtime": {
+          "version": "6.23.0",
+          "from": "babel-runtime@^6.22.0",
+          "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz"
+        },
+        "babel-template": {
+          "version": "6.23.0",
+          "from": "babel-template@^6.23.0",
+          "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.23.0.tgz"
+        },
+        "babel-traverse": {
+          "version": "6.23.1",
+          "from": "babel-traverse@^6.23.0",
+          "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.23.1.tgz"
+        },
+        "babel-types": {
+          "version": "6.23.0",
+          "from": "babel-types@^6.23.0",
+          "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.23.0.tgz"
+        },
+        "lodash": {
+          "version": "4.17.4",
+          "from": "lodash@^4.2.0",
+          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz"
+        }
+      }
+    },
+    "babel-plugin-transform-es2015-modules-umd": {
+      "version": "6.23.0",
+      "from": "babel-plugin-transform-es2015-modules-umd@>=6.22.0 <7.0.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.23.0.tgz",
+      "dependencies": {
+        "babel-messages": {
+          "version": "6.23.0",
+          "from": "babel-messages@^6.23.0",
+          "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz"
+        },
+        "babel-runtime": {
+          "version": "6.23.0",
+          "from": "babel-runtime@^6.22.0",
+          "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz"
+        },
+        "babel-template": {
+          "version": "6.23.0",
+          "from": "babel-template@^6.23.0",
+          "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.23.0.tgz"
+        },
+        "babel-traverse": {
+          "version": "6.23.1",
+          "from": "babel-traverse@^6.23.0",
+          "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.23.1.tgz"
+        },
+        "babel-types": {
+          "version": "6.23.0",
+          "from": "babel-types@^6.23.0",
+          "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.23.0.tgz"
+        },
+        "lodash": {
+          "version": "4.17.4",
+          "from": "lodash@^4.2.0",
+          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz"
+        }
+      }
+    },
+    "babel-plugin-transform-es2015-object-super": {
+      "version": "6.22.0",
+      "from": "babel-plugin-transform-es2015-object-super@>=6.3.13 <7.0.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.22.0.tgz",
+      "dependencies": {
+        "babel-runtime": {
+          "version": "6.23.0",
+          "from": "babel-runtime@^6.22.0",
+          "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz"
+        }
+      }
+    },
+    "babel-plugin-transform-es2015-parameters": {
+      "version": "6.23.0",
+      "from": "babel-plugin-transform-es2015-parameters@>=6.22.0 <7.0.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.23.0.tgz",
+      "dependencies": {
+        "babel-messages": {
+          "version": "6.23.0",
+          "from": "babel-messages@^6.23.0",
+          "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz"
+        },
+        "babel-runtime": {
+          "version": "6.23.0",
+          "from": "babel-runtime@^6.22.0",
+          "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz"
+        },
+        "babel-template": {
+          "version": "6.23.0",
+          "from": "babel-template@^6.23.0",
+          "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.23.0.tgz"
+        },
+        "babel-traverse": {
+          "version": "6.23.1",
+          "from": "babel-traverse@^6.23.0",
+          "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.23.1.tgz"
+        },
+        "babel-types": {
+          "version": "6.23.0",
+          "from": "babel-types@^6.23.0",
+          "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.23.0.tgz"
+        },
+        "lodash": {
+          "version": "4.17.4",
+          "from": "lodash@^4.2.0",
+          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz"
+        }
+      }
+    },
+    "babel-plugin-transform-es2015-shorthand-properties": {
+      "version": "6.22.0",
+      "from": "babel-plugin-transform-es2015-shorthand-properties@>=6.3.13 <7.0.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.22.0.tgz",
+      "dependencies": {
+        "babel-runtime": {
+          "version": "6.23.0",
+          "from": "babel-runtime@^6.22.0",
+          "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz"
+        }
+      }
+    },
+    "babel-plugin-transform-es2015-spread": {
+      "version": "6.22.0",
+      "from": "babel-plugin-transform-es2015-spread@>=6.3.13 <7.0.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz",
+      "dependencies": {
+        "babel-runtime": {
+          "version": "6.23.0",
+          "from": "babel-runtime@^6.22.0",
+          "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz"
+        }
+      }
+    },
+    "babel-plugin-transform-es2015-sticky-regex": {
+      "version": "6.22.0",
+      "from": "babel-plugin-transform-es2015-sticky-regex@>=6.3.13 <7.0.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.22.0.tgz",
+      "dependencies": {
+        "babel-runtime": {
+          "version": "6.23.0",
+          "from": "babel-runtime@^6.22.0",
+          "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz"
+        }
+      }
+    },
+    "babel-plugin-transform-es2015-template-literals": {
+      "version": "6.22.0",
+      "from": "babel-plugin-transform-es2015-template-literals@>=6.6.0 <7.0.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz",
+      "dependencies": {
+        "babel-runtime": {
+          "version": "6.23.0",
+          "from": "babel-runtime@^6.22.0",
+          "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz"
+        }
+      }
+    },
+    "babel-plugin-transform-es2015-typeof-symbol": {
+      "version": "6.23.0",
+      "from": "babel-plugin-transform-es2015-typeof-symbol@>=6.22.0 <7.0.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz",
+      "dependencies": {
+        "babel-runtime": {
+          "version": "6.23.0",
+          "from": "babel-runtime@^6.22.0",
+          "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz"
+        }
+      }
+    },
+    "babel-plugin-transform-es2015-unicode-regex": {
+      "version": "6.22.0",
+      "from": "babel-plugin-transform-es2015-unicode-regex@>=6.3.13 <7.0.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.22.0.tgz",
+      "dependencies": {
+        "babel-runtime": {
+          "version": "6.23.0",
+          "from": "babel-runtime@^6.22.0",
+          "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz"
+        }
+      }
+    },
+    "babel-plugin-transform-flow-strip-types": {
+      "version": "6.22.0",
+      "from": "babel-plugin-transform-flow-strip-types@>=6.3.13 <7.0.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-transform-flow-strip-types/-/babel-plugin-transform-flow-strip-types-6.22.0.tgz",
+      "dependencies": {
+        "babel-runtime": {
+          "version": "6.23.0",
+          "from": "babel-runtime@^6.22.0",
+          "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz"
+        }
+      }
+    },
+    "babel-plugin-transform-react-display-name": {
+      "version": "6.23.0",
+      "from": "babel-plugin-transform-react-display-name@>=6.23.0 <7.0.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-display-name/-/babel-plugin-transform-react-display-name-6.23.0.tgz",
+      "dependencies": {
+        "babel-runtime": {
+          "version": "6.23.0",
+          "from": "babel-runtime@^6.22.0",
+          "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz"
+        }
+      }
+    },
+    "babel-plugin-transform-react-jsx": {
+      "version": "6.23.0",
+      "from": "babel-plugin-transform-react-jsx@>=6.23.0 <7.0.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-jsx/-/babel-plugin-transform-react-jsx-6.23.0.tgz",
+      "dependencies": {
+        "babel-runtime": {
+          "version": "6.23.0",
+          "from": "babel-runtime@^6.22.0",
+          "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz"
+        }
+      }
+    },
+    "babel-plugin-transform-react-jsx-self": {
+      "version": "6.22.0",
+      "from": "babel-plugin-transform-react-jsx-self@>=6.22.0 <7.0.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-jsx-self/-/babel-plugin-transform-react-jsx-self-6.22.0.tgz",
+      "dependencies": {
+        "babel-runtime": {
+          "version": "6.23.0",
+          "from": "babel-runtime@^6.22.0",
+          "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz"
+        }
+      }
+    },
+    "babel-plugin-transform-react-jsx-source": {
+      "version": "6.22.0",
+      "from": "babel-plugin-transform-react-jsx-source@>=6.3.13 <7.0.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-transform-react-jsx-source/-/babel-plugin-transform-react-jsx-source-6.22.0.tgz",
+      "dependencies": {
+        "babel-runtime": {
+          "version": "6.23.0",
+          "from": "babel-runtime@^6.22.0",
+          "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz"
+        }
+      }
+    },
+    "babel-plugin-transform-regenerator": {
+      "version": "6.22.0",
+      "from": "babel-plugin-transform-regenerator@>=6.6.0 <7.0.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.22.0.tgz"
+    },
+    "babel-plugin-transform-strict-mode": {
+      "version": "6.22.0",
+      "from": "babel-plugin-transform-strict-mode@>=6.22.0 <7.0.0",
+      "resolved": "https://registry.npmjs.org/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.22.0.tgz",
+      "dependencies": {
+        "babel-runtime": {
+          "version": "6.23.0",
+          "from": "babel-runtime@^6.22.0",
+          "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz"
+        }
+      }
+    },
+    "babel-preset-es2015": {
+      "version": "6.22.0",
+      "from": "babel-preset-es2015@>=6.22.0 <6.23.0",
+      "resolved": "https://registry.npmjs.org/babel-preset-es2015/-/babel-preset-es2015-6.22.0.tgz"
+    },
+    "babel-preset-flow": {
+      "version": "6.23.0",
+      "from": "babel-preset-flow@>=6.23.0 <7.0.0",
+      "resolved": "https://registry.npmjs.org/babel-preset-flow/-/babel-preset-flow-6.23.0.tgz"
+    },
+    "babel-preset-react": {
+      "version": "6.23.0",
+      "from": "babel-preset-react@>=6.23.0 <6.24.0",
+      "resolved": "https://registry.npmjs.org/babel-preset-react/-/babel-preset-react-6.23.0.tgz"
+    },
+    "babel-register": {
+      "version": "6.22.0",
+      "from": "babel-register@>=6.7.2 <7.0.0",
+      "resolved": "https://registry.npmjs.org/babel-register/-/babel-register-6.22.0.tgz",
+      "dependencies": {
+        "babel-core": {
+          "version": "6.22.1",
+          "from": "babel-core@>=6.22.0 <7.0.0",
+          "resolved": "https://registry.npmjs.org/babel-core/-/babel-core-6.22.1.tgz"
+        },
+        "babel-runtime": {
+          "version": "6.22.0",
+          "from": "babel-runtime@>=6.22.0 <7.0.0",
+          "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.22.0.tgz"
+        },
+        "json5": {
+          "version": "0.5.1",
+          "from": "json5@>=0.5.0 <0.6.0",
+          "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz"
+        },
+        "lodash": {
+          "version": "4.17.4",
+          "from": "lodash@>=4.2.0 <5.0.0",
+          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz"
+        },
+        "minimatch": {
+          "version": "3.0.3",
+          "from": "minimatch@>=3.0.2 <4.0.0",
+          "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.3.tgz"
+        }
+      }
+    },
+    "babel-runtime": {
+      "version": "5.8.38",
+      "from": "babel-runtime@>=5.0.0 <6.0.0",
+      "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-5.8.38.tgz",
+      "dependencies": {
+        "core-js": {
+          "version": "1.2.7",
+          "from": "core-js@>=1.0.0 <2.0.0",
+          "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz"
+        }
+      }
+    },
+    "babel-template": {
+      "version": "6.22.0",
+      "from": "babel-template@>=6.7.0 <7.0.0",
+      "resolved": "https://registry.npmjs.org/babel-template/-/babel-template-6.22.0.tgz",
+      "dependencies": {
+        "babel-runtime": {
+          "version": "6.22.0",
+          "from": "babel-runtime@>=6.22.0 <7.0.0",
+          "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.22.0.tgz"
+        },
+        "lodash": {
+          "version": "4.17.4",
+          "from": "lodash@>=4.2.0 <5.0.0",
+          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz"
+        }
+      }
+    },
+    "babel-traverse": {
+      "version": "6.22.1",
+      "from": "babel-traverse@>=6.7.6 <7.0.0",
+      "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.22.1.tgz",
+      "dependencies": {
+        "babel-runtime": {
+          "version": "6.22.0",
+          "from": "babel-runtime@>=6.22.0 <7.0.0",
+          "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.22.0.tgz"
+        },
+        "lodash": {
+          "version": "4.17.4",
+          "from": "lodash@>=4.2.0 <5.0.0",
+          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz"
+        }
+      }
+    },
+    "babel-types": {
+      "version": "6.22.0",
+      "from": "babel-types@>=6.7.7 <7.0.0",
+      "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.22.0.tgz",
+      "dependencies": {
+        "babel-runtime": {
+          "version": "6.22.0",
+          "from": "babel-runtime@>=6.22.0 <7.0.0",
+          "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.22.0.tgz"
+        },
+        "lodash": {
+          "version": "4.17.4",
+          "from": "lodash@>=4.2.0 <5.0.0",
+          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz"
+        }
+      }
+    },
+    "babylon": {
+      "version": "6.15.0",
+      "from": "babylon@>=6.7.0 <7.0.0",
+      "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.15.0.tgz"
+    },
+    "back": {
+      "version": "1.0.1",
+      "from": "back@>=1.0.1 <2.0.0",
+      "resolved": "https://registry.npmjs.org/back/-/back-1.0.1.tgz"
+    },
+    "backo2": {
+      "version": "1.0.2",
+      "from": "backo2@1.0.2",
+      "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz"
+    },
+    "balanced-match": {
+      "version": "0.4.2",
+      "from": "balanced-match@>=0.4.1 <0.5.0",
+      "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.4.2.tgz"
+    },
+    "base64-arraybuffer": {
+      "version": "0.1.2",
+      "from": "base64-arraybuffer@0.1.2",
+      "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.2.tgz"
+    },
+    "base64-js": {
+      "version": "1.2.0",
+      "from": "base64-js@>=1.0.2 <2.0.0",
+      "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.2.0.tgz"
+    },
+    "base64-url": {
+      "version": "1.3.3",
+      "from": "base64-url@1.3.3",
+      "resolved": "https://registry.npmjs.org/base64-url/-/base64-url-1.3.3.tgz"
+    },
+    "base64id": {
+      "version": "0.1.0",
+      "from": "base64id@0.1.0",
+      "resolved": "https://registry.npmjs.org/base64id/-/base64id-0.1.0.tgz"
+    },
+    "base64url": {
+      "version": "1.0.6",
+      "from": "base64url@>=1.0.4 <1.1.0",
+      "resolved": "https://registry.npmjs.org/base64url/-/base64url-1.0.6.tgz"
+    },
+    "basic-auth": {
+      "version": "1.0.4",
+      "from": "basic-auth@>=1.0.3 <1.1.0",
+      "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-1.0.4.tgz"
+    },
+    "basic-auth-connect": {
+      "version": "1.0.0",
+      "from": "basic-auth-connect@>=1.0.0 <1.1.0",
+      "resolved": "https://registry.npmjs.org/basic-auth-connect/-/basic-auth-connect-1.0.0.tgz"
+    },
+    "bcrypt-pbkdf": {
+      "version": "1.0.1",
+      "from": "bcrypt-pbkdf@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz",
+      "optional": true
+    },
+    "beeper": {
+      "version": "1.1.1",
+      "from": "beeper@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/beeper/-/beeper-1.1.1.tgz"
+    },
+    "benchmark": {
+      "version": "1.0.0",
+      "from": "benchmark@1.0.0",
+      "resolved": "https://registry.npmjs.org/benchmark/-/benchmark-1.0.0.tgz"
+    },
+    "better-assert": {
+      "version": "1.0.2",
+      "from": "better-assert@>=1.0.0 <1.1.0",
+      "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz"
+    },
+    "big.js": {
+      "version": "3.1.3",
+      "from": "big.js@>=3.1.3 <4.0.0",
+      "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.1.3.tgz"
+    },
+    "binary-extensions": {
+      "version": "1.8.0",
+      "from": "binary-extensions@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.8.0.tgz"
+    },
+    "bindings": {
+      "version": "1.2.1",
+      "from": "bindings@>=1.2.0 <1.3.0",
+      "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.2.1.tgz",
+      "optional": true
+    },
+    "bl": {
+      "version": "1.1.2",
+      "from": "bl@>=1.1.2 <1.2.0",
+      "resolved": "https://registry.npmjs.org/bl/-/bl-1.1.2.tgz",
+      "dependencies": {
+        "isarray": {
+          "version": "1.0.0",
+          "from": "isarray@>=1.0.0 <1.1.0",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz"
+        },
+        "readable-stream": {
+          "version": "2.0.6",
+          "from": "readable-stream@>=2.0.5 <2.1.0",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.6.tgz"
+        }
+      }
+    },
+    "blob": {
+      "version": "0.0.4",
+      "from": "blob@0.0.4",
+      "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.4.tgz"
+    },
+    "block-stream": {
+      "version": "0.0.9",
+      "from": "block-stream@*",
+      "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz"
+    },
+    "bluebird": {
+      "version": "3.4.7",
+      "from": "bluebird@>=3.1.1 <4.0.0",
+      "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.4.7.tgz"
+    },
+    "bn.js": {
+      "version": "4.11.6",
+      "from": "bn.js@>=4.1.1 <5.0.0",
+      "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.6.tgz"
+    },
+    "body-parser": {
+      "version": "1.14.2",
+      "from": "body-parser@>=1.14.1 <1.15.0",
+      "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.14.2.tgz"
+    },
+    "boom": {
+      "version": "2.10.1",
+      "from": "boom@>=2.0.0 <3.0.0",
+      "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz"
+    },
+    "bootstrap-sass": {
+      "version": "3.3.7",
+      "from": "bootstrap-sass@>=3.3.6 <3.4.0",
+      "resolved": "https://registry.npmjs.org/bootstrap-sass/-/bootstrap-sass-3.3.7.tgz"
+    },
+    "botkit": {
+      "version": "0.1.2",
+      "from": "botkit@>=0.1.1 <0.2.0",
+      "resolved": "https://registry.npmjs.org/botkit/-/botkit-0.1.2.tgz"
+    },
+    "brace-expansion": {
+      "version": "1.1.6",
+      "from": "brace-expansion@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.6.tgz"
+    },
+    "braces": {
+      "version": "1.8.5",
+      "from": "braces@>=1.8.2 <2.0.0",
+      "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz"
+    },
+    "brorand": {
+      "version": "1.1.0",
+      "from": "brorand@>=1.0.1 <2.0.0",
+      "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz"
+    },
+    "browserify-aes": {
+      "version": "1.0.6",
+      "from": "browserify-aes@>=1.0.4 <2.0.0",
+      "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.0.6.tgz"
+    },
+    "browserify-cipher": {
+      "version": "1.0.0",
+      "from": "browserify-cipher@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.0.tgz"
+    },
+    "browserify-des": {
+      "version": "1.0.0",
+      "from": "browserify-des@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.0.tgz"
+    },
+    "browserify-rsa": {
+      "version": "4.0.1",
+      "from": "browserify-rsa@>=4.0.0 <5.0.0",
+      "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz"
+    },
+    "browserify-sign": {
+      "version": "4.0.0",
+      "from": "browserify-sign@>=4.0.0 <5.0.0",
+      "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.0.tgz"
+    },
+    "browserify-zlib": {
+      "version": "0.1.4",
+      "from": "browserify-zlib@>=0.1.4 <0.2.0",
+      "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.1.4.tgz"
+    },
+    "bson": {
+      "version": "1.0.4",
+      "from": "bson@>=1.0.4 <1.1.0",
+      "resolved": "https://registry.npmjs.org/bson/-/bson-1.0.4.tgz"
+    },
+    "buffer": {
+      "version": "4.9.1",
+      "from": "buffer@4.9.1",
+      "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz",
+      "dependencies": {
+        "isarray": {
+          "version": "1.0.0",
+          "from": "isarray@>=1.0.0 <2.0.0",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz"
+        }
+      }
+    },
+    "buffer-equal-constant-time": {
+      "version": "1.0.1",
+      "from": "buffer-equal-constant-time@>=1.0.1 <2.0.0",
+      "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz"
+    },
+    "buffer-shims": {
+      "version": "1.0.0",
+      "from": "buffer-shims@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/buffer-shims/-/buffer-shims-1.0.0.tgz"
+    },
+    "buffer-xor": {
+      "version": "1.0.3",
+      "from": "buffer-xor@>=1.0.2 <2.0.0",
+      "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz"
+    },
+    "bufferutil": {
+      "version": "1.2.1",
+      "from": "bufferutil@>=1.2.0 <1.3.0",
+      "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-1.2.1.tgz",
+      "optional": true
+    },
+    "buildmail": {
+      "version": "4.0.1",
+      "from": "buildmail@4.0.1",
+      "resolved": "https://registry.npmjs.org/buildmail/-/buildmail-4.0.1.tgz"
+    },
+    "builtin-modules": {
+      "version": "1.1.1",
+      "from": "builtin-modules@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz"
+    },
+    "builtin-status-codes": {
+      "version": "3.0.0",
+      "from": "builtin-status-codes@>=3.0.0 <4.0.0",
+      "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz"
+    },
+    "busboy": {
+      "version": "0.2.14",
+      "from": "busboy@>=0.2.11 <0.3.0",
+      "resolved": "https://registry.npmjs.org/busboy/-/busboy-0.2.14.tgz"
+    },
+    "bytes": {
+      "version": "2.2.0",
+      "from": "bytes@2.2.0",
+      "resolved": "https://registry.npmjs.org/bytes/-/bytes-2.2.0.tgz"
+    },
+    "callsite": {
+      "version": "1.0.0",
+      "from": "callsite@1.0.0",
+      "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz"
+    },
+    "camelcase": {
+      "version": "1.2.1",
+      "from": "camelcase@>=1.2.1 <2.0.0",
+      "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz"
+    },
+    "camelcase-keys": {
+      "version": "1.0.0",
+      "from": "camelcase-keys@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-1.0.0.tgz"
+    },
+    "caseless": {
+      "version": "0.11.0",
+      "from": "caseless@>=0.11.0 <0.12.0",
+      "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.11.0.tgz"
+    },
+    "center-align": {
+      "version": "0.1.3",
+      "from": "center-align@>=0.1.1 <0.2.0",
+      "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz"
+    },
+    "chai": {
+      "version": "1.10.0",
+      "from": "chai@>=1.10.0 <1.11.0",
+      "resolved": "https://registry.npmjs.org/chai/-/chai-1.10.0.tgz",
+      "dev": true
+    },
+    "chalk": {
+      "version": "1.1.3",
+      "from": "chalk@>=1.1.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz"
+    },
+    "chokidar": {
+      "version": "1.6.1",
+      "from": "chokidar@>=1.6.1 <2.0.0",
+      "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.6.1.tgz"
+    },
+    "cipher-base": {
+      "version": "1.0.3",
+      "from": "cipher-base@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.3.tgz"
+    },
+    "clean-css": {
+      "version": "3.4.24",
+      "from": "clean-css@>=3.1.9 <4.0.0",
+      "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-3.4.24.tgz",
+      "dependencies": {
+        "commander": {
+          "version": "2.8.1",
+          "from": "commander@>=2.8.0 <2.9.0",
+          "resolved": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz"
+        },
+        "source-map": {
+          "version": "0.4.4",
+          "from": "source-map@>=0.4.0 <0.5.0",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz"
+        }
+      }
+    },
+    "cli": {
+      "version": "0.6.6",
+      "from": "cli@>=0.6.0 <0.7.0",
+      "resolved": "https://registry.npmjs.org/cli/-/cli-0.6.6.tgz"
+    },
+    "cliui": {
+      "version": "3.2.0",
+      "from": "cliui@>=3.0.3 <4.0.0",
+      "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz"
+    },
+    "clone": {
+      "version": "1.0.2",
+      "from": "clone@>=1.0.2 <1.1.0",
+      "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.2.tgz"
+    },
+    "clone-buffer": {
+      "version": "1.0.0",
+      "from": "clone-buffer@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz"
+    },
+    "clone-stats": {
+      "version": "0.0.1",
+      "from": "clone-stats@>=0.0.1 <0.0.2",
+      "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz"
+    },
+    "cloneable-readable": {
+      "version": "1.0.0",
+      "from": "cloneable-readable@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.0.0.tgz"
+    },
+    "co": {
+      "version": "3.1.0",
+      "from": "co@3.1.0",
+      "resolved": "https://registry.npmjs.org/co/-/co-3.1.0.tgz"
+    },
+    "code-point-at": {
+      "version": "1.1.0",
+      "from": "code-point-at@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz"
+    },
+    "collect-all": {
+      "version": "0.2.1",
+      "from": "collect-all@>=0.2.1 <0.3.0",
+      "resolved": "https://registry.npmjs.org/collect-all/-/collect-all-0.2.1.tgz"
+    },
+    "collect-json": {
+      "version": "1.0.8",
+      "from": "collect-json@>=1.0.8 <2.0.0",
+      "resolved": "https://registry.npmjs.org/collect-json/-/collect-json-1.0.8.tgz",
+      "dependencies": {
+        "collect-all": {
+          "version": "1.0.2",
+          "from": "collect-all@>=1.0.2 <2.0.0",
+          "resolved": "https://registry.npmjs.org/collect-all/-/collect-all-1.0.2.tgz"
+        },
+        "stream-via": {
+          "version": "1.0.3",
+          "from": "stream-via@>=1.0.3 <2.0.0",
+          "resolved": "https://registry.npmjs.org/stream-via/-/stream-via-1.0.3.tgz"
+        }
+      }
+    },
+    "colors": {
+      "version": "1.1.2",
+      "from": "colors@>=1.1.2 <2.0.0",
+      "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz"
+    },
+    "column-layout": {
+      "version": "2.1.4",
+      "from": "column-layout@>=2.1.1 <3.0.0",
+      "resolved": "https://registry.npmjs.org/column-layout/-/column-layout-2.1.4.tgz"
+    },
+    "combined-stream": {
+      "version": "1.0.5",
+      "from": "combined-stream@>=1.0.5 <1.1.0",
+      "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz"
+    },
+    "command-line-args": {
+      "version": "2.1.6",
+      "from": "command-line-args@>=2.1.6 <3.0.0",
+      "resolved": "https://registry.npmjs.org/command-line-args/-/command-line-args-2.1.6.tgz"
+    },
+    "command-line-usage": {
+      "version": "2.0.5",
+      "from": "command-line-usage@>=2.0.0 <3.0.0",
+      "resolved": "https://registry.npmjs.org/command-line-usage/-/command-line-usage-2.0.5.tgz"
+    },
+    "commander": {
+      "version": "2.9.0",
+      "from": "commander@>=2.9.0 <2.10.0",
+      "resolved": "https://registry.npmjs.org/commander/-/commander-2.9.0.tgz"
+    },
+    "commondir": {
+      "version": "1.0.1",
+      "from": "commondir@>=1.0.1 <2.0.0",
+      "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz"
+    },
+    "component-bind": {
+      "version": "1.0.0",
+      "from": "component-bind@1.0.0",
+      "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz"
+    },
+    "component-emitter": {
+      "version": "1.1.2",
+      "from": "component-emitter@1.1.2",
+      "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.1.2.tgz"
+    },
+    "component-inherit": {
+      "version": "0.0.3",
+      "from": "component-inherit@0.0.3",
+      "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz"
+    },
+    "concat-map": {
+      "version": "0.0.1",
+      "from": "concat-map@0.0.1",
+      "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz"
+    },
+    "concat-stream": {
+      "version": "1.4.10",
+      "from": "concat-stream@>=1.4.7 <1.5.0",
+      "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.4.10.tgz"
+    },
+    "concat-with-sourcemaps": {
+      "version": "1.0.4",
+      "from": "concat-with-sourcemaps@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/concat-with-sourcemaps/-/concat-with-sourcemaps-1.0.4.tgz"
+    },
+    "connect-flash": {
+      "version": "0.1.1",
+      "from": "connect-flash@>=0.1.1 <0.2.0",
+      "resolved": "https://registry.npmjs.org/connect-flash/-/connect-flash-0.1.1.tgz"
+    },
+    "connect-redis": {
+      "version": "2.1.0",
+      "from": "connect-redis@>=2.1.0 <2.2.0",
+      "resolved": "https://registry.npmjs.org/connect-redis/-/connect-redis-2.1.0.tgz",
+      "dependencies": {
+        "debug": {
+          "version": "1.0.4",
+          "from": "debug@>=1.0.4 <2.0.0",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-1.0.4.tgz"
+        },
+        "ms": {
+          "version": "0.6.2",
+          "from": "ms@0.6.2",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-0.6.2.tgz"
+        },
+        "redis": {
+          "version": "0.12.1",
+          "from": "redis@>=0.12.1 <0.13.0",
+          "resolved": "https://registry.npmjs.org/redis/-/redis-0.12.1.tgz"
+        }
+      }
+    },
+    "console-browserify": {
+      "version": "1.1.0",
+      "from": "console-browserify@>=1.1.0 <1.2.0",
+      "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz"
+    },
+    "console-control-strings": {
+      "version": "1.1.0",
+      "from": "console-control-strings@>=1.1.0 <1.2.0",
+      "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz"
+    },
+    "consolidate": {
+      "version": "0.14.5",
+      "from": "consolidate@>=0.14.0 <0.15.0",
+      "resolved": "https://registry.npmjs.org/consolidate/-/consolidate-0.14.5.tgz"
+    },
+    "constants-browserify": {
+      "version": "1.0.0",
+      "from": "constants-browserify@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz"
+    },
+    "content-disposition": {
+      "version": "0.5.2",
+      "from": "content-disposition@0.5.2",
+      "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.2.tgz"
+    },
+    "content-type": {
+      "version": "1.0.2",
+      "from": "content-type@>=1.0.1 <1.1.0",
+      "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.2.tgz"
+    },
+    "convert-source-map": {
+      "version": "1.3.0",
+      "from": "convert-source-map@>=1.1.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.3.0.tgz"
+    },
+    "cookie": {
+      "version": "0.3.1",
+      "from": "cookie@0.3.1",
+      "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz"
+    },
+    "cookie-parser": {
+      "version": "1.3.5",
+      "from": "cookie-parser@>=1.3.4 <1.4.0",
+      "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.3.5.tgz",
+      "dependencies": {
+        "cookie": {
+          "version": "0.1.3",
+          "from": "cookie@0.1.3",
+          "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.1.3.tgz"
+        }
+      }
+    },
+    "cookie-signature": {
+      "version": "1.0.6",
+      "from": "cookie-signature@1.0.6",
+      "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz"
+    },
+    "cookies": {
+      "version": "0.6.1",
+      "from": "cookies@0.6.1",
+      "resolved": "https://registry.npmjs.org/cookies/-/cookies-0.6.1.tgz"
+    },
+    "core-js": {
+      "version": "2.4.1",
+      "from": "core-js@>=2.4.0 <3.0.0",
+      "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.4.1.tgz"
+    },
+    "core-util-is": {
+      "version": "1.0.2",
+      "from": "core-util-is@>=1.0.0 <1.1.0",
+      "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz"
+    },
+    "crc": {
+      "version": "3.4.1",
+      "from": "crc@3.4.1",
+      "resolved": "https://registry.npmjs.org/crc/-/crc-3.4.1.tgz"
+    },
+    "create-ecdh": {
+      "version": "4.0.0",
+      "from": "create-ecdh@>=4.0.0 <5.0.0",
+      "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.0.tgz"
+    },
+    "create-hash": {
+      "version": "1.1.2",
+      "from": "create-hash@>=1.1.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.1.2.tgz"
+    },
+    "create-hmac": {
+      "version": "1.1.4",
+      "from": "create-hmac@>=1.1.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.4.tgz"
+    },
+    "cross-spawn": {
+      "version": "3.0.1",
+      "from": "cross-spawn@>=3.0.0 <4.0.0",
+      "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-3.0.1.tgz",
+      "dependencies": {
+        "lru-cache": {
+          "version": "4.0.2",
+          "from": "lru-cache@>=4.0.1 <5.0.0",
+          "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.0.2.tgz"
+        }
+      }
+    },
+    "cryptiles": {
+      "version": "2.0.5",
+      "from": "cryptiles@>=2.0.0 <3.0.0",
+      "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz"
+    },
+    "crypto-browserify": {
+      "version": "1.0.9",
+      "from": "crypto-browserify@1.0.9",
+      "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-1.0.9.tgz"
+    },
+    "csrf": {
+      "version": "3.0.4",
+      "from": "csrf@>=3.0.3 <3.1.0",
+      "resolved": "https://registry.npmjs.org/csrf/-/csrf-3.0.4.tgz"
+    },
+    "currently-unhandled": {
+      "version": "0.4.1",
+      "from": "currently-unhandled@>=0.4.1 <0.5.0",
+      "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz"
+    },
+    "dashdash": {
+      "version": "1.14.1",
+      "from": "dashdash@>=1.12.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
+      "dependencies": {
+        "assert-plus": {
+          "version": "1.0.0",
+          "from": "assert-plus@>=1.0.0 <2.0.0",
+          "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz"
+        }
+      }
+    },
+    "date-now": {
+      "version": "0.1.4",
+      "from": "date-now@>=0.1.4 <0.2.0",
+      "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz"
+    },
+    "dateformat": {
+      "version": "2.0.0",
+      "from": "dateformat@>=2.0.0 <3.0.0",
+      "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-2.0.0.tgz"
+    },
+    "deap": {
+      "version": "1.0.0",
+      "from": "deap@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/deap/-/deap-1.0.0.tgz"
+    },
+    "debug": {
+      "version": "2.2.0",
+      "from": "debug@>=2.2.0 <2.3.0",
+      "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz"
+    },
+    "decamelize": {
+      "version": "1.2.0",
+      "from": "decamelize@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz"
+    },
+    "deep-eql": {
+      "version": "0.1.3",
+      "from": "deep-eql@0.1.3",
+      "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-0.1.3.tgz",
+      "dev": true
+    },
+    "deep-extend": {
+      "version": "0.4.1",
+      "from": "deep-extend@>=0.4.1 <0.5.0",
+      "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.4.1.tgz"
+    },
+    "deep-is": {
+      "version": "0.1.3",
+      "from": "deep-is@>=0.1.2 <0.2.0",
+      "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz"
+    },
+    "defaults": {
+      "version": "1.0.3",
+      "from": "defaults@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz"
+    },
+    "del": {
+      "version": "2.2.2",
+      "from": "del@>=2.2.0 <2.3.0",
+      "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz"
+    },
+    "delayed-stream": {
+      "version": "1.0.0",
+      "from": "delayed-stream@>=1.0.0 <1.1.0",
+      "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz"
+    },
+    "delegates": {
+      "version": "1.0.0",
+      "from": "delegates@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz"
+    },
+    "depd": {
+      "version": "1.1.0",
+      "from": "depd@>=1.1.0 <1.2.0",
+      "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.0.tgz"
+    },
+    "deprecated": {
+      "version": "0.0.1",
+      "from": "deprecated@>=0.0.1 <0.0.2",
+      "resolved": "https://registry.npmjs.org/deprecated/-/deprecated-0.0.1.tgz"
+    },
+    "des.js": {
+      "version": "1.0.0",
+      "from": "des.js@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz"
+    },
+    "destroy": {
+      "version": "1.0.4",
+      "from": "destroy@>=1.0.4 <1.1.0",
+      "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz"
+    },
+    "detect-file": {
+      "version": "0.1.0",
+      "from": "detect-file@>=0.1.0 <0.2.0",
+      "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-0.1.0.tgz"
+    },
+    "detect-indent": {
+      "version": "4.0.0",
+      "from": "detect-indent@>=4.0.0 <5.0.0",
+      "resolved": "https://registry.npmjs.org/detect-indent/-/detect-indent-4.0.0.tgz"
+    },
+    "dicer": {
+      "version": "0.2.5",
+      "from": "dicer@0.2.5",
+      "resolved": "https://registry.npmjs.org/dicer/-/dicer-0.2.5.tgz"
+    },
+    "diff": {
+      "version": "3.2.0",
+      "from": "diff@>=3.2.0 <3.3.0",
+      "resolved": "https://registry.npmjs.org/diff/-/diff-3.2.0.tgz"
+    },
+    "diff2html": {
+      "version": "2.0.12",
+      "from": "diff2html@>=2.0.12 <2.1.0",
+      "resolved": "https://registry.npmjs.org/diff2html/-/diff2html-2.0.12.tgz"
+    },
+    "diffie-hellman": {
+      "version": "5.0.2",
+      "from": "diffie-hellman@>=5.0.0 <6.0.0",
+      "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.2.tgz"
+    },
+    "dom-serializer": {
+      "version": "0.1.0",
+      "from": "dom-serializer@>=0.0.0 <1.0.0",
+      "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz",
+      "dependencies": {
+        "domelementtype": {
+          "version": "1.1.3",
+          "from": "domelementtype@>=1.1.1 <1.2.0",
+          "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz"
+        },
+        "entities": {
+          "version": "1.1.1",
+          "from": "entities@>=1.1.1 <1.2.0",
+          "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz"
+        }
+      }
+    },
+    "domain-browser": {
+      "version": "1.1.7",
+      "from": "domain-browser@>=1.1.1 <2.0.0",
+      "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.1.7.tgz"
+    },
+    "domelementtype": {
+      "version": "1.3.0",
+      "from": "domelementtype@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz"
+    },
+    "domhandler": {
+      "version": "2.3.0",
+      "from": "domhandler@>=2.3.0 <2.4.0",
+      "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz"
+    },
+    "domutils": {
+      "version": "1.5.1",
+      "from": "domutils@>=1.5.0 <1.6.0",
+      "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz"
+    },
+    "double-ended-queue": {
+      "version": "2.1.0-0",
+      "from": "double-ended-queue@>=2.1.0-0 <3.0.0",
+      "resolved": "https://registry.npmjs.org/double-ended-queue/-/double-ended-queue-2.1.0-0.tgz"
+    },
+    "duplexer2": {
+      "version": "0.0.2",
+      "from": "duplexer2@0.0.2",
+      "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz"
+    },
+    "ecc-jsbn": {
+      "version": "0.1.1",
+      "from": "ecc-jsbn@>=0.1.1 <0.2.0",
+      "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz",
+      "optional": true
+    },
+    "ecdsa-sig-formatter": {
+      "version": "1.0.9",
+      "from": "ecdsa-sig-formatter@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.9.tgz",
+      "dependencies": {
+        "base64url": {
+          "version": "2.0.0",
+          "from": "base64url@>=2.0.0 <3.0.0",
+          "resolved": "https://registry.npmjs.org/base64url/-/base64url-2.0.0.tgz"
+        }
+      }
+    },
+    "ee-first": {
+      "version": "1.1.1",
+      "from": "ee-first@1.1.1",
+      "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz"
+    },
+    "elasticsearch": {
+      "version": "12.1.3",
+      "from": "elasticsearch@>=12.1.3 <13.0.0",
+      "resolved": "https://registry.npmjs.org/elasticsearch/-/elasticsearch-12.1.3.tgz",
+      "dependencies": {
+        "lodash": {
+          "version": "4.17.4",
+          "from": "lodash@>=4.12.0 <5.0.0",
+          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz"
+        }
+      }
+    },
+    "elliptic": {
+      "version": "6.4.0",
+      "from": "elliptic@>=6.0.0 <7.0.0",
+      "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.0.tgz"
+    },
+    "emojify.js": {
+      "version": "1.1.0",
+      "from": "emojify.js@>=1.1.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/emojify.js/-/emojify.js-1.1.0.tgz"
+    },
+    "emojis-list": {
+      "version": "2.1.0",
+      "from": "emojis-list@>=2.0.0 <3.0.0",
+      "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz"
+    },
+    "encodeurl": {
+      "version": "1.0.1",
+      "from": "encodeurl@>=1.0.1 <1.1.0",
+      "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.1.tgz"
+    },
+    "encoding": {
+      "version": "0.1.12",
+      "from": "encoding@>=0.1.11 <0.2.0",
+      "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz"
+    },
+    "end-of-stream": {
+      "version": "0.1.5",
+      "from": "end-of-stream@>=0.1.5 <0.2.0",
+      "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-0.1.5.tgz",
+      "dependencies": {
+        "once": {
+          "version": "1.3.3",
+          "from": "once@>=1.3.0 <1.4.0",
+          "resolved": "https://registry.npmjs.org/once/-/once-1.3.3.tgz"
+        }
+      }
+    },
+    "engine.io": {
+      "version": "1.5.4",
+      "from": "engine.io@1.5.4",
+      "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-1.5.4.tgz",
+      "dependencies": {
+        "debug": {
+          "version": "1.0.3",
+          "from": "debug@1.0.3",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-1.0.3.tgz"
+        },
+        "ms": {
+          "version": "0.6.2",
+          "from": "ms@0.6.2",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-0.6.2.tgz"
+        },
+        "ws": {
+          "version": "0.8.0",
+          "from": "ws@0.8.0",
+          "resolved": "https://registry.npmjs.org/ws/-/ws-0.8.0.tgz"
+        }
+      }
+    },
+    "engine.io-client": {
+      "version": "1.5.4",
+      "from": "engine.io-client@1.5.4",
+      "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-1.5.4.tgz",
+      "dependencies": {
+        "debug": {
+          "version": "1.0.4",
+          "from": "debug@1.0.4",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-1.0.4.tgz"
+        },
+        "ms": {
+          "version": "0.6.2",
+          "from": "ms@0.6.2",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-0.6.2.tgz"
+        },
+        "parseuri": {
+          "version": "0.0.4",
+          "from": "parseuri@0.0.4",
+          "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.4.tgz"
+        },
+        "ws": {
+          "version": "0.8.0",
+          "from": "ws@0.8.0",
+          "resolved": "https://registry.npmjs.org/ws/-/ws-0.8.0.tgz"
+        }
+      }
+    },
+    "engine.io-parser": {
+      "version": "1.2.2",
+      "from": "engine.io-parser@1.2.2",
+      "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-1.2.2.tgz"
+    },
+    "enhanced-resolve": {
+      "version": "3.1.0",
+      "from": "enhanced-resolve@>=3.0.0 <4.0.0",
+      "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-3.1.0.tgz",
+      "dependencies": {
+        "graceful-fs": {
+          "version": "4.1.11",
+          "from": "graceful-fs@>=4.1.2 <5.0.0",
+          "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz"
+        }
+      }
+    },
+    "entities": {
+      "version": "1.0.0",
+      "from": "entities@>=1.0.0 <1.1.0",
+      "resolved": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz"
+    },
+    "errno": {
+      "version": "0.1.4",
+      "from": "errno@>=0.1.3 <0.2.0",
+      "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.4.tgz"
+    },
+    "error-ex": {
+      "version": "1.3.0",
+      "from": "error-ex@>=1.2.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.0.tgz"
+    },
+    "errorhandler": {
+      "version": "1.3.6",
+      "from": "errorhandler@>=1.3.4 <1.4.0",
+      "resolved": "https://registry.npmjs.org/errorhandler/-/errorhandler-1.3.6.tgz",
+      "dependencies": {
+        "accepts": {
+          "version": "1.2.13",
+          "from": "accepts@>=1.2.6 <1.3.0",
+          "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.2.13.tgz"
+        },
+        "escape-html": {
+          "version": "1.0.1",
+          "from": "escape-html@1.0.1",
+          "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.1.tgz"
+        },
+        "negotiator": {
+          "version": "0.5.3",
+          "from": "negotiator@0.5.3",
+          "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.5.3.tgz"
+        }
+      }
+    },
+    "es6-promise": {
+      "version": "3.2.1",
+      "from": "es6-promise@3.2.1",
+      "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.2.1.tgz"
+    },
+    "escape-html": {
+      "version": "1.0.3",
+      "from": "escape-html@>=1.0.3 <1.1.0",
+      "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz"
+    },
+    "escape-string-regexp": {
+      "version": "1.0.5",
+      "from": "escape-string-regexp@>=1.0.2 <2.0.0",
+      "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz"
+    },
+    "escodegen": {
+      "version": "1.7.1",
+      "from": "escodegen@>=1.7.0 <1.8.0",
+      "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.7.1.tgz",
+      "dependencies": {
+        "esprima": {
+          "version": "1.2.5",
+          "from": "esprima@>=1.2.2 <2.0.0",
+          "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.2.5.tgz"
+        },
+        "source-map": {
+          "version": "0.2.0",
+          "from": "source-map@>=0.2.0 <0.3.0",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.2.0.tgz",
+          "optional": true
+        }
+      }
+    },
+    "esprima": {
+      "version": "2.5.0",
+      "from": "esprima@>=2.5.0 <2.6.0",
+      "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.5.0.tgz"
+    },
+    "estraverse": {
+      "version": "1.9.3",
+      "from": "estraverse@>=1.9.1 <2.0.0",
+      "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-1.9.3.tgz"
+    },
+    "esutils": {
+      "version": "2.0.2",
+      "from": "esutils@>=2.0.2 <3.0.0",
+      "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz"
+    },
+    "etag": {
+      "version": "1.7.0",
+      "from": "etag@>=1.7.0 <1.8.0",
+      "resolved": "https://registry.npmjs.org/etag/-/etag-1.7.0.tgz"
+    },
+    "events": {
+      "version": "1.1.1",
+      "from": "events@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz"
+    },
+    "evp_bytestokey": {
+      "version": "1.0.0",
+      "from": "evp_bytestokey@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.0.tgz"
+    },
+    "exit": {
+      "version": "0.1.2",
+      "from": "exit@0.1.2",
+      "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz"
+    },
+    "expand-brackets": {
+      "version": "0.1.5",
+      "from": "expand-brackets@>=0.1.4 <0.2.0",
+      "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz"
+    },
+    "expand-range": {
+      "version": "1.8.2",
+      "from": "expand-range@>=1.8.1 <2.0.0",
+      "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz"
+    },
+    "expand-tilde": {
+      "version": "1.2.2",
+      "from": "expand-tilde@>=1.2.2 <2.0.0",
+      "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-1.2.2.tgz"
+    },
+    "express": {
+      "version": "4.14.1",
+      "from": "express@>=4.14.0 <4.15.0",
+      "resolved": "https://registry.npmjs.org/express/-/express-4.14.1.tgz",
+      "dependencies": {
+        "qs": {
+          "version": "6.2.0",
+          "from": "qs@6.2.0",
+          "resolved": "https://registry.npmjs.org/qs/-/qs-6.2.0.tgz"
+        }
+      }
+    },
+    "express-form": {
+      "version": "0.12.6",
+      "from": "express-form@>=0.12.0 <0.13.0",
+      "resolved": "https://registry.npmjs.org/express-form/-/express-form-0.12.6.tgz",
+      "dependencies": {
+        "async": {
+          "version": "0.9.2",
+          "from": "async@>=0.9.0 <0.10.0",
+          "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz"
+        }
+      }
+    },
+    "express-session": {
+      "version": "1.14.2",
+      "from": "express-session@>=1.14.0 <1.15.0",
+      "resolved": "https://registry.npmjs.org/express-session/-/express-session-1.14.2.tgz"
+    },
+    "extend": {
+      "version": "3.0.0",
+      "from": "extend@>=3.0.0 <4.0.0",
+      "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.0.tgz"
+    },
+    "extglob": {
+      "version": "0.3.2",
+      "from": "extglob@>=0.3.1 <0.4.0",
+      "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz"
+    },
+    "extsprintf": {
+      "version": "1.0.2",
+      "from": "extsprintf@1.0.2",
+      "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.0.2.tgz"
+    },
+    "fancy-log": {
+      "version": "1.3.0",
+      "from": "fancy-log@>=1.1.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.0.tgz"
+    },
+    "fast-levenshtein": {
+      "version": "1.0.7",
+      "from": "fast-levenshtein@>=1.0.0 <1.1.0",
+      "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-1.0.7.tgz"
+    },
+    "fbjs": {
+      "version": "0.8.9",
+      "from": "fbjs@>=0.8.0 <0.9.0",
+      "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.9.tgz",
+      "dependencies": {
+        "core-js": {
+          "version": "1.2.7",
+          "from": "core-js@>=1.0.0 <2.0.0",
+          "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz"
+        }
+      }
+    },
+    "feature-detect-es6": {
+      "version": "1.3.1",
+      "from": "feature-detect-es6@>=1.2.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/feature-detect-es6/-/feature-detect-es6-1.3.1.tgz"
+    },
+    "filename-regex": {
+      "version": "2.0.0",
+      "from": "filename-regex@>=2.0.0 <3.0.0",
+      "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.0.tgz"
+    },
+    "fileset": {
+      "version": "0.2.1",
+      "from": "fileset@>=0.2.0 <0.3.0",
+      "resolved": "https://registry.npmjs.org/fileset/-/fileset-0.2.1.tgz",
+      "dependencies": {
+        "glob": {
+          "version": "5.0.15",
+          "from": "glob@>=5.0.0 <6.0.0",
+          "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz"
+        }
+      }
+    },
+    "filesize": {
+      "version": "2.0.4",
+      "from": "filesize@>=2.0.0 <2.1.0",
+      "resolved": "https://registry.npmjs.org/filesize/-/filesize-2.0.4.tgz"
+    },
+    "fill-range": {
+      "version": "2.2.3",
+      "from": "fill-range@>=2.1.0 <3.0.0",
+      "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz"
+    },
+    "finalhandler": {
+      "version": "0.5.1",
+      "from": "finalhandler@0.5.1",
+      "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-0.5.1.tgz"
+    },
+    "find-cache-dir": {
+      "version": "0.1.1",
+      "from": "find-cache-dir@>=0.1.1 <0.2.0",
+      "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-0.1.1.tgz"
+    },
+    "find-index": {
+      "version": "0.1.1",
+      "from": "find-index@>=0.1.1 <0.2.0",
+      "resolved": "https://registry.npmjs.org/find-index/-/find-index-0.1.1.tgz"
+    },
+    "find-replace": {
+      "version": "1.0.3",
+      "from": "find-replace@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/find-replace/-/find-replace-1.0.3.tgz",
+      "dependencies": {
+        "test-value": {
+          "version": "2.1.0",
+          "from": "test-value@>=2.1.0 <3.0.0",
+          "resolved": "https://registry.npmjs.org/test-value/-/test-value-2.1.0.tgz"
+        }
+      }
+    },
+    "find-up": {
+      "version": "1.1.2",
+      "from": "find-up@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz",
+      "dependencies": {
+        "path-exists": {
+          "version": "2.1.0",
+          "from": "path-exists@>=2.0.0 <3.0.0",
+          "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz"
+        }
+      }
+    },
+    "findup-sync": {
+      "version": "0.4.3",
+      "from": "findup-sync@>=0.4.2 <0.5.0",
+      "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.4.3.tgz"
+    },
+    "fined": {
+      "version": "1.0.2",
+      "from": "fined@>=1.0.1 <2.0.0",
+      "resolved": "https://registry.npmjs.org/fined/-/fined-1.0.2.tgz"
+    },
+    "first-chunk-stream": {
+      "version": "1.0.0",
+      "from": "first-chunk-stream@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/first-chunk-stream/-/first-chunk-stream-1.0.0.tgz"
+    },
+    "flagged-respawn": {
+      "version": "0.3.2",
+      "from": "flagged-respawn@>=0.3.2 <0.4.0",
+      "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-0.3.2.tgz"
+    },
+    "follow-redirects": {
+      "version": "1.0.0",
+      "from": "follow-redirects@1.0.0",
+      "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.0.0.tgz"
+    },
+    "font-awesome": {
+      "version": "4.7.0",
+      "from": "font-awesome@>=4.7.0 <4.8.0",
+      "resolved": "https://registry.npmjs.org/font-awesome/-/font-awesome-4.7.0.tgz"
+    },
+    "for-in": {
+      "version": "0.1.6",
+      "from": "for-in@>=0.1.5 <0.2.0",
+      "resolved": "https://registry.npmjs.org/for-in/-/for-in-0.1.6.tgz"
+    },
+    "for-own": {
+      "version": "0.1.4",
+      "from": "for-own@>=0.1.4 <0.2.0",
+      "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.4.tgz"
+    },
+    "forever-agent": {
+      "version": "0.6.1",
+      "from": "forever-agent@>=0.6.1 <0.7.0",
+      "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz"
+    },
+    "form-data": {
+      "version": "2.1.2",
+      "from": "form-data@>=2.1.1 <2.2.0",
+      "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.2.tgz"
+    },
+    "formatio": {
+      "version": "1.1.1",
+      "from": "formatio@1.1.1",
+      "resolved": "https://registry.npmjs.org/formatio/-/formatio-1.1.1.tgz",
+      "dev": true
+    },
+    "forwarded": {
+      "version": "0.1.0",
+      "from": "forwarded@>=0.1.0 <0.2.0",
+      "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.1.0.tgz"
+    },
+    "fresh": {
+      "version": "0.3.0",
+      "from": "fresh@0.3.0",
+      "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.3.0.tgz"
+    },
+    "fs-exists-sync": {
+      "version": "0.1.0",
+      "from": "fs-exists-sync@>=0.1.0 <0.2.0",
+      "resolved": "https://registry.npmjs.org/fs-exists-sync/-/fs-exists-sync-0.1.0.tgz"
+    },
+    "fs-extra": {
+      "version": "0.30.0",
+      "from": "fs-extra@>=0.30.0 <0.31.0",
+      "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-0.30.0.tgz",
+      "dependencies": {
+        "graceful-fs": {
+          "version": "4.1.11",
+          "from": "graceful-fs@^4.1.2",
+          "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz"
+        }
+      }
+    },
+    "fs.realpath": {
+      "version": "1.0.0",
+      "from": "fs.realpath@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz"
+    },
+    "fstream": {
+      "version": "1.0.10",
+      "from": "fstream@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.10.tgz",
+      "dependencies": {
+        "graceful-fs": {
+          "version": "4.1.11",
+          "from": "graceful-fs@>=4.1.2 <5.0.0",
+          "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz"
+        }
+      }
+    },
+    "gauge": {
+      "version": "2.7.2",
+      "from": "gauge@>=2.7.1 <2.8.0",
+      "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.2.tgz",
+      "dependencies": {
+        "supports-color": {
+          "version": "0.2.0",
+          "from": "supports-color@>=0.2.0 <0.3.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-0.2.0.tgz"
+        }
+      }
+    },
+    "gaze": {
+      "version": "0.5.2",
+      "from": "gaze@>=0.5.1 <0.6.0",
+      "resolved": "https://registry.npmjs.org/gaze/-/gaze-0.5.2.tgz"
+    },
+    "generate-function": {
+      "version": "2.0.0",
+      "from": "generate-function@>=2.0.0 <3.0.0",
+      "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.0.0.tgz"
+    },
+    "generate-object-property": {
+      "version": "1.2.0",
+      "from": "generate-object-property@>=1.1.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/generate-object-property/-/generate-object-property-1.2.0.tgz"
+    },
+    "get-caller-file": {
+      "version": "1.0.2",
+      "from": "get-caller-file@>=1.0.1 <2.0.0",
+      "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz"
+    },
+    "get-stdin": {
+      "version": "4.0.1",
+      "from": "get-stdin@>=4.0.1 <5.0.0",
+      "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz"
+    },
+    "getpass": {
+      "version": "0.1.6",
+      "from": "getpass@>=0.1.1 <0.2.0",
+      "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.6.tgz",
+      "dependencies": {
+        "assert-plus": {
+          "version": "1.0.0",
+          "from": "assert-plus@>=1.0.0 <2.0.0",
+          "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz"
+        }
+      }
+    },
+    "glob": {
+      "version": "3.2.11",
+      "from": "glob@>=3.2.1 <3.3.0",
+      "resolved": "https://registry.npmjs.org/glob/-/glob-3.2.11.tgz",
+      "dependencies": {
+        "minimatch": {
+          "version": "0.3.0",
+          "from": "minimatch@>=0.3.0 <0.4.0",
+          "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz"
+        }
+      }
+    },
+    "glob-base": {
+      "version": "0.3.0",
+      "from": "glob-base@>=0.3.0 <0.4.0",
+      "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz"
+    },
+    "glob-parent": {
+      "version": "2.0.0",
+      "from": "glob-parent@>=2.0.0 <3.0.0",
+      "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz"
+    },
+    "glob-stream": {
+      "version": "3.1.18",
+      "from": "glob-stream@>=3.1.5 <4.0.0",
+      "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-3.1.18.tgz",
+      "dependencies": {
+        "glob": {
+          "version": "4.5.3",
+          "from": "glob@>=4.3.1 <5.0.0",
+          "resolved": "https://registry.npmjs.org/glob/-/glob-4.5.3.tgz"
+        },
+        "readable-stream": {
+          "version": "1.0.34",
+          "from": "readable-stream@>=1.0.33-1 <1.1.0-0",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz"
+        },
+        "through2": {
+          "version": "0.6.5",
+          "from": "through2@>=0.6.1 <0.7.0",
+          "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz"
+        }
+      }
+    },
+    "glob-watcher": {
+      "version": "0.0.6",
+      "from": "glob-watcher@>=0.0.6 <0.0.7",
+      "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-0.0.6.tgz"
+    },
+    "glob2base": {
+      "version": "0.0.12",
+      "from": "glob2base@>=0.0.12 <0.0.13",
+      "resolved": "https://registry.npmjs.org/glob2base/-/glob2base-0.0.12.tgz"
+    },
+    "global": {
+      "version": "2.0.1",
+      "from": "https://github.com/component/global/archive/v2.0.1.tar.gz",
+      "resolved": "https://github.com/component/global/archive/v2.0.1.tar.gz"
+    },
+    "global-modules": {
+      "version": "0.2.3",
+      "from": "global-modules@>=0.2.3 <0.3.0",
+      "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-0.2.3.tgz"
+    },
+    "global-prefix": {
+      "version": "0.1.5",
+      "from": "global-prefix@>=0.1.4 <0.2.0",
+      "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-0.1.5.tgz"
+    },
+    "globals": {
+      "version": "9.14.0",
+      "from": "globals@>=9.0.0 <10.0.0",
+      "resolved": "https://registry.npmjs.org/globals/-/globals-9.14.0.tgz"
+    },
+    "globby": {
+      "version": "5.0.0",
+      "from": "globby@>=5.0.0 <6.0.0",
+      "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz",
+      "dependencies": {
+        "glob": {
+          "version": "7.1.1",
+          "from": "glob@>=7.0.3 <8.0.0",
+          "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz"
+        },
+        "minimatch": {
+          "version": "3.0.3",
+          "from": "minimatch@>=3.0.2 <4.0.0",
+          "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.3.tgz"
+        }
+      }
+    },
+    "globule": {
+      "version": "0.1.0",
+      "from": "globule@>=0.1.0 <0.2.0",
+      "resolved": "https://registry.npmjs.org/globule/-/globule-0.1.0.tgz",
+      "dependencies": {
+        "glob": {
+          "version": "3.1.21",
+          "from": "glob@>=3.1.21 <3.2.0",
+          "resolved": "https://registry.npmjs.org/glob/-/glob-3.1.21.tgz"
+        },
+        "graceful-fs": {
+          "version": "1.2.3",
+          "from": "graceful-fs@>=1.2.0 <1.3.0",
+          "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.2.3.tgz"
+        },
+        "inherits": {
+          "version": "1.0.2",
+          "from": "inherits@>=1.0.0 <2.0.0",
+          "resolved": "https://registry.npmjs.org/inherits/-/inherits-1.0.2.tgz"
+        },
+        "lodash": {
+          "version": "1.0.2",
+          "from": "lodash@>=1.0.1 <1.1.0",
+          "resolved": "https://registry.npmjs.org/lodash/-/lodash-1.0.2.tgz"
+        },
+        "minimatch": {
+          "version": "0.2.14",
+          "from": "minimatch@>=0.2.11 <0.3.0",
+          "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz"
+        }
+      }
+    },
+    "glogg": {
+      "version": "1.0.0",
+      "from": "glogg@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.0.tgz"
+    },
+    "google-auth-library": {
+      "version": "0.9.10",
+      "from": "google-auth-library@>=0.9.7 <0.10.0",
+      "resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-0.9.10.tgz",
+      "dependencies": {
+        "async": {
+          "version": "1.4.2",
+          "from": "async@>=1.4.2 <1.5.0",
+          "resolved": "https://registry.npmjs.org/async/-/async-1.4.2.tgz"
+        },
+        "form-data": {
+          "version": "1.0.1",
+          "from": "form-data@>=1.0.0-rc4 <1.1.0",
+          "resolved": "https://registry.npmjs.org/form-data/-/form-data-1.0.1.tgz",
+          "dependencies": {
+            "async": {
+              "version": "2.1.4",
+              "from": "async@>=2.0.1 <3.0.0",
+              "resolved": "https://registry.npmjs.org/async/-/async-2.1.4.tgz"
+            }
+          }
+        },
+        "lodash": {
+          "version": "4.17.4",
+          "from": "lodash@>=4.14.0 <5.0.0",
+          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz"
+        },
+        "qs": {
+          "version": "6.2.1",
+          "from": "qs@>=6.2.0 <6.3.0",
+          "resolved": "https://registry.npmjs.org/qs/-/qs-6.2.1.tgz"
+        },
+        "request": {
+          "version": "2.74.0",
+          "from": "request@>=2.74.0 <2.75.0",
+          "resolved": "https://registry.npmjs.org/request/-/request-2.74.0.tgz"
+        },
+        "string-template": {
+          "version": "0.2.1",
+          "from": "string-template@>=0.2.0 <0.3.0",
+          "resolved": "https://registry.npmjs.org/string-template/-/string-template-0.2.1.tgz"
+        }
+      }
+    },
+    "google-p12-pem": {
+      "version": "0.1.1",
+      "from": "google-p12-pem@>=0.1.0 <0.2.0",
+      "resolved": "https://registry.npmjs.org/google-p12-pem/-/google-p12-pem-0.1.1.tgz"
+    },
+    "googleapis": {
+      "version": "12.3.0",
+      "from": "googleapis@12.3.0",
+      "resolved": "https://registry.npmjs.org/googleapis/-/googleapis-12.3.0.tgz",
+      "dependencies": {
+        "async": {
+          "version": "2.0.1",
+          "from": "async@>=2.0.1 <2.1.0",
+          "resolved": "https://registry.npmjs.org/async/-/async-2.0.1.tgz"
+        },
+        "lodash": {
+          "version": "4.17.4",
+          "from": "lodash@>=4.8.0 <5.0.0",
+          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz"
+        }
+      }
+    },
+    "graceful-fs": {
+      "version": "3.0.11",
+      "from": "graceful-fs@>=3.0.0 <4.0.0",
+      "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.11.tgz"
+    },
+    "graceful-readlink": {
+      "version": "1.0.1",
+      "from": "graceful-readlink@>=1.0.0",
+      "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz"
+    },
+    "growl": {
+      "version": "1.9.2",
+      "from": "growl@1.9.2",
+      "resolved": "https://registry.npmjs.org/growl/-/growl-1.9.2.tgz"
+    },
+    "gtoken": {
+      "version": "1.2.1",
+      "from": "gtoken@>=1.1.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/gtoken/-/gtoken-1.2.1.tgz"
+    },
+    "gulp": {
+      "version": "3.9.1",
+      "from": "gulp@>=3.9.0 <3.10.0",
+      "resolved": "https://registry.npmjs.org/gulp/-/gulp-3.9.1.tgz",
+      "dependencies": {
+        "minimist": {
+          "version": "1.2.0",
+          "from": "minimist@>=1.1.0 <2.0.0",
+          "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz"
+        },
+        "semver": {
+          "version": "4.3.6",
+          "from": "semver@>=4.1.0 <5.0.0",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz"
+        }
+      }
+    },
+    "gulp-concat": {
+      "version": "2.6.1",
+      "from": "gulp-concat@>=2.6.0 <2.7.0",
+      "resolved": "https://registry.npmjs.org/gulp-concat/-/gulp-concat-2.6.1.tgz",
+      "dependencies": {
+        "clone-stats": {
+          "version": "1.0.0",
+          "from": "clone-stats@>=1.0.0 <2.0.0",
+          "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz"
+        },
+        "replace-ext": {
+          "version": "1.0.0",
+          "from": "replace-ext@>=1.0.0 <2.0.0",
+          "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz"
+        },
+        "vinyl": {
+          "version": "2.0.1",
+          "from": "vinyl@>=2.0.0 <3.0.0",
+          "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.0.1.tgz"
+        }
+      }
+    },
+    "gulp-cssmin": {
+      "version": "0.1.7",
+      "from": "gulp-cssmin@>=0.1.7 <0.2.0",
+      "resolved": "https://registry.npmjs.org/gulp-cssmin/-/gulp-cssmin-0.1.7.tgz",
+      "dependencies": {
+        "ansi-regex": {
+          "version": "0.2.1",
+          "from": "ansi-regex@>=0.2.0 <0.3.0",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-0.2.1.tgz"
+        },
+        "ansi-styles": {
+          "version": "1.1.0",
+          "from": "ansi-styles@>=1.1.0 <2.0.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.1.0.tgz"
+        },
+        "camelcase": {
+          "version": "2.1.1",
+          "from": "camelcase@>=2.0.0 <3.0.0",
+          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz"
+        },
+        "camelcase-keys": {
+          "version": "2.1.0",
+          "from": "camelcase-keys@>=2.0.0 <3.0.0",
+          "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz"
+        },
+        "chalk": {
+          "version": "0.5.1",
+          "from": "chalk@>=0.5.0 <0.6.0",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.5.1.tgz"
+        },
+        "dateformat": {
+          "version": "1.0.12",
+          "from": "dateformat@>=1.0.7-1.2.3 <2.0.0",
+          "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.12.tgz"
+        },
+        "graceful-fs": {
+          "version": "2.0.3",
+          "from": "graceful-fs@>=2.0.0 <2.1.0",
+          "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-2.0.3.tgz"
+        },
+        "gulp-rename": {
+          "version": "1.1.0",
+          "from": "gulp-rename@>=1.1.0 <1.2.0",
+          "resolved": "https://registry.npmjs.org/gulp-rename/-/gulp-rename-1.1.0.tgz"
+        },
+        "gulp-util": {
+          "version": "2.2.20",
+          "from": "gulp-util@>=2.2.0 <2.3.0",
+          "resolved": "https://registry.npmjs.org/gulp-util/-/gulp-util-2.2.20.tgz"
+        },
+        "has-ansi": {
+          "version": "0.1.0",
+          "from": "has-ansi@>=0.1.0 <0.2.0",
+          "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-0.1.0.tgz"
+        },
+        "lodash._reinterpolate": {
+          "version": "2.4.1",
+          "from": "lodash._reinterpolate@>=2.4.1 <3.0.0",
+          "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-2.4.1.tgz"
+        },
+        "lodash.escape": {
+          "version": "2.4.1",
+          "from": "lodash.escape@>=2.4.1 <2.5.0",
+          "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-2.4.1.tgz"
+        },
+        "lodash.keys": {
+          "version": "2.4.1",
+          "from": "lodash.keys@>=2.4.1 <2.5.0",
+          "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-2.4.1.tgz"
+        },
+        "lodash.template": {
+          "version": "2.4.1",
+          "from": "lodash.template@>=2.4.1 <3.0.0",
+          "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-2.4.1.tgz"
+        },
+        "lodash.templatesettings": {
+          "version": "2.4.1",
+          "from": "lodash.templatesettings@>=2.4.1 <2.5.0",
+          "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-2.4.1.tgz"
+        },
+        "meow": {
+          "version": "3.7.0",
+          "from": "meow@>=3.3.0 <4.0.0",
+          "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz",
+          "dependencies": {
+            "minimist": {
+              "version": "1.2.0",
+              "from": "minimist@>=1.1.3 <2.0.0",
+              "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz"
+            }
+          }
+        },
+        "minimist": {
+          "version": "0.2.0",
+          "from": "minimist@>=0.2.0 <0.3.0",
+          "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.2.0.tgz"
+        },
+        "readable-stream": {
+          "version": "1.0.34",
+          "from": "readable-stream@>=1.0.17 <1.1.0",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz"
+        },
+        "strip-ansi": {
+          "version": "0.3.0",
+          "from": "strip-ansi@>=0.3.0 <0.4.0",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.3.0.tgz"
+        },
+        "supports-color": {
+          "version": "0.2.0",
+          "from": "supports-color@>=0.2.0 <0.3.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-0.2.0.tgz"
+        },
+        "through2": {
+          "version": "0.5.1",
+          "from": "through2@>=0.5.0 <0.6.0",
+          "resolved": "https://registry.npmjs.org/through2/-/through2-0.5.1.tgz"
+        },
+        "vinyl": {
+          "version": "0.2.3",
+          "from": "vinyl@>=0.2.1 <0.3.0",
+          "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.2.3.tgz"
+        },
+        "xtend": {
+          "version": "3.0.0",
+          "from": "xtend@>=3.0.0 <3.1.0",
+          "resolved": "https://registry.npmjs.org/xtend/-/xtend-3.0.0.tgz"
+        }
+      }
+    },
+    "gulp-jshint": {
+      "version": "1.12.0",
+      "from": "gulp-jshint@>=1.12.0 <1.13.0",
+      "resolved": "https://registry.npmjs.org/gulp-jshint/-/gulp-jshint-1.12.0.tgz",
+      "dependencies": {
+        "readable-stream": {
+          "version": "1.0.34",
+          "from": "readable-stream@>=1.0.33-1 <1.1.0-0",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz"
+        },
+        "through2": {
+          "version": "0.6.5",
+          "from": "through2@>=0.6.1 <0.7.0",
+          "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz"
+        }
+      }
+    },
+    "gulp-rename": {
+      "version": "1.2.2",
+      "from": "gulp-rename@>=1.2.2 <1.3.0",
+      "resolved": "https://registry.npmjs.org/gulp-rename/-/gulp-rename-1.2.2.tgz"
+    },
+    "gulp-sass": {
+      "version": "3.1.0",
+      "from": "gulp-sass@>=3.1.0 <3.2.0",
+      "resolved": "https://registry.npmjs.org/gulp-sass/-/gulp-sass-3.1.0.tgz"
+    },
+    "gulp-spawn-mocha": {
+      "version": "2.2.2",
+      "from": "gulp-spawn-mocha@>=2.2.1 <2.3.0",
+      "resolved": "https://registry.npmjs.org/gulp-spawn-mocha/-/gulp-spawn-mocha-2.2.2.tgz",
+      "dependencies": {
+        "ansi-regex": {
+          "version": "0.2.1",
+          "from": "ansi-regex@>=0.2.0 <0.3.0",
+          "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-0.2.1.tgz"
+        },
+        "ansi-styles": {
+          "version": "1.1.0",
+          "from": "ansi-styles@>=1.1.0 <2.0.0",
+          "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-1.1.0.tgz"
+        },
+        "camelcase": {
+          "version": "2.1.1",
+          "from": "camelcase@>=2.0.0 <3.0.0",
+          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz"
+        },
+        "camelcase-keys": {
+          "version": "2.1.0",
+          "from": "camelcase-keys@>=2.0.0 <3.0.0",
+          "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz"
+        },
+        "chalk": {
+          "version": "0.5.1",
+          "from": "chalk@>=0.5.0 <0.6.0",
+          "resolved": "https://registry.npmjs.org/chalk/-/chalk-0.5.1.tgz"
+        },
+        "commander": {
+          "version": "2.3.0",
+          "from": "commander@2.3.0",
+          "resolved": "https://registry.npmjs.org/commander/-/commander-2.3.0.tgz"
+        },
+        "dateformat": {
+          "version": "1.0.12",
+          "from": "dateformat@>=1.0.7-1.2.3 <2.0.0",
+          "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.12.tgz"
+        },
+        "diff": {
+          "version": "1.4.0",
+          "from": "diff@1.4.0",
+          "resolved": "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz"
+        },
+        "gulp-util": {
+          "version": "2.2.20",
+          "from": "gulp-util@>=2.2.10 <2.3.0",
+          "resolved": "https://registry.npmjs.org/gulp-util/-/gulp-util-2.2.20.tgz"
+        },
+        "has-ansi": {
+          "version": "0.1.0",
+          "from": "has-ansi@>=0.1.0 <0.2.0",
+          "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-0.1.0.tgz"
+        },
+        "lodash._reinterpolate": {
+          "version": "2.4.1",
+          "from": "lodash._reinterpolate@>=2.4.1 <3.0.0",
+          "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-2.4.1.tgz"
+        },
+        "lodash.escape": {
+          "version": "2.4.1",
+          "from": "lodash.escape@>=2.4.1 <2.5.0",
+          "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-2.4.1.tgz"
+        },
+        "lodash.keys": {
+          "version": "2.4.1",
+          "from": "lodash.keys@>=2.4.1 <2.5.0",
+          "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-2.4.1.tgz"
+        },
+        "lodash.template": {
+          "version": "2.4.1",
+          "from": "lodash.template@>=2.4.1 <3.0.0",
+          "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-2.4.1.tgz"
+        },
+        "lodash.templatesettings": {
+          "version": "2.4.1",
+          "from": "lodash.templatesettings@>=2.4.1 <2.5.0",
+          "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-2.4.1.tgz"
+        },
+        "meow": {
+          "version": "3.7.0",
+          "from": "meow@>=3.3.0 <4.0.0",
+          "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz",
+          "dependencies": {
+            "minimist": {
+              "version": "1.2.0",
+              "from": "minimist@>=1.1.3 <2.0.0",
+              "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz"
+            }
+          }
+        },
+        "minimist": {
+          "version": "0.2.0",
+          "from": "minimist@>=0.2.0 <0.3.0",
+          "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.2.0.tgz"
+        },
+        "mocha": {
+          "version": "2.5.3",
+          "from": "mocha@>=2.0.0 <3.0.0",
+          "resolved": "https://registry.npmjs.org/mocha/-/mocha-2.5.3.tgz",
+          "dependencies": {
+            "escape-string-regexp": {
+              "version": "1.0.2",
+              "from": "escape-string-regexp@1.0.2",
+              "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz"
+            },
+            "supports-color": {
+              "version": "1.2.0",
+              "from": "supports-color@1.2.0",
+              "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-1.2.0.tgz"
+            }
+          }
+        },
+        "readable-stream": {
+          "version": "1.0.34",
+          "from": "readable-stream@>=1.0.17 <1.1.0",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz"
+        },
+        "strip-ansi": {
+          "version": "0.3.0",
+          "from": "strip-ansi@>=0.3.0 <0.4.0",
+          "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-0.3.0.tgz"
+        },
+        "supports-color": {
+          "version": "0.2.0",
+          "from": "supports-color@>=0.2.0 <0.3.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-0.2.0.tgz"
+        },
+        "through2": {
+          "version": "0.5.1",
+          "from": "through2@>=0.5.0 <0.6.0",
+          "resolved": "https://registry.npmjs.org/through2/-/through2-0.5.1.tgz"
+        },
+        "vinyl": {
+          "version": "0.2.3",
+          "from": "vinyl@>=0.2.1 <0.3.0",
+          "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.2.3.tgz"
+        },
+        "xtend": {
+          "version": "3.0.0",
+          "from": "xtend@>=3.0.0 <3.1.0",
+          "resolved": "https://registry.npmjs.org/xtend/-/xtend-3.0.0.tgz"
+        }
+      }
+    },
+    "gulp-uglify": {
+      "version": "1.4.2",
+      "from": "gulp-uglify@>=1.4.2 <1.5.0",
+      "resolved": "https://registry.npmjs.org/gulp-uglify/-/gulp-uglify-1.4.2.tgz",
+      "dependencies": {
+        "async": {
+          "version": "0.2.10",
+          "from": "async@>=0.2.6 <0.3.0",
+          "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz"
+        },
+        "uglify-js": {
+          "version": "2.5.0",
+          "from": "uglify-js@2.5.0",
+          "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.5.0.tgz"
+        },
+        "window-size": {
+          "version": "0.1.0",
+          "from": "window-size@0.1.0",
+          "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz"
+        },
+        "wordwrap": {
+          "version": "0.0.2",
+          "from": "wordwrap@0.0.2",
+          "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz"
+        },
+        "yargs": {
+          "version": "3.5.4",
+          "from": "yargs@>=3.5.4 <3.6.0",
+          "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.5.4.tgz"
+        }
+      }
+    },
+    "gulp-util": {
+      "version": "3.0.8",
+      "from": "gulp-util@>=3.0.0 <4.0.0",
+      "resolved": "https://registry.npmjs.org/gulp-util/-/gulp-util-3.0.8.tgz",
+      "dependencies": {
+        "minimist": {
+          "version": "1.2.0",
+          "from": "minimist@>=1.1.0 <2.0.0",
+          "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz"
+        },
+        "object-assign": {
+          "version": "3.0.0",
+          "from": "object-assign@>=3.0.0 <4.0.0",
+          "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz"
+        }
+      }
+    },
+    "gulp-watch": {
+      "version": "4.3.11",
+      "from": "gulp-watch@>=4.3.5 <4.4.0",
+      "resolved": "https://registry.npmjs.org/gulp-watch/-/gulp-watch-4.3.11.tgz",
+      "dependencies": {
+        "glob-parent": {
+          "version": "3.1.0",
+          "from": "glob-parent@>=3.0.1 <4.0.0",
+          "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz"
+        },
+        "is-extglob": {
+          "version": "2.1.1",
+          "from": "is-extglob@>=2.1.0 <3.0.0",
+          "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz"
+        },
+        "is-glob": {
+          "version": "3.1.0",
+          "from": "is-glob@>=3.1.0 <4.0.0",
+          "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz"
+        },
+        "isarray": {
+          "version": "1.0.0",
+          "from": "isarray@>=1.0.0 <1.1.0",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz"
+        },
+        "readable-stream": {
+          "version": "2.2.2",
+          "from": "readable-stream@>=2.2.2 <3.0.0",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.2.tgz"
+        },
+        "vinyl": {
+          "version": "1.2.0",
+          "from": "vinyl@>=1.2.0 <2.0.0",
+          "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-1.2.0.tgz"
+        }
+      }
+    },
+    "gulplog": {
+      "version": "1.0.0",
+      "from": "gulplog@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz"
+    },
+    "handlebars": {
+      "version": "4.0.6",
+      "from": "handlebars@>=4.0.1 <5.0.0",
+      "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.0.6.tgz",
+      "dependencies": {
+        "source-map": {
+          "version": "0.4.4",
+          "from": "source-map@>=0.4.4 <0.5.0",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz"
+        }
+      }
+    },
+    "har-validator": {
+      "version": "2.0.6",
+      "from": "har-validator@>=2.0.6 <2.1.0",
+      "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-2.0.6.tgz"
+    },
+    "has-ansi": {
+      "version": "2.0.0",
+      "from": "has-ansi@>=2.0.0 <3.0.0",
+      "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz"
+    },
+    "has-binary": {
+      "version": "0.1.6",
+      "from": "has-binary@0.1.6",
+      "resolved": "https://registry.npmjs.org/has-binary/-/has-binary-0.1.6.tgz"
+    },
+    "has-binary-data": {
+      "version": "0.1.3",
+      "from": "has-binary-data@0.1.3",
+      "resolved": "https://registry.npmjs.org/has-binary-data/-/has-binary-data-0.1.3.tgz"
+    },
+    "has-cors": {
+      "version": "1.0.3",
+      "from": "has-cors@1.0.3",
+      "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.0.3.tgz"
+    },
+    "has-flag": {
+      "version": "1.0.0",
+      "from": "has-flag@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz"
+    },
+    "has-gulplog": {
+      "version": "0.1.0",
+      "from": "has-gulplog@>=0.1.0 <0.2.0",
+      "resolved": "https://registry.npmjs.org/has-gulplog/-/has-gulplog-0.1.0.tgz"
+    },
+    "has-unicode": {
+      "version": "2.0.1",
+      "from": "has-unicode@>=2.0.0 <3.0.0",
+      "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz"
+    },
+    "hash.js": {
+      "version": "1.0.3",
+      "from": "hash.js@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.0.3.tgz"
+    },
+    "hawk": {
+      "version": "3.1.3",
+      "from": "hawk@>=3.1.3 <3.2.0",
+      "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz"
+    },
+    "highlight.js": {
+      "version": "9.9.0",
+      "from": "highlight.js@>=9.9.0 <9.10.0",
+      "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.9.0.tgz"
+    },
+    "hmac-drbg": {
+      "version": "1.0.0",
+      "from": "hmac-drbg@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.0.tgz"
+    },
+    "hoek": {
+      "version": "2.16.3",
+      "from": "hoek@>=2.0.0 <3.0.0",
+      "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz"
+    },
+    "hogan.js": {
+      "version": "3.0.2",
+      "from": "hogan.js@>=3.0.2 <4.0.0",
+      "resolved": "https://registry.npmjs.org/hogan.js/-/hogan.js-3.0.2.tgz",
+      "dependencies": {
+        "mkdirp": {
+          "version": "0.3.0",
+          "from": "mkdirp@0.3.0",
+          "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz"
+        }
+      }
+    },
+    "home-or-tmp": {
+      "version": "2.0.0",
+      "from": "home-or-tmp@>=2.0.0 <3.0.0",
+      "resolved": "https://registry.npmjs.org/home-or-tmp/-/home-or-tmp-2.0.0.tgz"
+    },
+    "homedir-polyfill": {
+      "version": "1.0.1",
+      "from": "homedir-polyfill@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.1.tgz"
+    },
+    "hooks-fixed": {
+      "version": "1.2.0",
+      "from": "hooks-fixed@1.2.0",
+      "resolved": "https://registry.npmjs.org/hooks-fixed/-/hooks-fixed-1.2.0.tgz"
+    },
+    "hosted-git-info": {
+      "version": "2.1.5",
+      "from": "hosted-git-info@>=2.1.4 <3.0.0",
+      "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.1.5.tgz"
+    },
+    "htmlparser2": {
+      "version": "3.8.3",
+      "from": "htmlparser2@>=3.8.0 <3.9.0",
+      "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz"
+    },
+    "http-errors": {
+      "version": "1.3.1",
+      "from": "http-errors@>=1.3.1 <1.4.0",
+      "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.3.1.tgz"
+    },
+    "http-signature": {
+      "version": "1.1.1",
+      "from": "http-signature@>=1.1.0 <1.2.0",
+      "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz"
+    },
+    "httpntlm": {
+      "version": "1.6.1",
+      "from": "httpntlm@1.6.1",
+      "resolved": "https://registry.npmjs.org/httpntlm/-/httpntlm-1.6.1.tgz"
+    },
+    "httpreq": {
+      "version": "0.4.22",
+      "from": "httpreq@>=0.4.22",
+      "resolved": "https://registry.npmjs.org/httpreq/-/httpreq-0.4.22.tgz"
+    },
+    "https-browserify": {
+      "version": "0.0.1",
+      "from": "https-browserify@0.0.1",
+      "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-0.0.1.tgz"
+    },
+    "https-proxy-agent": {
+      "version": "1.0.0",
+      "from": "https-proxy-agent@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-1.0.0.tgz"
+    },
+    "i18next": {
+      "version": "4.1.4",
+      "from": "i18next@>=4.1.0 <4.2.0",
+      "resolved": "https://registry.npmjs.org/i18next/-/i18next-4.1.4.tgz"
+    },
+    "i18next-express-middleware": {
+      "version": "1.0.2",
+      "from": "i18next-express-middleware@>=1.0.2 <1.1.0",
+      "resolved": "https://registry.npmjs.org/i18next-express-middleware/-/i18next-express-middleware-1.0.2.tgz"
+    },
+    "i18next-node-fs-backend": {
+      "version": "0.1.3",
+      "from": "i18next-node-fs-backend@>=0.1.3 <0.2.0",
+      "resolved": "https://registry.npmjs.org/i18next-node-fs-backend/-/i18next-node-fs-backend-0.1.3.tgz",
+      "dependencies": {
+        "esprima": {
+          "version": "2.7.3",
+          "from": "esprima@>=2.6.0 <3.0.0",
+          "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz"
+        },
+        "js-yaml": {
+          "version": "3.5.4",
+          "from": "js-yaml@3.5.4",
+          "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.5.4.tgz"
+        },
+        "json5": {
+          "version": "0.5.0",
+          "from": "json5@0.5.0",
+          "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.0.tgz"
+        }
+      }
+    },
+    "i18next-sprintf-postprocessor": {
+      "version": "0.2.2",
+      "from": "i18next-sprintf-postprocessor@>=0.2.2 <0.3.0",
+      "resolved": "https://registry.npmjs.org/i18next-sprintf-postprocessor/-/i18next-sprintf-postprocessor-0.2.2.tgz"
+    },
+    "iconv-lite": {
+      "version": "0.4.13",
+      "from": "iconv-lite@0.4.13",
+      "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.13.tgz"
+    },
+    "ieee754": {
+      "version": "1.1.8",
+      "from": "ieee754@>=1.1.4 <2.0.0",
+      "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.8.tgz"
+    },
+    "in-publish": {
+      "version": "2.0.0",
+      "from": "in-publish@>=2.0.0 <3.0.0",
+      "resolved": "https://registry.npmjs.org/in-publish/-/in-publish-2.0.0.tgz"
+    },
+    "indent-string": {
+      "version": "1.2.2",
+      "from": "indent-string@>=1.1.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-1.2.2.tgz",
+      "dependencies": {
+        "minimist": {
+          "version": "1.2.0",
+          "from": "minimist@>=1.1.0 <2.0.0",
+          "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz"
+        },
+        "repeating": {
+          "version": "1.1.3",
+          "from": "repeating@>=1.1.0 <2.0.0",
+          "resolved": "https://registry.npmjs.org/repeating/-/repeating-1.1.3.tgz"
+        }
+      }
+    },
+    "indexof": {
+      "version": "0.0.1",
+      "from": "indexof@0.0.1",
+      "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz"
+    },
+    "inflight": {
+      "version": "1.0.6",
+      "from": "inflight@>=1.0.4 <2.0.0",
+      "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz"
+    },
+    "inherits": {
+      "version": "2.0.3",
+      "from": "inherits@>=2.0.1 <2.1.0",
+      "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz"
+    },
+    "ini": {
+      "version": "1.3.4",
+      "from": "ini@>=1.3.4 <2.0.0",
+      "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz"
+    },
+    "inline-attachment": {
+      "version": "2.0.3",
+      "from": "git+https://github.com/Rovak/InlineAttachment.git#2.0.3",
+      "resolved": "git+https://github.com/Rovak/InlineAttachment.git#3aeb84a42976e88eaa030ed94f1cfd11b018b134"
+    },
+    "interpret": {
+      "version": "1.0.1",
+      "from": "interpret@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.0.1.tgz"
+    },
+    "invariant": {
+      "version": "2.2.2",
+      "from": "invariant@>=2.2.0 <3.0.0",
+      "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.2.tgz"
+    },
+    "invert-kv": {
+      "version": "1.0.0",
+      "from": "invert-kv@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz"
+    },
+    "ip": {
+      "version": "1.1.4",
+      "from": "ip@>=1.1.2 <2.0.0",
+      "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.4.tgz"
+    },
+    "ipaddr.js": {
+      "version": "1.2.0",
+      "from": "ipaddr.js@1.2.0",
+      "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.2.0.tgz"
+    },
+    "irregular-plurals": {
+      "version": "1.2.0",
+      "from": "irregular-plurals@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/irregular-plurals/-/irregular-plurals-1.2.0.tgz"
+    },
+    "is-absolute": {
+      "version": "0.2.6",
+      "from": "is-absolute@>=0.2.3 <0.3.0",
+      "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-0.2.6.tgz"
+    },
+    "is-arrayish": {
+      "version": "0.2.1",
+      "from": "is-arrayish@>=0.2.1 <0.3.0",
+      "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz"
+    },
+    "is-binary-path": {
+      "version": "1.0.1",
+      "from": "is-binary-path@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz"
+    },
+    "is-buffer": {
+      "version": "1.1.4",
+      "from": "is-buffer@>=1.0.2 <2.0.0",
+      "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.4.tgz"
+    },
+    "is-builtin-module": {
+      "version": "1.0.0",
+      "from": "is-builtin-module@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz"
+    },
+    "is-dotfile": {
+      "version": "1.0.2",
+      "from": "is-dotfile@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.2.tgz"
+    },
+    "is-equal-shallow": {
+      "version": "0.1.3",
+      "from": "is-equal-shallow@>=0.1.3 <0.2.0",
+      "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz"
+    },
+    "is-extendable": {
+      "version": "0.1.1",
+      "from": "is-extendable@>=0.1.1 <0.2.0",
+      "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz"
+    },
+    "is-extglob": {
+      "version": "1.0.0",
+      "from": "is-extglob@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz"
+    },
+    "is-finite": {
+      "version": "1.0.2",
+      "from": "is-finite@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz"
+    },
+    "is-fullwidth-code-point": {
+      "version": "1.0.0",
+      "from": "is-fullwidth-code-point@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz"
+    },
+    "is-glob": {
+      "version": "2.0.1",
+      "from": "is-glob@>=2.0.1 <3.0.0",
+      "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz"
+    },
+    "is-my-json-valid": {
+      "version": "2.15.0",
+      "from": "is-my-json-valid@>=2.12.4 <3.0.0",
+      "resolved": "https://registry.npmjs.org/is-my-json-valid/-/is-my-json-valid-2.15.0.tgz"
+    },
+    "is-number": {
+      "version": "2.1.0",
+      "from": "is-number@>=2.1.0 <3.0.0",
+      "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz"
+    },
+    "is-path-cwd": {
+      "version": "1.0.0",
+      "from": "is-path-cwd@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz"
+    },
+    "is-path-in-cwd": {
+      "version": "1.0.0",
+      "from": "is-path-in-cwd@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz"
+    },
+    "is-path-inside": {
+      "version": "1.0.0",
+      "from": "is-path-inside@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.0.tgz"
+    },
+    "is-posix-bracket": {
+      "version": "0.1.1",
+      "from": "is-posix-bracket@>=0.1.0 <0.2.0",
+      "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz"
+    },
+    "is-primitive": {
+      "version": "2.0.0",
+      "from": "is-primitive@>=2.0.0 <3.0.0",
+      "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz"
+    },
+    "is-property": {
+      "version": "1.0.2",
+      "from": "is-property@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz"
+    },
+    "is-relative": {
+      "version": "0.2.1",
+      "from": "is-relative@>=0.2.1 <0.3.0",
+      "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-0.2.1.tgz"
+    },
+    "is-stream": {
+      "version": "1.1.0",
+      "from": "is-stream@>=1.1.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz"
+    },
+    "is-typedarray": {
+      "version": "1.0.0",
+      "from": "is-typedarray@>=1.0.0 <1.1.0",
+      "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz"
+    },
+    "is-unc-path": {
+      "version": "0.1.2",
+      "from": "is-unc-path@>=0.1.1 <0.2.0",
+      "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-0.1.2.tgz"
+    },
+    "is-utf8": {
+      "version": "0.2.1",
+      "from": "is-utf8@>=0.2.0 <0.3.0",
+      "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz"
+    },
+    "is-windows": {
+      "version": "0.2.0",
+      "from": "is-windows@>=0.2.0 <0.3.0",
+      "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-0.2.0.tgz"
+    },
+    "isarray": {
+      "version": "0.0.1",
+      "from": "isarray@0.0.1",
+      "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz"
+    },
+    "isexe": {
+      "version": "1.1.2",
+      "from": "isexe@>=1.1.1 <2.0.0",
+      "resolved": "https://registry.npmjs.org/isexe/-/isexe-1.1.2.tgz"
+    },
+    "isobject": {
+      "version": "2.1.0",
+      "from": "isobject@>=2.0.0 <3.0.0",
+      "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
+      "dependencies": {
+        "isarray": {
+          "version": "1.0.0",
+          "from": "isarray@1.0.0",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz"
+        }
+      }
+    },
+    "isomorphic-fetch": {
+      "version": "2.2.1",
+      "from": "isomorphic-fetch@>=2.1.1 <3.0.0",
+      "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz"
+    },
+    "isstream": {
+      "version": "0.1.2",
+      "from": "isstream@>=0.1.2 <0.2.0",
+      "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz"
+    },
+    "istanbul": {
+      "version": "0.3.22",
+      "from": "istanbul@>=0.3.5 <0.4.0",
+      "resolved": "https://registry.npmjs.org/istanbul/-/istanbul-0.3.22.tgz",
+      "dependencies": {
+        "nopt": {
+          "version": "3.0.6",
+          "from": "nopt@>=3.0.0 <4.0.0",
+          "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz"
+        },
+        "resolve": {
+          "version": "1.1.7",
+          "from": "resolve@>=1.1.0 <1.2.0",
+          "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz"
+        },
+        "supports-color": {
+          "version": "3.2.3",
+          "from": "supports-color@>=3.1.0 <4.0.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz"
+        }
+      }
+    },
+    "jade": {
+      "version": "0.26.3",
+      "from": "jade@0.26.3",
+      "resolved": "https://registry.npmjs.org/jade/-/jade-0.26.3.tgz",
+      "dependencies": {
+        "commander": {
+          "version": "0.6.1",
+          "from": "commander@0.6.1",
+          "resolved": "https://registry.npmjs.org/commander/-/commander-0.6.1.tgz"
+        },
+        "mkdirp": {
+          "version": "0.3.0",
+          "from": "mkdirp@0.3.0",
+          "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz"
+        }
+      }
+    },
+    "jfs": {
+      "version": "0.2.6",
+      "from": "jfs@>=0.2.6 <0.3.0",
+      "resolved": "https://registry.npmjs.org/jfs/-/jfs-0.2.6.tgz",
+      "dependencies": {
+        "async": {
+          "version": "1.2.1",
+          "from": "async@>=1.2.1 <1.3.0",
+          "resolved": "https://registry.npmjs.org/async/-/async-1.2.1.tgz"
+        }
+      }
+    },
+    "jmespath": {
+      "version": "0.15.0",
+      "from": "jmespath@0.15.0",
+      "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz"
+    },
+    "jodid25519": {
+      "version": "1.0.2",
+      "from": "jodid25519@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/jodid25519/-/jodid25519-1.0.2.tgz",
+      "optional": true
+    },
+    "jquery": {
+      "version": "2.1.4",
+      "from": "jquery@>=2.1.4 <2.2.0",
+      "resolved": "https://registry.npmjs.org/jquery/-/jquery-2.1.4.tgz"
+    },
+    "jquery.cookie": {
+      "version": "1.4.1",
+      "from": "jquery.cookie@>=1.4.1 <1.5.0",
+      "resolved": "https://registry.npmjs.org/jquery.cookie/-/jquery.cookie-1.4.1.tgz"
+    },
+    "js-tokens": {
+      "version": "3.0.1",
+      "from": "js-tokens@>=3.0.0 <4.0.0",
+      "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.1.tgz"
+    },
+    "js-yaml": {
+      "version": "3.7.0",
+      "from": "js-yaml@>=3.0.0 <4.0.0",
+      "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.7.0.tgz",
+      "dependencies": {
+        "esprima": {
+          "version": "2.7.3",
+          "from": "esprima@>=2.6.0 <3.0.0",
+          "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.7.3.tgz"
+        }
+      }
+    },
+    "jsbn": {
+      "version": "0.1.0",
+      "from": "jsbn@>=0.1.0 <0.2.0",
+      "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.0.tgz",
+      "optional": true
+    },
+    "jsesc": {
+      "version": "1.3.0",
+      "from": "jsesc@>=1.3.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-1.3.0.tgz"
+    },
+    "jshint": {
+      "version": "2.9.4",
+      "from": "jshint@>=2.7.0 <3.0.0",
+      "resolved": "https://registry.npmjs.org/jshint/-/jshint-2.9.4.tgz",
+      "dependencies": {
+        "cli": {
+          "version": "1.0.1",
+          "from": "cli@>=1.0.0 <1.1.0",
+          "resolved": "https://registry.npmjs.org/cli/-/cli-1.0.1.tgz"
+        },
+        "glob": {
+          "version": "7.1.1",
+          "from": "glob@>=7.1.1 <8.0.0",
+          "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz"
+        },
+        "lodash": {
+          "version": "3.7.0",
+          "from": "lodash@>=3.7.0 <3.8.0",
+          "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.7.0.tgz"
+        },
+        "minimatch": {
+          "version": "3.0.3",
+          "from": "minimatch@>=3.0.2 <3.1.0",
+          "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.3.tgz"
+        }
+      }
+    },
+    "jshint-stylish": {
+      "version": "2.1.0",
+      "from": "jshint-stylish@>=2.1.0 <2.2.0",
+      "resolved": "https://registry.npmjs.org/jshint-stylish/-/jshint-stylish-2.1.0.tgz"
+    },
+    "json-loader": {
+      "version": "0.5.4",
+      "from": "json-loader@>=0.5.4 <0.6.0",
+      "resolved": "https://registry.npmjs.org/json-loader/-/json-loader-0.5.4.tgz"
+    },
+    "json-schema": {
+      "version": "0.2.3",
+      "from": "json-schema@0.2.3",
+      "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz"
+    },
+    "json-stable-stringify": {
+      "version": "1.0.1",
+      "from": "json-stable-stringify@>=1.0.1 <2.0.0",
+      "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz"
+    },
+    "json-stringify-safe": {
+      "version": "5.0.1",
+      "from": "json-stringify-safe@>=5.0.1 <5.1.0",
+      "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz"
+    },
+    "json3": {
+      "version": "3.2.6",
+      "from": "json3@3.2.6",
+      "resolved": "https://registry.npmjs.org/json3/-/json3-3.2.6.tgz"
+    },
+    "json5": {
+      "version": "0.4.0",
+      "from": "json5@>=0.4.0 <0.5.0",
+      "resolved": "https://registry.npmjs.org/json5/-/json5-0.4.0.tgz"
+    },
+    "jsonfile": {
+      "version": "2.4.0",
+      "from": "jsonfile@>=2.1.0 <3.0.0",
+      "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz",
+      "dependencies": {
+        "graceful-fs": {
+          "version": "4.1.11",
+          "from": "graceful-fs@^4.1.6",
+          "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
+          "optional": true
+        }
+      }
+    },
+    "jsonify": {
+      "version": "0.0.0",
+      "from": "jsonify@>=0.0.0 <0.1.0",
+      "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz"
+    },
+    "jsonpointer": {
+      "version": "4.0.1",
+      "from": "jsonpointer@>=4.0.0 <5.0.0",
+      "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-4.0.1.tgz"
+    },
+    "jsprim": {
+      "version": "1.3.1",
+      "from": "jsprim@>=1.2.2 <2.0.0",
+      "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.3.1.tgz"
+    },
+    "jwa": {
+      "version": "1.0.2",
+      "from": "jwa@>=1.0.0 <1.1.0",
+      "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.0.2.tgz",
+      "dependencies": {
+        "base64url": {
+          "version": "0.0.6",
+          "from": "base64url@>=0.0.4 <0.1.0",
+          "resolved": "https://registry.npmjs.org/base64url/-/base64url-0.0.6.tgz"
+        }
+      }
+    },
+    "jws": {
+      "version": "3.0.0",
+      "from": "jws@>=3.0.0 <3.1.0",
+      "resolved": "https://registry.npmjs.org/jws/-/jws-3.0.0.tgz"
+    },
+    "kareem": {
+      "version": "1.2.0",
+      "from": "kareem@1.2.0",
+      "resolved": "https://registry.npmjs.org/kareem/-/kareem-1.2.0.tgz"
+    },
+    "kerberos": {
+      "version": "0.0.22",
+      "from": "kerberos@0.0.22",
+      "resolved": "https://registry.npmjs.org/kerberos/-/kerberos-0.0.22.tgz",
+      "dependencies": {
+        "nan": {
+          "version": "2.4.0",
+          "from": "nan@>=2.4.0 <2.5.0",
+          "resolved": "https://registry.npmjs.org/nan/-/nan-2.4.0.tgz"
+        }
+      }
+    },
+    "keygrip": {
+      "version": "1.0.1",
+      "from": "keygrip@>=1.0.0 <1.1.0",
+      "resolved": "https://registry.npmjs.org/keygrip/-/keygrip-1.0.1.tgz"
+    },
+    "kind-of": {
+      "version": "3.1.0",
+      "from": "kind-of@>=3.0.2 <4.0.0",
+      "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.1.0.tgz"
+    },
+    "klaw": {
+      "version": "1.3.1",
+      "from": "klaw@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/klaw/-/klaw-1.3.1.tgz",
+      "dependencies": {
+        "graceful-fs": {
+          "version": "4.1.11",
+          "from": "graceful-fs@^4.1.9",
+          "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
+          "optional": true
+        }
+      }
+    },
+    "lazy-cache": {
+      "version": "1.0.4",
+      "from": "lazy-cache@>=1.0.3 <2.0.0",
+      "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz"
+    },
+    "lcid": {
+      "version": "1.0.0",
+      "from": "lcid@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz"
+    },
+    "levn": {
+      "version": "0.2.5",
+      "from": "levn@>=0.2.5 <0.3.0",
+      "resolved": "https://registry.npmjs.org/levn/-/levn-0.2.5.tgz"
+    },
+    "libbase64": {
+      "version": "0.1.0",
+      "from": "libbase64@0.1.0",
+      "resolved": "https://registry.npmjs.org/libbase64/-/libbase64-0.1.0.tgz"
+    },
+    "libmime": {
+      "version": "3.0.0",
+      "from": "libmime@3.0.0",
+      "resolved": "https://registry.npmjs.org/libmime/-/libmime-3.0.0.tgz",
+      "dependencies": {
+        "iconv-lite": {
+          "version": "0.4.15",
+          "from": "iconv-lite@0.4.15",
+          "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.15.tgz"
+        }
+      }
+    },
+    "libqp": {
+      "version": "1.1.0",
+      "from": "libqp@1.1.0",
+      "resolved": "https://registry.npmjs.org/libqp/-/libqp-1.1.0.tgz"
+    },
+    "liftoff": {
+      "version": "2.3.0",
+      "from": "liftoff@>=2.1.0 <3.0.0",
+      "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-2.3.0.tgz"
+    },
+    "load-json-file": {
+      "version": "1.1.0",
+      "from": "load-json-file@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
+      "dependencies": {
+        "graceful-fs": {
+          "version": "4.1.11",
+          "from": "graceful-fs@>=4.1.2 <5.0.0",
+          "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz"
+        },
+        "strip-bom": {
+          "version": "2.0.0",
+          "from": "strip-bom@>=2.0.0 <3.0.0",
+          "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz"
+        }
+      }
+    },
+    "loader-runner": {
+      "version": "2.3.0",
+      "from": "loader-runner@>=2.3.0 <3.0.0",
+      "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.3.0.tgz"
+    },
+    "loader-utils": {
+      "version": "0.2.17",
+      "from": "loader-utils@>=0.2.16 <0.3.0",
+      "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-0.2.17.tgz",
+      "dependencies": {
+        "json5": {
+          "version": "0.5.1",
+          "from": "json5@>=0.5.0 <0.6.0",
+          "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz"
+        }
+      }
+    },
+    "localtunnel": {
+      "version": "1.8.2",
+      "from": "localtunnel@>=1.8.1 <2.0.0",
+      "resolved": "https://registry.npmjs.org/localtunnel/-/localtunnel-1.8.2.tgz",
+      "dependencies": {
+        "qs": {
+          "version": "6.3.0",
+          "from": "qs@>=6.3.0 <6.4.0",
+          "resolved": "https://registry.npmjs.org/qs/-/qs-6.3.0.tgz"
+        },
+        "request": {
+          "version": "2.78.0",
+          "from": "request@2.78.0",
+          "resolved": "https://registry.npmjs.org/request/-/request-2.78.0.tgz"
+        }
+      }
+    },
+    "lodash": {
+      "version": "3.5.0",
+      "from": "lodash@>=3.5.0 <3.6.0",
+      "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.5.0.tgz"
+    },
+    "lodash._basecopy": {
+      "version": "3.0.1",
+      "from": "lodash._basecopy@>=3.0.0 <4.0.0",
+      "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz"
+    },
+    "lodash._basetostring": {
+      "version": "3.0.1",
+      "from": "lodash._basetostring@>=3.0.0 <4.0.0",
+      "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz"
+    },
+    "lodash._basevalues": {
+      "version": "3.0.0",
+      "from": "lodash._basevalues@>=3.0.0 <4.0.0",
+      "resolved": "https://registry.npmjs.org/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz"
+    },
+    "lodash._escapehtmlchar": {
+      "version": "2.4.1",
+      "from": "lodash._escapehtmlchar@>=2.4.1 <2.5.0",
+      "resolved": "https://registry.npmjs.org/lodash._escapehtmlchar/-/lodash._escapehtmlchar-2.4.1.tgz"
+    },
+    "lodash._escapestringchar": {
+      "version": "2.4.1",
+      "from": "lodash._escapestringchar@>=2.4.1 <2.5.0",
+      "resolved": "https://registry.npmjs.org/lodash._escapestringchar/-/lodash._escapestringchar-2.4.1.tgz"
+    },
+    "lodash._getnative": {
+      "version": "3.9.1",
+      "from": "lodash._getnative@>=3.0.0 <4.0.0",
+      "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz"
+    },
+    "lodash._htmlescapes": {
+      "version": "2.4.1",
+      "from": "lodash._htmlescapes@>=2.4.1 <2.5.0",
+      "resolved": "https://registry.npmjs.org/lodash._htmlescapes/-/lodash._htmlescapes-2.4.1.tgz"
+    },
+    "lodash._isiterateecall": {
+      "version": "3.0.9",
+      "from": "lodash._isiterateecall@>=3.0.0 <4.0.0",
+      "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz"
+    },
+    "lodash._isnative": {
+      "version": "2.4.1",
+      "from": "lodash._isnative@>=2.4.1 <2.5.0",
+      "resolved": "https://registry.npmjs.org/lodash._isnative/-/lodash._isnative-2.4.1.tgz"
+    },
+    "lodash._objecttypes": {
+      "version": "2.4.1",
+      "from": "lodash._objecttypes@>=2.4.1 <2.5.0",
+      "resolved": "https://registry.npmjs.org/lodash._objecttypes/-/lodash._objecttypes-2.4.1.tgz"
+    },
+    "lodash._reescape": {
+      "version": "3.0.0",
+      "from": "lodash._reescape@>=3.0.0 <4.0.0",
+      "resolved": "https://registry.npmjs.org/lodash._reescape/-/lodash._reescape-3.0.0.tgz"
+    },
+    "lodash._reevaluate": {
+      "version": "3.0.0",
+      "from": "lodash._reevaluate@>=3.0.0 <4.0.0",
+      "resolved": "https://registry.npmjs.org/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz"
+    },
+    "lodash._reinterpolate": {
+      "version": "3.0.0",
+      "from": "lodash._reinterpolate@>=3.0.0 <4.0.0",
+      "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz"
+    },
+    "lodash._reunescapedhtml": {
+      "version": "2.4.1",
+      "from": "lodash._reunescapedhtml@>=2.4.1 <2.5.0",
+      "resolved": "https://registry.npmjs.org/lodash._reunescapedhtml/-/lodash._reunescapedhtml-2.4.1.tgz",
+      "dependencies": {
+        "lodash.keys": {
+          "version": "2.4.1",
+          "from": "lodash.keys@>=2.4.1 <2.5.0",
+          "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-2.4.1.tgz"
+        }
+      }
+    },
+    "lodash._root": {
+      "version": "3.0.1",
+      "from": "lodash._root@>=3.0.0 <4.0.0",
+      "resolved": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz"
+    },
+    "lodash._shimkeys": {
+      "version": "2.4.1",
+      "from": "lodash._shimkeys@>=2.4.1 <2.5.0",
+      "resolved": "https://registry.npmjs.org/lodash._shimkeys/-/lodash._shimkeys-2.4.1.tgz"
+    },
+    "lodash.assign": {
+      "version": "4.2.0",
+      "from": "lodash.assign@>=4.2.0 <5.0.0",
+      "resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz"
+    },
+    "lodash.assignwith": {
+      "version": "4.2.0",
+      "from": "lodash.assignwith@>=4.0.7 <5.0.0",
+      "resolved": "https://registry.npmjs.org/lodash.assignwith/-/lodash.assignwith-4.2.0.tgz"
+    },
+    "lodash.clone": {
+      "version": "4.5.0",
+      "from": "lodash.clone@>=4.3.2 <5.0.0",
+      "resolved": "https://registry.npmjs.org/lodash.clone/-/lodash.clone-4.5.0.tgz"
+    },
+    "lodash.clonedeep": {
+      "version": "4.5.0",
+      "from": "lodash.clonedeep@>=4.3.2 <5.0.0",
+      "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz"
+    },
+    "lodash.defaults": {
+      "version": "2.4.1",
+      "from": "lodash.defaults@>=2.4.1 <2.5.0",
+      "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-2.4.1.tgz",
+      "dependencies": {
+        "lodash.keys": {
+          "version": "2.4.1",
+          "from": "lodash.keys@>=2.4.1 <2.5.0",
+          "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-2.4.1.tgz"
+        }
+      }
+    },
+    "lodash.escape": {
+      "version": "3.2.0",
+      "from": "lodash.escape@>=3.0.0 <4.0.0",
+      "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.2.0.tgz"
+    },
+    "lodash.isarguments": {
+      "version": "3.1.0",
+      "from": "lodash.isarguments@>=3.0.0 <4.0.0",
+      "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz"
+    },
+    "lodash.isarray": {
+      "version": "3.0.4",
+      "from": "lodash.isarray@>=3.0.0 <4.0.0",
+      "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz"
+    },
+    "lodash.isempty": {
+      "version": "4.4.0",
+      "from": "lodash.isempty@>=4.2.1 <5.0.0",
+      "resolved": "https://registry.npmjs.org/lodash.isempty/-/lodash.isempty-4.4.0.tgz"
+    },
+    "lodash.isobject": {
+      "version": "2.4.1",
+      "from": "lodash.isobject@>=2.4.1 <2.5.0",
+      "resolved": "https://registry.npmjs.org/lodash.isobject/-/lodash.isobject-2.4.1.tgz"
+    },
+    "lodash.isplainobject": {
+      "version": "4.0.6",
+      "from": "lodash.isplainobject@>=4.0.4 <5.0.0",
+      "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz"
+    },
+    "lodash.isstring": {
+      "version": "4.0.1",
+      "from": "lodash.isstring@>=4.0.1 <5.0.0",
+      "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz"
+    },
+    "lodash.keys": {
+      "version": "3.1.2",
+      "from": "lodash.keys@>=3.0.0 <4.0.0",
+      "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz"
+    },
+    "lodash.mapvalues": {
+      "version": "4.6.0",
+      "from": "lodash.mapvalues@>=4.4.0 <5.0.0",
+      "resolved": "https://registry.npmjs.org/lodash.mapvalues/-/lodash.mapvalues-4.6.0.tgz"
+    },
+    "lodash.mergewith": {
+      "version": "4.6.0",
+      "from": "lodash.mergewith@>=4.6.0 <5.0.0",
+      "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.0.tgz"
+    },
+    "lodash.noop": {
+      "version": "3.0.1",
+      "from": "lodash.noop@>=3.0.0 <3.1.0",
+      "resolved": "https://registry.npmjs.org/lodash.noop/-/lodash.noop-3.0.1.tgz"
+    },
+    "lodash.pick": {
+      "version": "4.4.0",
+      "from": "lodash.pick@>=4.2.1 <5.0.0",
+      "resolved": "https://registry.npmjs.org/lodash.pick/-/lodash.pick-4.4.0.tgz"
+    },
+    "lodash.restparam": {
+      "version": "3.6.1",
+      "from": "lodash.restparam@>=3.0.0 <4.0.0",
+      "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz"
+    },
+    "lodash.some": {
+      "version": "4.6.0",
+      "from": "lodash.some@>=4.2.2 <5.0.0",
+      "resolved": "https://registry.npmjs.org/lodash.some/-/lodash.some-4.6.0.tgz"
+    },
+    "lodash.template": {
+      "version": "3.6.2",
+      "from": "lodash.template@>=3.0.0 <4.0.0",
+      "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz"
+    },
+    "lodash.templatesettings": {
+      "version": "3.1.1",
+      "from": "lodash.templatesettings@>=3.0.0 <4.0.0",
+      "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz"
+    },
+    "lodash.values": {
+      "version": "2.4.1",
+      "from": "lodash.values@>=2.4.1 <2.5.0",
+      "resolved": "https://registry.npmjs.org/lodash.values/-/lodash.values-2.4.1.tgz",
+      "dependencies": {
+        "lodash.keys": {
+          "version": "2.4.1",
+          "from": "lodash.keys@>=2.4.1 <2.5.0",
+          "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-2.4.1.tgz"
+        }
+      }
+    },
+    "log-symbols": {
+      "version": "1.0.2",
+      "from": "log-symbols@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz"
+    },
+    "lolex": {
+      "version": "1.1.0",
+      "from": "lolex@1.1.0",
+      "resolved": "https://registry.npmjs.org/lolex/-/lolex-1.1.0.tgz",
+      "dev": true
+    },
+    "longest": {
+      "version": "1.0.1",
+      "from": "longest@>=1.0.1 <2.0.0",
+      "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz"
+    },
+    "loose-envify": {
+      "version": "1.3.1",
+      "from": "loose-envify@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz"
+    },
+    "loud-rejection": {
+      "version": "1.6.0",
+      "from": "loud-rejection@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz"
+    },
+    "lru-cache": {
+      "version": "2.7.3",
+      "from": "lru-cache@>=2.0.0 <3.0.0",
+      "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz"
+    },
+    "mailcomposer": {
+      "version": "4.0.1",
+      "from": "mailcomposer@4.0.1",
+      "resolved": "https://registry.npmjs.org/mailcomposer/-/mailcomposer-4.0.1.tgz"
+    },
+    "map-cache": {
+      "version": "0.2.2",
+      "from": "map-cache@>=0.2.0 <0.3.0",
+      "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz"
+    },
+    "map-obj": {
+      "version": "1.0.1",
+      "from": "map-obj@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz"
+    },
+    "map-stream": {
+      "version": "0.0.4",
+      "from": "map-stream@0.0.4",
+      "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.0.4.tgz"
+    },
+    "marked": {
+      "version": "0.3.6",
+      "from": "marked@>=0.3.5 <0.4.0",
+      "resolved": "https://registry.npmjs.org/marked/-/marked-0.3.6.tgz"
+    },
+    "media-typer": {
+      "version": "0.3.0",
+      "from": "media-typer@0.3.0",
+      "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz"
+    },
+    "memory-fs": {
+      "version": "0.4.1",
+      "from": "memory-fs@>=0.4.1 <0.5.0",
+      "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz",
+      "dependencies": {
+        "isarray": {
+          "version": "1.0.0",
+          "from": "isarray@>=1.0.0 <1.1.0",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz"
+        },
+        "readable-stream": {
+          "version": "2.2.3",
+          "from": "readable-stream@>=2.0.1 <3.0.0",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.3.tgz"
+        }
+      }
+    },
+    "meow": {
+      "version": "2.0.0",
+      "from": "meow@>=2.0.0 <2.1.0",
+      "resolved": "https://registry.npmjs.org/meow/-/meow-2.0.0.tgz",
+      "dependencies": {
+        "minimist": {
+          "version": "1.2.0",
+          "from": "minimist@>=1.1.0 <2.0.0",
+          "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz"
+        },
+        "object-assign": {
+          "version": "1.0.0",
+          "from": "object-assign@>=1.0.0 <2.0.0",
+          "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-1.0.0.tgz"
+        }
+      }
+    },
+    "merge-descriptors": {
+      "version": "1.0.1",
+      "from": "merge-descriptors@1.0.1",
+      "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz"
+    },
+    "method-override": {
+      "version": "2.3.7",
+      "from": "method-override@>=2.3.1 <2.4.0",
+      "resolved": "https://registry.npmjs.org/method-override/-/method-override-2.3.7.tgz",
+      "dependencies": {
+        "debug": {
+          "version": "2.3.3",
+          "from": "debug@2.3.3",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.3.3.tgz"
+        },
+        "ms": {
+          "version": "0.7.2",
+          "from": "ms@0.7.2",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz"
+        }
+      }
+    },
+    "methods": {
+      "version": "1.1.2",
+      "from": "methods@>=1.1.2 <1.2.0",
+      "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz"
+    },
+    "micromatch": {
+      "version": "2.3.11",
+      "from": "micromatch@>=2.3.7 <3.0.0",
+      "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz"
+    },
+    "miller-rabin": {
+      "version": "4.0.0",
+      "from": "miller-rabin@>=4.0.0 <5.0.0",
+      "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.0.tgz"
+    },
+    "mime": {
+      "version": "1.3.4",
+      "from": "mime@1.3.4",
+      "resolved": "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz"
+    },
+    "mime-db": {
+      "version": "1.26.0",
+      "from": "mime-db@>=1.26.0 <1.27.0",
+      "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.26.0.tgz"
+    },
+    "mime-types": {
+      "version": "2.1.14",
+      "from": "mime-types@>=2.1.13 <2.2.0",
+      "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.14.tgz"
+    },
+    "minimalistic-assert": {
+      "version": "1.0.0",
+      "from": "minimalistic-assert@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz"
+    },
+    "minimalistic-crypto-utils": {
+      "version": "1.0.1",
+      "from": "minimalistic-crypto-utils@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz"
+    },
+    "minimatch": {
+      "version": "2.0.10",
+      "from": "minimatch@>=2.0.3 <3.0.0",
+      "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz"
+    },
+    "minimist": {
+      "version": "0.0.8",
+      "from": "minimist@0.0.8",
+      "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz"
+    },
+    "mkdirp": {
+      "version": "0.5.1",
+      "from": "mkdirp@>=0.5.1 <0.6.0",
+      "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz"
+    },
+    "mocha": {
+      "version": "2.2.5",
+      "from": "mocha@>=2.2.0 <2.3.0",
+      "resolved": "https://registry.npmjs.org/mocha/-/mocha-2.2.5.tgz",
+      "dev": true,
+      "dependencies": {
+        "commander": {
+          "version": "2.3.0",
+          "from": "commander@2.3.0",
+          "resolved": "https://registry.npmjs.org/commander/-/commander-2.3.0.tgz",
+          "dev": true
+        },
+        "debug": {
+          "version": "2.0.0",
+          "from": "debug@2.0.0",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.0.0.tgz",
+          "dev": true
+        },
+        "diff": {
+          "version": "1.4.0",
+          "from": "diff@1.4.0",
+          "resolved": "https://registry.npmjs.org/diff/-/diff-1.4.0.tgz",
+          "dev": true
+        },
+        "escape-string-regexp": {
+          "version": "1.0.2",
+          "from": "escape-string-regexp@1.0.2",
+          "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz",
+          "dev": true
+        },
+        "glob": {
+          "version": "3.2.3",
+          "from": "glob@3.2.3",
+          "resolved": "https://registry.npmjs.org/glob/-/glob-3.2.3.tgz",
+          "dev": true
+        },
+        "graceful-fs": {
+          "version": "2.0.3",
+          "from": "graceful-fs@>=2.0.0 <2.1.0",
+          "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-2.0.3.tgz",
+          "dev": true
+        },
+        "growl": {
+          "version": "1.8.1",
+          "from": "growl@1.8.1",
+          "resolved": "https://registry.npmjs.org/growl/-/growl-1.8.1.tgz",
+          "dev": true
+        },
+        "minimatch": {
+          "version": "0.2.14",
+          "from": "minimatch@>=0.2.11 <0.3.0",
+          "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz",
+          "dev": true
+        },
+        "mkdirp": {
+          "version": "0.5.0",
+          "from": "mkdirp@0.5.0",
+          "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.0.tgz",
+          "dev": true
+        },
+        "ms": {
+          "version": "0.6.2",
+          "from": "ms@0.6.2",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-0.6.2.tgz",
+          "dev": true
+        },
+        "supports-color": {
+          "version": "1.2.1",
+          "from": "supports-color@>=1.2.0 <1.3.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-1.2.1.tgz",
+          "dev": true
+        }
+      }
+    },
+    "moment": {
+      "version": "2.13.0",
+      "from": "moment@>=2.13.0 <2.14.0",
+      "resolved": "https://registry.npmjs.org/moment/-/moment-2.13.0.tgz"
+    },
+    "mongodb": {
+      "version": "2.2.22",
+      "from": "mongodb@2.2.22",
+      "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-2.2.22.tgz",
+      "dependencies": {
+        "isarray": {
+          "version": "1.0.0",
+          "from": "isarray@>=1.0.0 <1.1.0",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz"
+        },
+        "readable-stream": {
+          "version": "2.1.5",
+          "from": "readable-stream@2.1.5",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.1.5.tgz"
+        }
+      }
+    },
+    "mongodb-core": {
+      "version": "2.1.7",
+      "from": "mongodb-core@2.1.7",
+      "resolved": "https://registry.npmjs.org/mongodb-core/-/mongodb-core-2.1.7.tgz"
+    },
+    "mongoose": {
+      "version": "4.7.9",
+      "from": "mongoose@>=4.7.0 <4.8.0",
+      "resolved": "https://registry.npmjs.org/mongoose/-/mongoose-4.7.9.tgz",
+      "dependencies": {
+        "async": {
+          "version": "2.1.4",
+          "from": "async@2.1.4",
+          "resolved": "https://registry.npmjs.org/async/-/async-2.1.4.tgz"
+        },
+        "lodash": {
+          "version": "4.17.4",
+          "from": "lodash@>=4.14.0 <5.0.0",
+          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz"
+        },
+        "ms": {
+          "version": "0.7.2",
+          "from": "ms@0.7.2",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz"
+        }
+      }
+    },
+    "mongoose-paginate": {
+      "version": "5.0.3",
+      "from": "mongoose-paginate@>=5.0.0 <5.1.0",
+      "resolved": "https://registry.npmjs.org/mongoose-paginate/-/mongoose-paginate-5.0.3.tgz",
+      "dependencies": {
+        "bluebird": {
+          "version": "3.0.5",
+          "from": "bluebird@3.0.5",
+          "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.0.5.tgz"
+        }
+      }
+    },
+    "morgan": {
+      "version": "1.7.0",
+      "from": "morgan@>=1.7.0 <1.8.0",
+      "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.7.0.tgz"
+    },
+    "mpath": {
+      "version": "0.2.1",
+      "from": "mpath@0.2.1",
+      "resolved": "https://registry.npmjs.org/mpath/-/mpath-0.2.1.tgz"
+    },
+    "mpromise": {
+      "version": "0.5.5",
+      "from": "mpromise@0.5.5",
+      "resolved": "https://registry.npmjs.org/mpromise/-/mpromise-0.5.5.tgz"
+    },
+    "mquery": {
+      "version": "2.0.0",
+      "from": "mquery@2.0.0",
+      "resolved": "https://registry.npmjs.org/mquery/-/mquery-2.0.0.tgz",
+      "dependencies": {
+        "bluebird": {
+          "version": "2.10.2",
+          "from": "bluebird@2.10.2",
+          "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-2.10.2.tgz"
+        },
+        "sliced": {
+          "version": "0.0.5",
+          "from": "sliced@0.0.5",
+          "resolved": "https://registry.npmjs.org/sliced/-/sliced-0.0.5.tgz"
+        }
+      }
+    },
+    "ms": {
+      "version": "0.7.1",
+      "from": "ms@0.7.1",
+      "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz"
+    },
+    "multer": {
+      "version": "1.2.1",
+      "from": "multer@>=1.2.1 <1.3.0",
+      "resolved": "https://registry.npmjs.org/multer/-/multer-1.2.1.tgz",
+      "dependencies": {
+        "concat-stream": {
+          "version": "1.6.0",
+          "from": "concat-stream@>=1.5.0 <2.0.0",
+          "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.0.tgz"
+        },
+        "isarray": {
+          "version": "1.0.0",
+          "from": "isarray@>=1.0.0 <1.1.0",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz"
+        },
+        "object-assign": {
+          "version": "3.0.0",
+          "from": "object-assign@>=3.0.0 <4.0.0",
+          "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz"
+        },
+        "readable-stream": {
+          "version": "2.2.2",
+          "from": "readable-stream@>=2.2.2 <3.0.0",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.2.tgz"
+        }
+      }
+    },
+    "multipipe": {
+      "version": "0.1.2",
+      "from": "multipipe@>=0.1.2 <0.2.0",
+      "resolved": "https://registry.npmjs.org/multipipe/-/multipipe-0.1.2.tgz"
+    },
+    "muri": {
+      "version": "1.2.0",
+      "from": "muri@1.2.0",
+      "resolved": "https://registry.npmjs.org/muri/-/muri-1.2.0.tgz"
+    },
+    "mustache": {
+      "version": "2.3.0",
+      "from": "mustache@>=2.2.1 <3.0.0",
+      "resolved": "https://registry.npmjs.org/mustache/-/mustache-2.3.0.tgz"
+    },
+    "nan": {
+      "version": "2.5.1",
+      "from": "nan@>=2.3.2 <3.0.0",
+      "resolved": "https://registry.npmjs.org/nan/-/nan-2.5.1.tgz"
+    },
+    "natives": {
+      "version": "1.1.0",
+      "from": "natives@>=1.1.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/natives/-/natives-1.1.0.tgz"
+    },
+    "negotiator": {
+      "version": "0.6.1",
+      "from": "negotiator@0.6.1",
+      "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz"
+    },
+    "node-fetch": {
+      "version": "1.6.3",
+      "from": "node-fetch@>=1.0.1 <2.0.0",
+      "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.6.3.tgz"
+    },
+    "node-forge": {
+      "version": "0.6.48",
+      "from": "node-forge@>=0.6.46 <0.7.0",
+      "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-0.6.48.tgz"
+    },
+    "node-gyp": {
+      "version": "3.5.0",
+      "from": "node-gyp@>=3.3.1 <4.0.0",
+      "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.5.0.tgz",
+      "dependencies": {
+        "glob": {
+          "version": "7.1.1",
+          "from": "glob@>=7.0.3 <8.0.0",
+          "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz"
+        },
+        "graceful-fs": {
+          "version": "4.1.11",
+          "from": "graceful-fs@>=4.1.2 <5.0.0",
+          "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz"
+        },
+        "minimatch": {
+          "version": "3.0.3",
+          "from": "minimatch@>=3.0.2 <4.0.0",
+          "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.3.tgz"
+        },
+        "nopt": {
+          "version": "3.0.6",
+          "from": "nopt@>=2.0.0 <3.0.0||>=3.0.0 <4.0.0",
+          "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz"
+        }
+      }
+    },
+    "node-libs-browser": {
+      "version": "2.0.0",
+      "from": "node-libs-browser@>=2.0.0 <3.0.0",
+      "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.0.0.tgz",
+      "dependencies": {
+        "crypto-browserify": {
+          "version": "3.11.0",
+          "from": "crypto-browserify@>=3.11.0 <4.0.0",
+          "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.11.0.tgz"
+        },
+        "isarray": {
+          "version": "1.0.0",
+          "from": "isarray@~1.0.0",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz"
+        },
+        "readable-stream": {
+          "version": "2.2.3",
+          "from": "readable-stream@^2.0.5",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.3.tgz"
+        },
+        "url": {
+          "version": "0.11.0",
+          "from": "url@>=0.11.0 <0.12.0",
+          "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz",
+          "dependencies": {
+            "punycode": {
+              "version": "1.3.2",
+              "from": "punycode@1.3.2",
+              "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz"
+            }
+          }
+        }
+      }
+    },
+    "node-sass": {
+      "version": "4.5.0",
+      "from": "node-sass@>=4.2.0 <5.0.0",
+      "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.5.0.tgz",
+      "dependencies": {
+        "camelcase": {
+          "version": "2.1.1",
+          "from": "camelcase@>=2.0.0 <3.0.0",
+          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz"
+        },
+        "camelcase-keys": {
+          "version": "2.1.0",
+          "from": "camelcase-keys@>=2.0.0 <3.0.0",
+          "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz"
+        },
+        "gaze": {
+          "version": "1.1.2",
+          "from": "gaze@>=1.0.0 <2.0.0",
+          "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.2.tgz"
+        },
+        "glob": {
+          "version": "7.1.1",
+          "from": "glob@>=7.0.3 <8.0.0",
+          "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz"
+        },
+        "globule": {
+          "version": "1.1.0",
+          "from": "globule@>=1.0.0 <2.0.0",
+          "resolved": "https://registry.npmjs.org/globule/-/globule-1.1.0.tgz"
+        },
+        "lodash": {
+          "version": "4.16.6",
+          "from": "lodash@>=4.16.4 <4.17.0",
+          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.16.6.tgz"
+        },
+        "meow": {
+          "version": "3.7.0",
+          "from": "meow@>=3.7.0 <4.0.0",
+          "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz"
+        },
+        "minimatch": {
+          "version": "3.0.3",
+          "from": "minimatch@>=3.0.2 <3.1.0",
+          "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.3.tgz"
+        },
+        "minimist": {
+          "version": "1.2.0",
+          "from": "minimist@>=1.1.3 <2.0.0",
+          "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz"
+        }
+      }
+    },
+    "node-uuid": {
+      "version": "1.4.7",
+      "from": "node-uuid@>=1.4.3 <1.5.0",
+      "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.7.tgz"
+    },
+    "nodemailer": {
+      "version": "2.7.2",
+      "from": "nodemailer@>=2.7.0 <2.8.0",
+      "resolved": "https://registry.npmjs.org/nodemailer/-/nodemailer-2.7.2.tgz"
+    },
+    "nodemailer-direct-transport": {
+      "version": "3.3.2",
+      "from": "nodemailer-direct-transport@3.3.2",
+      "resolved": "https://registry.npmjs.org/nodemailer-direct-transport/-/nodemailer-direct-transport-3.3.2.tgz"
+    },
+    "nodemailer-fetch": {
+      "version": "1.6.0",
+      "from": "nodemailer-fetch@1.6.0",
+      "resolved": "https://registry.npmjs.org/nodemailer-fetch/-/nodemailer-fetch-1.6.0.tgz"
+    },
+    "nodemailer-ses-transport": {
+      "version": "1.5.0",
+      "from": "nodemailer-ses-transport@>=1.5.0 <1.6.0",
+      "resolved": "https://registry.npmjs.org/nodemailer-ses-transport/-/nodemailer-ses-transport-1.5.0.tgz",
+      "dependencies": {
+        "aws-sdk": {
+          "version": "2.9.0",
+          "from": "aws-sdk@>=2.6.12 <3.0.0",
+          "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.9.0.tgz"
+        },
+        "uuid": {
+          "version": "3.0.0",
+          "from": "uuid@3.0.0",
+          "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.0.0.tgz"
+        }
+      }
+    },
+    "nodemailer-shared": {
+      "version": "1.1.0",
+      "from": "nodemailer-shared@1.1.0",
+      "resolved": "https://registry.npmjs.org/nodemailer-shared/-/nodemailer-shared-1.1.0.tgz"
+    },
+    "nodemailer-smtp-pool": {
+      "version": "2.8.2",
+      "from": "nodemailer-smtp-pool@2.8.2",
+      "resolved": "https://registry.npmjs.org/nodemailer-smtp-pool/-/nodemailer-smtp-pool-2.8.2.tgz"
+    },
+    "nodemailer-smtp-transport": {
+      "version": "2.7.2",
+      "from": "nodemailer-smtp-transport@2.7.2",
+      "resolved": "https://registry.npmjs.org/nodemailer-smtp-transport/-/nodemailer-smtp-transport-2.7.2.tgz"
+    },
+    "nodemailer-wellknown": {
+      "version": "0.1.10",
+      "from": "nodemailer-wellknown@0.1.10",
+      "resolved": "https://registry.npmjs.org/nodemailer-wellknown/-/nodemailer-wellknown-0.1.10.tgz"
+    },
+    "nopt": {
+      "version": "1.0.10",
+      "from": "nopt@1.0.10",
+      "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz"
+    },
+    "normalize-package-data": {
+      "version": "2.3.5",
+      "from": "normalize-package-data@>=2.3.4 <3.0.0",
+      "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.3.5.tgz"
+    },
+    "normalize-path": {
+      "version": "2.0.1",
+      "from": "normalize-path@>=2.0.1 <3.0.0",
+      "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.0.1.tgz"
+    },
+    "npmlog": {
+      "version": "4.0.2",
+      "from": "npmlog@>=4.0.0 <5.0.0",
+      "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.0.2.tgz"
+    },
+    "number-is-nan": {
+      "version": "1.0.1",
+      "from": "number-is-nan@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz"
+    },
+    "oauth-sign": {
+      "version": "0.8.2",
+      "from": "oauth-sign@>=0.8.1 <0.9.0",
+      "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz"
+    },
+    "object-additions": {
+      "version": "0.5.1",
+      "from": "object-additions@>=0.5.1 <0.6.0",
+      "resolved": "https://registry.npmjs.org/object-additions/-/object-additions-0.5.1.tgz"
+    },
+    "object-assign": {
+      "version": "4.1.1",
+      "from": "object-assign@>=4.0.1 <5.0.0",
+      "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz"
+    },
+    "object-component": {
+      "version": "0.0.3",
+      "from": "object-component@0.0.3",
+      "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz"
+    },
+    "object-get": {
+      "version": "2.1.0",
+      "from": "object-get@>=2.0.2 <3.0.0",
+      "resolved": "https://registry.npmjs.org/object-get/-/object-get-2.1.0.tgz"
+    },
+    "object-keys": {
+      "version": "1.0.1",
+      "from": "object-keys@1.0.1",
+      "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.0.1.tgz"
+    },
+    "object-tools": {
+      "version": "2.0.6",
+      "from": "object-tools@>=2.0.6 <3.0.0",
+      "resolved": "https://registry.npmjs.org/object-tools/-/object-tools-2.0.6.tgz"
+    },
+    "object.omit": {
+      "version": "2.0.1",
+      "from": "object.omit@>=2.0.0 <3.0.0",
+      "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz"
+    },
+    "on-finished": {
+      "version": "2.3.0",
+      "from": "on-finished@>=2.3.0 <2.4.0",
+      "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz"
+    },
+    "on-headers": {
+      "version": "1.0.1",
+      "from": "on-headers@>=1.0.1 <1.1.0",
+      "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz"
+    },
+    "once": {
+      "version": "1.4.0",
+      "from": "once@>=1.3.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz"
+    },
+    "openurl": {
+      "version": "1.1.0",
+      "from": "openurl@1.1.0",
+      "resolved": "https://registry.npmjs.org/openurl/-/openurl-1.1.0.tgz"
+    },
+    "optimist": {
+      "version": "0.6.1",
+      "from": "optimist@>=0.6.1 <0.7.0",
+      "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
+      "dependencies": {
+        "wordwrap": {
+          "version": "0.0.3",
+          "from": "wordwrap@>=0.0.2 <0.1.0",
+          "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz"
+        }
+      }
+    },
+    "optionator": {
+      "version": "0.5.0",
+      "from": "optionator@>=0.5.0 <0.6.0",
+      "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.5.0.tgz",
+      "dependencies": {
+        "wordwrap": {
+          "version": "0.0.3",
+          "from": "wordwrap@>=0.0.2 <0.1.0",
+          "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz"
+        }
+      }
+    },
+    "options": {
+      "version": "0.0.6",
+      "from": "options@>=0.0.5",
+      "resolved": "https://registry.npmjs.org/options/-/options-0.0.6.tgz"
+    },
+    "orchestrator": {
+      "version": "0.3.8",
+      "from": "orchestrator@>=0.3.0 <0.4.0",
+      "resolved": "https://registry.npmjs.org/orchestrator/-/orchestrator-0.3.8.tgz"
+    },
+    "ordered-read-streams": {
+      "version": "0.1.0",
+      "from": "ordered-read-streams@>=0.1.0 <0.2.0",
+      "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-0.1.0.tgz"
+    },
+    "os-browserify": {
+      "version": "0.2.1",
+      "from": "os-browserify@>=0.2.0 <0.3.0",
+      "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.2.1.tgz"
+    },
+    "os-homedir": {
+      "version": "1.0.2",
+      "from": "os-homedir@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz"
+    },
+    "os-locale": {
+      "version": "1.4.0",
+      "from": "os-locale@>=1.4.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz"
+    },
+    "os-tmpdir": {
+      "version": "1.0.2",
+      "from": "os-tmpdir@>=1.0.1 <2.0.0",
+      "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz"
+    },
+    "osenv": {
+      "version": "0.1.4",
+      "from": "osenv@>=0.0.0 <1.0.0",
+      "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.4.tgz"
+    },
+    "pako": {
+      "version": "0.2.9",
+      "from": "pako@>=0.2.0 <0.3.0",
+      "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz"
+    },
+    "parse-asn1": {
+      "version": "5.0.0",
+      "from": "parse-asn1@>=5.0.0 <6.0.0",
+      "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.0.0.tgz"
+    },
+    "parse-filepath": {
+      "version": "1.0.1",
+      "from": "parse-filepath@>=1.0.1 <2.0.0",
+      "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.1.tgz"
+    },
+    "parse-glob": {
+      "version": "3.0.4",
+      "from": "parse-glob@>=3.0.4 <4.0.0",
+      "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz"
+    },
+    "parse-json": {
+      "version": "2.2.0",
+      "from": "parse-json@>=2.2.0 <3.0.0",
+      "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz"
+    },
+    "parse-passwd": {
+      "version": "1.0.0",
+      "from": "parse-passwd@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz"
+    },
+    "parsejson": {
+      "version": "0.0.1",
+      "from": "parsejson@0.0.1",
+      "resolved": "https://registry.npmjs.org/parsejson/-/parsejson-0.0.1.tgz"
+    },
+    "parseqs": {
+      "version": "0.0.2",
+      "from": "parseqs@0.0.2",
+      "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.2.tgz"
+    },
+    "parseuri": {
+      "version": "0.0.2",
+      "from": "parseuri@0.0.2",
+      "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.2.tgz"
+    },
+    "parseurl": {
+      "version": "1.3.1",
+      "from": "parseurl@>=1.3.1 <1.4.0",
+      "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.1.tgz"
+    },
+    "path-browserify": {
+      "version": "0.0.0",
+      "from": "path-browserify@0.0.0",
+      "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz"
+    },
+    "path-dirname": {
+      "version": "1.0.2",
+      "from": "path-dirname@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz"
+    },
+    "path-exists": {
+      "version": "1.0.0",
+      "from": "path-exists@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-1.0.0.tgz"
+    },
+    "path-is-absolute": {
+      "version": "1.0.1",
+      "from": "path-is-absolute@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz"
+    },
+    "path-is-inside": {
+      "version": "1.0.2",
+      "from": "path-is-inside@>=1.0.1 <2.0.0",
+      "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz"
+    },
+    "path-root": {
+      "version": "0.1.1",
+      "from": "path-root@>=0.1.1 <0.2.0",
+      "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz"
+    },
+    "path-root-regex": {
+      "version": "0.1.2",
+      "from": "path-root-regex@>=0.1.0 <0.2.0",
+      "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz"
+    },
+    "path-to-regexp": {
+      "version": "0.1.7",
+      "from": "path-to-regexp@0.1.7",
+      "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz"
+    },
+    "path-type": {
+      "version": "1.1.0",
+      "from": "path-type@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz",
+      "dependencies": {
+        "graceful-fs": {
+          "version": "4.1.11",
+          "from": "graceful-fs@>=4.1.2 <5.0.0",
+          "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz"
+        }
+      }
+    },
+    "pbkdf2": {
+      "version": "3.0.9",
+      "from": "pbkdf2@>=3.0.3 <4.0.0",
+      "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.9.tgz"
+    },
+    "pbkdf2-compat": {
+      "version": "2.0.1",
+      "from": "pbkdf2-compat@2.0.1",
+      "resolved": "https://registry.npmjs.org/pbkdf2-compat/-/pbkdf2-compat-2.0.1.tgz"
+    },
+    "pify": {
+      "version": "2.3.0",
+      "from": "pify@>=2.0.0 <3.0.0",
+      "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz"
+    },
+    "pinkie": {
+      "version": "2.0.4",
+      "from": "pinkie@>=2.0.0 <3.0.0",
+      "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz"
+    },
+    "pinkie-promise": {
+      "version": "2.0.1",
+      "from": "pinkie-promise@>=2.0.0 <3.0.0",
+      "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz"
+    },
+    "pkg-dir": {
+      "version": "1.0.0",
+      "from": "pkg-dir@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-1.0.0.tgz"
+    },
+    "plur": {
+      "version": "2.1.2",
+      "from": "plur@>=2.1.0 <3.0.0",
+      "resolved": "https://registry.npmjs.org/plur/-/plur-2.1.2.tgz"
+    },
+    "prelude-ls": {
+      "version": "1.1.2",
+      "from": "prelude-ls@>=1.1.1 <1.2.0",
+      "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz"
+    },
+    "preserve": {
+      "version": "0.2.0",
+      "from": "preserve@>=0.2.0 <0.3.0",
+      "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz"
+    },
+    "pretty-hrtime": {
+      "version": "1.0.3",
+      "from": "pretty-hrtime@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz"
+    },
+    "private": {
+      "version": "0.1.6",
+      "from": "private@>=0.1.6 <0.2.0",
+      "resolved": "https://registry.npmjs.org/private/-/private-0.1.6.tgz"
+    },
+    "process": {
+      "version": "0.11.9",
+      "from": "process@>=0.11.0 <0.12.0",
+      "resolved": "https://registry.npmjs.org/process/-/process-0.11.9.tgz"
+    },
+    "process-nextick-args": {
+      "version": "1.0.7",
+      "from": "process-nextick-args@>=1.0.6 <1.1.0",
+      "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz"
+    },
+    "promise": {
+      "version": "7.1.1",
+      "from": "promise@>=7.1.1 <8.0.0",
+      "resolved": "https://registry.npmjs.org/promise/-/promise-7.1.1.tgz"
+    },
+    "proxy-addr": {
+      "version": "1.1.3",
+      "from": "proxy-addr@>=1.1.3 <1.2.0",
+      "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-1.1.3.tgz"
+    },
+    "proxyquire": {
+      "version": "1.4.0",
+      "from": "proxyquire@>=1.4.0 <1.5.0",
+      "resolved": "https://registry.npmjs.org/proxyquire/-/proxyquire-1.4.0.tgz",
+      "dev": true
+    },
+    "prr": {
+      "version": "0.0.0",
+      "from": "prr@>=0.0.0 <0.1.0",
+      "resolved": "https://registry.npmjs.org/prr/-/prr-0.0.0.tgz"
+    },
+    "pseudomap": {
+      "version": "1.0.2",
+      "from": "pseudomap@>=1.0.1 <2.0.0",
+      "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz"
+    },
+    "public-encrypt": {
+      "version": "4.0.0",
+      "from": "public-encrypt@>=4.0.0 <5.0.0",
+      "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.0.tgz"
+    },
+    "punycode": {
+      "version": "1.4.1",
+      "from": "punycode@>=1.4.1 <2.0.0",
+      "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz"
+    },
+    "qs": {
+      "version": "5.2.0",
+      "from": "qs@5.2.0",
+      "resolved": "https://registry.npmjs.org/qs/-/qs-5.2.0.tgz"
+    },
+    "querystring": {
+      "version": "0.2.0",
+      "from": "querystring@0.2.0",
+      "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz"
+    },
+    "querystring-es3": {
+      "version": "0.2.1",
+      "from": "querystring-es3@>=0.2.0 <0.3.0",
+      "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz"
+    },
+    "random-bytes": {
+      "version": "1.0.0",
+      "from": "random-bytes@>=1.0.0 <1.1.0",
+      "resolved": "https://registry.npmjs.org/random-bytes/-/random-bytes-1.0.0.tgz"
+    },
+    "randomatic": {
+      "version": "1.1.6",
+      "from": "randomatic@>=1.1.3 <2.0.0",
+      "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.6.tgz"
+    },
+    "randombytes": {
+      "version": "2.0.3",
+      "from": "randombytes@>=2.0.0 <3.0.0",
+      "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.3.tgz"
+    },
+    "range-parser": {
+      "version": "1.2.0",
+      "from": "range-parser@>=1.2.0 <1.3.0",
+      "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz"
+    },
+    "raw-body": {
+      "version": "2.1.7",
+      "from": "raw-body@>=2.1.5 <2.2.0",
+      "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.1.7.tgz",
+      "dependencies": {
+        "bytes": {
+          "version": "2.4.0",
+          "from": "bytes@2.4.0",
+          "resolved": "https://registry.npmjs.org/bytes/-/bytes-2.4.0.tgz"
+        }
+      }
+    },
+    "rcfinder": {
+      "version": "0.1.9",
+      "from": "rcfinder@>=0.1.6 <0.2.0",
+      "resolved": "https://registry.npmjs.org/rcfinder/-/rcfinder-0.1.9.tgz"
+    },
+    "rcloader": {
+      "version": "0.1.2",
+      "from": "rcloader@0.1.2",
+      "resolved": "https://registry.npmjs.org/rcloader/-/rcloader-0.1.2.tgz",
+      "dependencies": {
+        "lodash": {
+          "version": "2.4.2",
+          "from": "lodash@>=2.4.1 <2.5.0",
+          "resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz"
+        }
+      }
+    },
+    "react": {
+      "version": "15.0.2",
+      "from": "react@>=15.0.1 <15.1.0",
+      "resolved": "https://registry.npmjs.org/react/-/react-15.0.2.tgz"
+    },
+    "react-dom": {
+      "version": "15.0.2",
+      "from": "react-dom@>=15.0.1 <15.1.0",
+      "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-15.0.2.tgz"
+    },
+    "read-pkg": {
+      "version": "1.1.0",
+      "from": "read-pkg@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz"
+    },
+    "read-pkg-up": {
+      "version": "1.0.1",
+      "from": "read-pkg-up@>=1.0.1 <2.0.0",
+      "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz"
+    },
+    "readable-stream": {
+      "version": "1.1.14",
+      "from": "readable-stream@>=1.1.9 <1.2.0",
+      "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz"
+    },
+    "readdirp": {
+      "version": "2.1.0",
+      "from": "readdirp@>=2.0.0 <3.0.0",
+      "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.1.0.tgz",
+      "dependencies": {
+        "graceful-fs": {
+          "version": "4.1.11",
+          "from": "graceful-fs@>=4.1.2 <5.0.0",
+          "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz"
+        },
+        "isarray": {
+          "version": "1.0.0",
+          "from": "isarray@>=1.0.0 <1.1.0",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz"
+        },
+        "minimatch": {
+          "version": "3.0.3",
+          "from": "minimatch@>=3.0.2 <4.0.0",
+          "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.3.tgz"
+        },
+        "readable-stream": {
+          "version": "2.2.2",
+          "from": "readable-stream@>=2.0.2 <3.0.0",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.2.tgz"
+        }
+      }
+    },
+    "rechoir": {
+      "version": "0.6.2",
+      "from": "rechoir@>=0.6.2 <0.7.0",
+      "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz"
+    },
+    "redent": {
+      "version": "1.0.0",
+      "from": "redent@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz",
+      "dependencies": {
+        "indent-string": {
+          "version": "2.1.0",
+          "from": "indent-string@>=2.1.0 <3.0.0",
+          "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz"
+        }
+      }
+    },
+    "redis": {
+      "version": "2.6.5",
+      "from": "redis@>=2.6.5 <2.7.0",
+      "resolved": "https://registry.npmjs.org/redis/-/redis-2.6.5.tgz"
+    },
+    "redis-commands": {
+      "version": "1.3.1",
+      "from": "redis-commands@>=1.2.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/redis-commands/-/redis-commands-1.3.1.tgz"
+    },
+    "redis-parser": {
+      "version": "2.4.0",
+      "from": "redis-parser@>=2.0.0 <3.0.0",
+      "resolved": "https://registry.npmjs.org/redis-parser/-/redis-parser-2.4.0.tgz"
+    },
+    "regenerate": {
+      "version": "1.3.2",
+      "from": "regenerate@>=1.2.1 <2.0.0",
+      "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.3.2.tgz"
+    },
+    "regenerator-runtime": {
+      "version": "0.10.1",
+      "from": "regenerator-runtime@>=0.10.0 <0.11.0",
+      "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.10.1.tgz"
+    },
+    "regenerator-transform": {
+      "version": "0.9.8",
+      "from": "regenerator-transform@0.9.8",
+      "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.9.8.tgz",
+      "dependencies": {
+        "babel-runtime": {
+          "version": "6.23.0",
+          "from": "babel-runtime@^6.18.0",
+          "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.23.0.tgz"
+        }
+      }
+    },
+    "regex-cache": {
+      "version": "0.4.3",
+      "from": "regex-cache@>=0.4.2 <0.5.0",
+      "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.3.tgz"
+    },
+    "regexp-clone": {
+      "version": "0.0.1",
+      "from": "regexp-clone@0.0.1",
+      "resolved": "https://registry.npmjs.org/regexp-clone/-/regexp-clone-0.0.1.tgz"
+    },
+    "regexpu-core": {
+      "version": "2.0.0",
+      "from": "regexpu-core@>=2.0.0 <3.0.0",
+      "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-2.0.0.tgz"
+    },
+    "regjsgen": {
+      "version": "0.2.0",
+      "from": "regjsgen@>=0.2.0 <0.3.0",
+      "resolved": "https://registry.npmjs.org/regjsgen/-/regjsgen-0.2.0.tgz"
+    },
+    "regjsparser": {
+      "version": "0.1.5",
+      "from": "regjsparser@>=0.1.4 <0.2.0",
+      "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.1.5.tgz",
+      "dependencies": {
+        "jsesc": {
+          "version": "0.5.0",
+          "from": "jsesc@>=0.5.0 <0.6.0",
+          "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz"
+        }
+      }
+    },
+    "remove-trailing-separator": {
+      "version": "1.0.1",
+      "from": "remove-trailing-separator@>=1.0.1 <2.0.0",
+      "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.0.1.tgz"
+    },
+    "repeat-element": {
+      "version": "1.1.2",
+      "from": "repeat-element@>=1.1.2 <2.0.0",
+      "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz"
+    },
+    "repeat-string": {
+      "version": "1.6.1",
+      "from": "repeat-string@>=1.5.2 <2.0.0",
+      "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz"
+    },
+    "repeating": {
+      "version": "2.0.1",
+      "from": "repeating@>=2.0.0 <3.0.0",
+      "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz"
+    },
+    "replace-ext": {
+      "version": "0.0.1",
+      "from": "replace-ext@0.0.1",
+      "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz"
+    },
+    "request": {
+      "version": "2.79.0",
+      "from": "request@>=2.67.0 <3.0.0",
+      "resolved": "https://registry.npmjs.org/request/-/request-2.79.0.tgz",
+      "dependencies": {
+        "qs": {
+          "version": "6.3.0",
+          "from": "qs@>=6.3.0 <6.4.0",
+          "resolved": "https://registry.npmjs.org/qs/-/qs-6.3.0.tgz"
+        },
+        "uuid": {
+          "version": "3.0.1",
+          "from": "uuid@>=3.0.0 <4.0.0",
+          "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.0.1.tgz"
+        }
+      }
+    },
+    "require_optional": {
+      "version": "1.0.0",
+      "from": "require_optional@>=1.0.0 <1.1.0",
+      "resolved": "https://registry.npmjs.org/require_optional/-/require_optional-1.0.0.tgz",
+      "dependencies": {
+        "semver": {
+          "version": "5.3.0",
+          "from": "semver@>=5.1.0 <6.0.0",
+          "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz"
+        }
+      }
+    },
+    "require-directory": {
+      "version": "2.1.1",
+      "from": "require-directory@>=2.1.1 <3.0.0",
+      "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz"
+    },
+    "require-main-filename": {
+      "version": "1.0.1",
+      "from": "require-main-filename@>=1.0.1 <2.0.0",
+      "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz"
+    },
+    "resolve": {
+      "version": "1.2.0",
+      "from": "resolve@>=1.1.7 <2.0.0",
+      "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.2.0.tgz"
+    },
+    "resolve-dir": {
+      "version": "0.1.1",
+      "from": "resolve-dir@>=0.1.0 <0.2.0",
+      "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-0.1.1.tgz"
+    },
+    "resolve-from": {
+      "version": "2.0.0",
+      "from": "resolve-from@>=2.0.0 <3.0.0",
+      "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-2.0.0.tgz"
+    },
+    "reveal.js": {
+      "version": "3.2.0",
+      "from": "reveal.js@>=3.2.0 <3.3.0",
+      "resolved": "https://registry.npmjs.org/reveal.js/-/reveal.js-3.2.0.tgz",
+      "dependencies": {
+        "accepts": {
+          "version": "1.2.13",
+          "from": "accepts@>=1.2.12 <1.3.0",
+          "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.2.13.tgz"
+        },
+        "content-disposition": {
+          "version": "0.5.1",
+          "from": "content-disposition@0.5.1",
+          "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.1.tgz"
+        },
+        "cookie": {
+          "version": "0.1.5",
+          "from": "cookie@0.1.5",
+          "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.1.5.tgz"
+        },
+        "express": {
+          "version": "4.13.4",
+          "from": "express@>=4.13.3 <4.14.0",
+          "resolved": "https://registry.npmjs.org/express/-/express-4.13.4.tgz"
+        },
+        "finalhandler": {
+          "version": "0.4.1",
+          "from": "finalhandler@0.4.1",
+          "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-0.4.1.tgz"
+        },
+        "ipaddr.js": {
+          "version": "1.0.5",
+          "from": "ipaddr.js@1.0.5",
+          "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.0.5.tgz"
+        },
+        "mustache": {
+          "version": "2.1.3",
+          "from": "mustache@>=2.1.3 <2.2.0",
+          "resolved": "https://registry.npmjs.org/mustache/-/mustache-2.1.3.tgz"
+        },
+        "negotiator": {
+          "version": "0.5.3",
+          "from": "negotiator@0.5.3",
+          "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.5.3.tgz"
+        },
+        "proxy-addr": {
+          "version": "1.0.10",
+          "from": "proxy-addr@>=1.0.10 <1.1.0",
+          "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-1.0.10.tgz"
+        },
+        "qs": {
+          "version": "4.0.0",
+          "from": "qs@4.0.0",
+          "resolved": "https://registry.npmjs.org/qs/-/qs-4.0.0.tgz"
+        },
+        "range-parser": {
+          "version": "1.0.3",
+          "from": "range-parser@>=1.0.3 <1.1.0",
+          "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.0.3.tgz"
+        },
+        "send": {
+          "version": "0.13.1",
+          "from": "send@0.13.1",
+          "resolved": "https://registry.npmjs.org/send/-/send-0.13.1.tgz"
+        },
+        "serve-static": {
+          "version": "1.10.3",
+          "from": "serve-static@>=1.10.2 <1.11.0",
+          "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.10.3.tgz",
+          "dependencies": {
+            "send": {
+              "version": "0.13.2",
+              "from": "send@0.13.2",
+              "resolved": "https://registry.npmjs.org/send/-/send-0.13.2.tgz"
+            }
+          }
+        },
+        "statuses": {
+          "version": "1.2.1",
+          "from": "statuses@>=1.2.1 <1.3.0",
+          "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.2.1.tgz"
+        },
+        "underscore": {
+          "version": "1.8.3",
+          "from": "underscore@>=1.8.3 <1.9.0",
+          "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz"
+        },
+        "vary": {
+          "version": "1.0.1",
+          "from": "vary@>=1.0.1 <1.1.0",
+          "resolved": "https://registry.npmjs.org/vary/-/vary-1.0.1.tgz"
+        }
+      }
+    },
+    "right-align": {
+      "version": "0.1.3",
+      "from": "right-align@>=0.1.1 <0.2.0",
+      "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz"
+    },
+    "rimraf": {
+      "version": "2.5.4",
+      "from": "rimraf@>=2.2.8 <3.0.0",
+      "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.5.4.tgz",
+      "dependencies": {
+        "glob": {
+          "version": "7.1.1",
+          "from": "glob@>=7.0.5 <8.0.0",
+          "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz"
+        },
+        "minimatch": {
+          "version": "3.0.3",
+          "from": "minimatch@>=3.0.2 <4.0.0",
+          "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.3.tgz"
+        }
+      }
+    },
+    "ripemd160": {
+      "version": "1.0.1",
+      "from": "ripemd160@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-1.0.1.tgz"
+    },
+    "rndm": {
+      "version": "1.2.0",
+      "from": "rndm@1.2.0",
+      "resolved": "https://registry.npmjs.org/rndm/-/rndm-1.2.0.tgz"
+    },
+    "safe-buffer": {
+      "version": "5.0.1",
+      "from": "safe-buffer@>=5.0.1 <6.0.0",
+      "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.0.1.tgz"
+    },
+    "samsam": {
+      "version": "1.1.3",
+      "from": "samsam@>=1.1.0 <1.2.0",
+      "resolved": "https://registry.npmjs.org/samsam/-/samsam-1.1.3.tgz",
+      "dev": true
+    },
+    "sass-graph": {
+      "version": "2.1.2",
+      "from": "sass-graph@>=2.1.1 <3.0.0",
+      "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-2.1.2.tgz",
+      "dependencies": {
+        "glob": {
+          "version": "7.1.1",
+          "from": "glob@>=7.0.0 <8.0.0",
+          "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.1.tgz"
+        },
+        "lodash": {
+          "version": "4.17.4",
+          "from": "lodash@>=4.0.0 <5.0.0",
+          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz"
+        },
+        "minimatch": {
+          "version": "3.0.3",
+          "from": "minimatch@>=3.0.2 <4.0.0",
+          "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.3.tgz"
+        },
+        "window-size": {
+          "version": "0.2.0",
+          "from": "window-size@>=0.2.0 <0.3.0",
+          "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.2.0.tgz"
+        },
+        "yargs": {
+          "version": "4.8.1",
+          "from": "yargs@>=4.7.1 <5.0.0",
+          "resolved": "https://registry.npmjs.org/yargs/-/yargs-4.8.1.tgz"
+        }
+      }
+    },
+    "sax": {
+      "version": "1.1.5",
+      "from": "sax@1.1.5",
+      "resolved": "https://registry.npmjs.org/sax/-/sax-1.1.5.tgz"
+    },
+    "semver": {
+      "version": "5.0.3",
+      "from": "semver@>=5.0.1 <5.1.0",
+      "resolved": "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz"
+    },
+    "send": {
+      "version": "0.14.2",
+      "from": "send@0.14.2",
+      "resolved": "https://registry.npmjs.org/send/-/send-0.14.2.tgz",
+      "dependencies": {
+        "http-errors": {
+          "version": "1.5.1",
+          "from": "http-errors@>=1.5.1 <1.6.0",
+          "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.5.1.tgz"
+        },
+        "ms": {
+          "version": "0.7.2",
+          "from": "ms@0.7.2",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.2.tgz"
+        }
+      }
+    },
+    "sequencify": {
+      "version": "0.0.7",
+      "from": "sequencify@>=0.0.7 <0.1.0",
+      "resolved": "https://registry.npmjs.org/sequencify/-/sequencify-0.0.7.tgz"
+    },
+    "serve-static": {
+      "version": "1.11.2",
+      "from": "serve-static@>=1.11.2 <1.12.0",
+      "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.11.2.tgz"
+    },
+    "set-blocking": {
+      "version": "2.0.0",
+      "from": "set-blocking@>=2.0.0 <2.1.0",
+      "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz"
+    },
+    "set-immediate-shim": {
+      "version": "1.0.1",
+      "from": "set-immediate-shim@>=1.0.1 <2.0.0",
+      "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz"
+    },
+    "setimmediate": {
+      "version": "1.0.5",
+      "from": "setimmediate@>=1.0.5 <2.0.0",
+      "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz"
+    },
+    "setprototypeof": {
+      "version": "1.0.2",
+      "from": "setprototypeof@1.0.2",
+      "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.2.tgz"
+    },
+    "sha.js": {
+      "version": "2.4.8",
+      "from": "sha.js@>=2.3.6 <3.0.0",
+      "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.8.tgz"
+    },
+    "shebang-regex": {
+      "version": "1.0.0",
+      "from": "shebang-regex@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz"
+    },
+    "shelljs": {
+      "version": "0.3.0",
+      "from": "shelljs@>=0.3.0 <0.4.0",
+      "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz"
+    },
+    "sigmund": {
+      "version": "1.0.1",
+      "from": "sigmund@>=1.0.0 <1.1.0",
+      "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz"
+    },
+    "signal-exit": {
+      "version": "3.0.2",
+      "from": "signal-exit@>=3.0.0 <4.0.0",
+      "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz"
+    },
+    "sinon": {
+      "version": "1.14.1",
+      "from": "sinon@>=1.14.0 <1.15.0",
+      "resolved": "https://registry.npmjs.org/sinon/-/sinon-1.14.1.tgz",
+      "dev": true
+    },
+    "sinon-chai": {
+      "version": "2.7.0",
+      "from": "sinon-chai@>=2.7.0 <2.8.0",
+      "resolved": "https://registry.npmjs.org/sinon-chai/-/sinon-chai-2.7.0.tgz",
+      "dev": true
+    },
+    "slash": {
+      "version": "1.0.0",
+      "from": "slash@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/slash/-/slash-1.0.0.tgz"
+    },
+    "sliced": {
+      "version": "1.0.1",
+      "from": "sliced@1.0.1",
+      "resolved": "https://registry.npmjs.org/sliced/-/sliced-1.0.1.tgz"
+    },
+    "smart-buffer": {
+      "version": "1.1.15",
+      "from": "smart-buffer@>=1.0.4 <2.0.0",
+      "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-1.1.15.tgz"
+    },
+    "smtp-connection": {
+      "version": "2.12.0",
+      "from": "smtp-connection@2.12.0",
+      "resolved": "https://registry.npmjs.org/smtp-connection/-/smtp-connection-2.12.0.tgz"
+    },
+    "sntp": {
+      "version": "1.0.9",
+      "from": "sntp@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz"
+    },
+    "socket.io": {
+      "version": "1.3.7",
+      "from": "socket.io@>=1.3.0 <1.4.0",
+      "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-1.3.7.tgz",
+      "dependencies": {
+        "debug": {
+          "version": "2.1.0",
+          "from": "debug@2.1.0",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-2.1.0.tgz"
+        },
+        "ms": {
+          "version": "0.6.2",
+          "from": "ms@0.6.2",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-0.6.2.tgz"
+        }
+      }
+    },
+    "socket.io-adapter": {
+      "version": "0.3.1",
+      "from": "socket.io-adapter@0.3.1",
+      "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-0.3.1.tgz",
+      "dependencies": {
+        "debug": {
+          "version": "1.0.2",
+          "from": "debug@1.0.2",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-1.0.2.tgz"
+        },
+        "ms": {
+          "version": "0.6.2",
+          "from": "ms@0.6.2",
+          "resolved": "https://registry.npmjs.org/ms/-/ms-0.6.2.tgz"
+        },
+        "socket.io-parser": {
+          "version": "2.2.2",
+          "from": "socket.io-parser@2.2.2",
+          "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-2.2.2.tgz",
+          "dependencies": {
+            "debug": {
+              "version": "0.7.4",
+              "from": "debug@0.7.4",
+              "resolved": "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz"
+            }
+          }
+        }
+      }
+    },
+    "socket.io-client": {
+      "version": "1.3.7",
+      "from": "socket.io-client@>=1.3.0 <1.4.0",
+      "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-1.3.7.tgz",
+      "dependencies": {
+        "debug": {
+          "version": "0.7.4",
+          "from": "debug@0.7.4",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz"
+        }
+      }
+    },
+    "socket.io-parser": {
+      "version": "2.2.4",
+      "from": "socket.io-parser@2.2.4",
+      "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-2.2.4.tgz",
+      "dependencies": {
+        "debug": {
+          "version": "0.7.4",
+          "from": "debug@0.7.4",
+          "resolved": "https://registry.npmjs.org/debug/-/debug-0.7.4.tgz"
+        }
+      }
+    },
+    "socks": {
+      "version": "1.1.9",
+      "from": "socks@1.1.9",
+      "resolved": "https://registry.npmjs.org/socks/-/socks-1.1.9.tgz"
+    },
+    "source-list-map": {
+      "version": "0.1.8",
+      "from": "source-list-map@>=0.1.7 <0.2.0",
+      "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-0.1.8.tgz"
+    },
+    "source-map": {
+      "version": "0.5.6",
+      "from": "source-map@>=0.5.0 <0.6.0",
+      "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz"
+    },
+    "source-map-support": {
+      "version": "0.4.11",
+      "from": "source-map-support@>=0.4.2 <0.5.0",
+      "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.11.tgz"
+    },
+    "sparkles": {
+      "version": "1.0.0",
+      "from": "sparkles@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.0.tgz"
+    },
+    "spdx-correct": {
+      "version": "1.0.2",
+      "from": "spdx-correct@>=1.0.0 <1.1.0",
+      "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz"
+    },
+    "spdx-expression-parse": {
+      "version": "1.0.4",
+      "from": "spdx-expression-parse@>=1.0.0 <1.1.0",
+      "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz"
+    },
+    "spdx-license-ids": {
+      "version": "1.2.2",
+      "from": "spdx-license-ids@>=1.0.2 <2.0.0",
+      "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz"
+    },
+    "sprintf": {
+      "version": "0.1.5",
+      "from": "sprintf@>=0.1.5 <0.2.0",
+      "resolved": "https://registry.npmjs.org/sprintf/-/sprintf-0.1.5.tgz"
+    },
+    "sprintf-js": {
+      "version": "1.0.3",
+      "from": "sprintf-js@>=1.0.2 <1.1.0",
+      "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz"
+    },
+    "sshpk": {
+      "version": "1.10.2",
+      "from": "sshpk@>=1.7.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.10.2.tgz",
+      "dependencies": {
+        "assert-plus": {
+          "version": "1.0.0",
+          "from": "assert-plus@>=1.0.0 <2.0.0",
+          "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz"
+        }
+      }
+    },
+    "statuses": {
+      "version": "1.3.1",
+      "from": "statuses@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz"
+    },
+    "stdout-stream": {
+      "version": "1.4.0",
+      "from": "stdout-stream@>=1.4.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/stdout-stream/-/stdout-stream-1.4.0.tgz",
+      "dependencies": {
+        "isarray": {
+          "version": "1.0.0",
+          "from": "isarray@>=1.0.0 <1.1.0",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz"
+        },
+        "readable-stream": {
+          "version": "2.2.2",
+          "from": "readable-stream@>=2.0.1 <3.0.0",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.2.tgz"
+        }
+      }
+    },
+    "stream-browserify": {
+      "version": "2.0.1",
+      "from": "stream-browserify@>=2.0.1 <3.0.0",
+      "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.1.tgz",
+      "dependencies": {
+        "isarray": {
+          "version": "1.0.0",
+          "from": "isarray@~1.0.0",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz"
+        },
+        "readable-stream": {
+          "version": "2.2.3",
+          "from": "readable-stream@^2.0.2",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.3.tgz"
+        }
+      }
+    },
+    "stream-connect": {
+      "version": "1.0.2",
+      "from": "stream-connect@>=1.0.1 <2.0.0",
+      "resolved": "https://registry.npmjs.org/stream-connect/-/stream-connect-1.0.2.tgz"
+    },
+    "stream-consume": {
+      "version": "0.1.0",
+      "from": "stream-consume@>=0.1.0 <0.2.0",
+      "resolved": "https://registry.npmjs.org/stream-consume/-/stream-consume-0.1.0.tgz"
+    },
+    "stream-http": {
+      "version": "2.6.3",
+      "from": "stream-http@>=2.3.1 <3.0.0",
+      "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.6.3.tgz",
+      "dependencies": {
+        "isarray": {
+          "version": "1.0.0",
+          "from": "isarray@~1.0.0",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz"
+        },
+        "readable-stream": {
+          "version": "2.2.3",
+          "from": "readable-stream@^2.1.0",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.3.tgz"
+        }
+      }
+    },
+    "stream-via": {
+      "version": "0.1.1",
+      "from": "stream-via@>=0.1.0 <0.2.0",
+      "resolved": "https://registry.npmjs.org/stream-via/-/stream-via-0.1.1.tgz"
+    },
+    "streamsearch": {
+      "version": "0.1.2",
+      "from": "streamsearch@0.1.2",
+      "resolved": "https://registry.npmjs.org/streamsearch/-/streamsearch-0.1.2.tgz"
+    },
+    "string_decoder": {
+      "version": "0.10.31",
+      "from": "string_decoder@>=0.10.0 <0.11.0",
+      "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz"
+    },
+    "string-length": {
+      "version": "1.0.1",
+      "from": "string-length@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/string-length/-/string-length-1.0.1.tgz"
+    },
+    "string-template": {
+      "version": "1.0.0",
+      "from": "string-template@>=1.0.0 <1.1.0",
+      "resolved": "https://registry.npmjs.org/string-template/-/string-template-1.0.0.tgz"
+    },
+    "string-width": {
+      "version": "1.0.2",
+      "from": "string-width@>=1.0.1 <2.0.0",
+      "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz"
+    },
+    "stringstream": {
+      "version": "0.0.5",
+      "from": "stringstream@>=0.0.4 <0.1.0",
+      "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz"
+    },
+    "strip-ansi": {
+      "version": "3.0.1",
+      "from": "strip-ansi@>=3.0.0 <4.0.0",
+      "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz"
+    },
+    "strip-bom": {
+      "version": "1.0.0",
+      "from": "strip-bom@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-1.0.0.tgz"
+    },
+    "strip-bom-stream": {
+      "version": "2.0.0",
+      "from": "strip-bom-stream@>=2.0.0 <3.0.0",
+      "resolved": "https://registry.npmjs.org/strip-bom-stream/-/strip-bom-stream-2.0.0.tgz",
+      "dependencies": {
+        "first-chunk-stream": {
+          "version": "2.0.0",
+          "from": "first-chunk-stream@>=2.0.0 <3.0.0",
+          "resolved": "https://registry.npmjs.org/first-chunk-stream/-/first-chunk-stream-2.0.0.tgz"
+        },
+        "isarray": {
+          "version": "1.0.0",
+          "from": "isarray@>=1.0.0 <1.1.0",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz"
+        },
+        "readable-stream": {
+          "version": "2.2.2",
+          "from": "readable-stream@>=2.0.2 <3.0.0",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.2.tgz"
+        },
+        "strip-bom": {
+          "version": "2.0.0",
+          "from": "strip-bom@>=2.0.0 <3.0.0",
+          "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz"
+        }
+      }
+    },
+    "strip-indent": {
+      "version": "1.0.1",
+      "from": "strip-indent@>=1.0.1 <2.0.0",
+      "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz"
+    },
+    "strip-json-comments": {
+      "version": "1.0.4",
+      "from": "strip-json-comments@>=1.0.0 <1.1.0",
+      "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz"
+    },
+    "supports-color": {
+      "version": "2.0.0",
+      "from": "supports-color@>=2.0.0 <3.0.0",
+      "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz"
+    },
+    "swig": {
+      "version": "1.4.2",
+      "from": "swig@>=1.4.0 <1.5.0",
+      "resolved": "https://registry.npmjs.org/swig/-/swig-1.4.2.tgz",
+      "dependencies": {
+        "async": {
+          "version": "0.2.10",
+          "from": "async@>=0.2.6 <0.3.0",
+          "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz"
+        },
+        "source-map": {
+          "version": "0.1.34",
+          "from": "source-map@0.1.34",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.34.tgz"
+        },
+        "uglify-js": {
+          "version": "2.4.24",
+          "from": "uglify-js@>=2.4.0 <2.5.0",
+          "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.4.24.tgz"
+        },
+        "window-size": {
+          "version": "0.1.0",
+          "from": "window-size@0.1.0",
+          "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz"
+        },
+        "wordwrap": {
+          "version": "0.0.2",
+          "from": "wordwrap@0.0.2",
+          "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz"
+        },
+        "yargs": {
+          "version": "3.5.4",
+          "from": "yargs@>=3.5.4 <3.6.0",
+          "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.5.4.tgz"
+        }
+      }
+    },
+    "tapable": {
+      "version": "0.2.6",
+      "from": "tapable@>=0.2.5 <0.3.0",
+      "resolved": "https://registry.npmjs.org/tapable/-/tapable-0.2.6.tgz"
+    },
+    "tar": {
+      "version": "2.2.1",
+      "from": "tar@>=2.0.0 <3.0.0",
+      "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.1.tgz"
+    },
+    "temp-write": {
+      "version": "0.1.1",
+      "from": "temp-write@>=0.1.0 <0.2.0",
+      "resolved": "https://registry.npmjs.org/temp-write/-/temp-write-0.1.1.tgz",
+      "dependencies": {
+        "graceful-fs": {
+          "version": "2.0.3",
+          "from": "graceful-fs@>=2.0.0 <2.1.0",
+          "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-2.0.3.tgz"
+        }
+      }
+    },
+    "tempfile": {
+      "version": "0.1.3",
+      "from": "tempfile@>=0.1.2 <0.2.0",
+      "resolved": "https://registry.npmjs.org/tempfile/-/tempfile-0.1.3.tgz"
+    },
+    "test-value": {
+      "version": "1.1.0",
+      "from": "test-value@>=1.1.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/test-value/-/test-value-1.1.0.tgz"
+    },
+    "text-table": {
+      "version": "0.2.0",
+      "from": "text-table@>=0.2.0 <0.3.0",
+      "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz"
+    },
+    "through": {
+      "version": "2.3.8",
+      "from": "through@>=2.3.4 <2.4.0",
+      "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz"
+    },
+    "through2": {
+      "version": "2.0.3",
+      "from": "through2@>=2.0.0 <3.0.0",
+      "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.3.tgz",
+      "dependencies": {
+        "isarray": {
+          "version": "1.0.0",
+          "from": "isarray@>=1.0.0 <1.1.0",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz"
+        },
+        "readable-stream": {
+          "version": "2.2.2",
+          "from": "readable-stream@>=2.1.5 <3.0.0",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.2.tgz"
+        }
+      }
+    },
+    "tildify": {
+      "version": "1.2.0",
+      "from": "tildify@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/tildify/-/tildify-1.2.0.tgz"
+    },
+    "time-stamp": {
+      "version": "1.0.1",
+      "from": "time-stamp@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.0.1.tgz"
+    },
+    "timers-browserify": {
+      "version": "2.0.2",
+      "from": "timers-browserify@>=2.0.2 <3.0.0",
+      "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.2.tgz"
+    },
+    "to-array": {
+      "version": "0.1.3",
+      "from": "to-array@0.1.3",
+      "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.3.tgz"
+    },
+    "to-arraybuffer": {
+      "version": "1.0.1",
+      "from": "to-arraybuffer@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz"
+    },
+    "to-fast-properties": {
+      "version": "1.0.2",
+      "from": "to-fast-properties@>=1.0.1 <2.0.0",
+      "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.2.tgz"
+    },
+    "to-iso-string": {
+      "version": "0.0.2",
+      "from": "to-iso-string@0.0.2",
+      "resolved": "https://registry.npmjs.org/to-iso-string/-/to-iso-string-0.0.2.tgz"
+    },
+    "tough-cookie": {
+      "version": "2.3.2",
+      "from": "tough-cookie@>=2.3.0 <2.4.0",
+      "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.2.tgz"
+    },
+    "trim-newlines": {
+      "version": "1.0.0",
+      "from": "trim-newlines@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz"
+    },
+    "tsscmp": {
+      "version": "1.0.5",
+      "from": "tsscmp@1.0.5",
+      "resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.5.tgz"
+    },
+    "tty-browserify": {
+      "version": "0.0.0",
+      "from": "tty-browserify@0.0.0",
+      "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz"
+    },
+    "tunnel-agent": {
+      "version": "0.4.3",
+      "from": "tunnel-agent@>=0.4.1 <0.5.0",
+      "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.3.tgz"
+    },
+    "tweetnacl": {
+      "version": "0.14.5",
+      "from": "tweetnacl@>=0.14.0 <0.15.0",
+      "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
+      "optional": true
+    },
+    "type-check": {
+      "version": "0.3.2",
+      "from": "type-check@>=0.3.1 <0.4.0",
+      "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz"
+    },
+    "type-detect": {
+      "version": "0.1.1",
+      "from": "type-detect@0.1.1",
+      "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-0.1.1.tgz",
+      "dev": true
+    },
+    "type-is": {
+      "version": "1.6.14",
+      "from": "type-is@>=1.6.10 <1.7.0",
+      "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.14.tgz"
+    },
+    "typedarray": {
+      "version": "0.0.6",
+      "from": "typedarray@>=0.0.5 <0.1.0",
+      "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz"
+    },
+    "typical": {
+      "version": "2.6.0",
+      "from": "typical@>=2.3.0 <3.0.0",
+      "resolved": "https://registry.npmjs.org/typical/-/typical-2.6.0.tgz"
+    },
+    "ua-parser-js": {
+      "version": "0.7.12",
+      "from": "ua-parser-js@>=0.7.9 <0.8.0",
+      "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.12.tgz"
+    },
+    "uglify-js": {
+      "version": "2.7.5",
+      "from": "uglify-js@>=2.6.0 <3.0.0",
+      "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.7.5.tgz",
+      "dependencies": {
+        "async": {
+          "version": "0.2.10",
+          "from": "async@>=0.2.6 <0.3.0",
+          "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz"
+        },
+        "cliui": {
+          "version": "2.1.0",
+          "from": "cliui@>=2.1.0 <3.0.0",
+          "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz"
+        },
+        "window-size": {
+          "version": "0.1.0",
+          "from": "window-size@0.1.0",
+          "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz"
+        },
+        "wordwrap": {
+          "version": "0.0.2",
+          "from": "wordwrap@0.0.2",
+          "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz"
+        },
+        "yargs": {
+          "version": "3.10.0",
+          "from": "yargs@>=3.10.0 <3.11.0",
+          "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz"
+        }
+      }
+    },
+    "uglify-save-license": {
+      "version": "0.4.1",
+      "from": "uglify-save-license@>=0.4.1 <0.5.0",
+      "resolved": "https://registry.npmjs.org/uglify-save-license/-/uglify-save-license-0.4.1.tgz"
+    },
+    "uglify-to-browserify": {
+      "version": "1.0.2",
+      "from": "uglify-to-browserify@>=1.0.0 <1.1.0",
+      "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz"
+    },
+    "uid-safe": {
+      "version": "2.1.3",
+      "from": "uid-safe@>=2.1.3 <2.2.0",
+      "resolved": "https://registry.npmjs.org/uid-safe/-/uid-safe-2.1.3.tgz"
+    },
+    "ultron": {
+      "version": "1.0.2",
+      "from": "ultron@>=1.0.0 <1.1.0",
+      "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.0.2.tgz"
+    },
+    "unc-path-regex": {
+      "version": "0.1.2",
+      "from": "unc-path-regex@>=0.1.0 <0.2.0",
+      "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz"
+    },
+    "underscore": {
+      "version": "1.7.0",
+      "from": "underscore@>=1.7.0 <1.8.0",
+      "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.7.0.tgz"
+    },
+    "unique-stream": {
+      "version": "1.0.0",
+      "from": "unique-stream@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-1.0.0.tgz"
+    },
+    "unpipe": {
+      "version": "1.0.0",
+      "from": "unpipe@1.0.0",
+      "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz"
+    },
+    "url": {
+      "version": "0.10.3",
+      "from": "url@0.10.3",
+      "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz",
+      "dependencies": {
+        "punycode": {
+          "version": "1.3.2",
+          "from": "punycode@1.3.2",
+          "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz"
+        }
+      }
+    },
+    "user-home": {
+      "version": "1.1.1",
+      "from": "user-home@>=1.1.1 <2.0.0",
+      "resolved": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz"
+    },
+    "utf-8-validate": {
+      "version": "1.2.2",
+      "from": "utf-8-validate@>=1.2.0 <1.3.0",
+      "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-1.2.2.tgz",
+      "optional": true,
+      "dependencies": {
+        "nan": {
+          "version": "2.4.0",
+          "from": "nan@>=2.4.0 <2.5.0",
+          "resolved": "https://registry.npmjs.org/nan/-/nan-2.4.0.tgz",
+          "optional": true
+        }
+      }
+    },
+    "utf8": {
+      "version": "2.1.0",
+      "from": "utf8@2.1.0",
+      "resolved": "https://registry.npmjs.org/utf8/-/utf8-2.1.0.tgz"
+    },
+    "util": {
+      "version": "0.10.3",
+      "from": "util@>=0.10.3 <0.11.0",
+      "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz",
+      "dependencies": {
+        "inherits": {
+          "version": "2.0.1",
+          "from": "inherits@2.0.1",
+          "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz"
+        }
+      }
+    },
+    "util-deprecate": {
+      "version": "1.0.2",
+      "from": "util-deprecate@>=1.0.1 <1.1.0",
+      "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz"
+    },
+    "utils-merge": {
+      "version": "1.0.0",
+      "from": "utils-merge@1.0.0",
+      "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.0.tgz"
+    },
+    "uuid": {
+      "version": "1.4.2",
+      "from": "uuid@>=1.4.0 <1.5.0",
+      "resolved": "https://registry.npmjs.org/uuid/-/uuid-1.4.2.tgz"
+    },
+    "v8flags": {
+      "version": "2.0.11",
+      "from": "v8flags@>=2.0.2 <3.0.0",
+      "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-2.0.11.tgz"
+    },
+    "validate-npm-package-license": {
+      "version": "3.0.1",
+      "from": "validate-npm-package-license@>=3.0.1 <4.0.0",
+      "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz"
+    },
+    "validator": {
+      "version": "2.1.0",
+      "from": "validator@>=2.1.0 <3.0.0",
+      "resolved": "https://registry.npmjs.org/validator/-/validator-2.1.0.tgz"
+    },
+    "vary": {
+      "version": "1.1.0",
+      "from": "vary@>=1.1.0 <1.2.0",
+      "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.0.tgz"
+    },
+    "verror": {
+      "version": "1.3.6",
+      "from": "verror@1.3.6",
+      "resolved": "https://registry.npmjs.org/verror/-/verror-1.3.6.tgz"
+    },
+    "vinyl": {
+      "version": "0.5.3",
+      "from": "vinyl@>=0.5.0 <0.6.0",
+      "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.5.3.tgz"
+    },
+    "vinyl-file": {
+      "version": "2.0.0",
+      "from": "vinyl-file@>=2.0.0 <3.0.0",
+      "resolved": "https://registry.npmjs.org/vinyl-file/-/vinyl-file-2.0.0.tgz",
+      "dependencies": {
+        "graceful-fs": {
+          "version": "4.1.11",
+          "from": "graceful-fs@>=4.1.2 <5.0.0",
+          "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz"
+        },
+        "strip-bom": {
+          "version": "2.0.0",
+          "from": "strip-bom@>=2.0.0 <3.0.0",
+          "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz"
+        },
+        "vinyl": {
+          "version": "1.2.0",
+          "from": "vinyl@>=1.1.0 <2.0.0",
+          "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-1.2.0.tgz"
+        }
+      }
+    },
+    "vinyl-fs": {
+      "version": "0.3.14",
+      "from": "vinyl-fs@>=0.3.0 <0.4.0",
+      "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-0.3.14.tgz",
+      "dependencies": {
+        "clone": {
+          "version": "0.2.0",
+          "from": "clone@>=0.2.0 <0.3.0",
+          "resolved": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz"
+        },
+        "readable-stream": {
+          "version": "1.0.34",
+          "from": "readable-stream@>=1.0.33-1 <1.1.0-0",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz"
+        },
+        "through2": {
+          "version": "0.6.5",
+          "from": "through2@>=0.6.1 <0.7.0",
+          "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz"
+        },
+        "vinyl": {
+          "version": "0.4.6",
+          "from": "vinyl@>=0.4.0 <0.5.0",
+          "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz"
+        }
+      }
+    },
+    "vinyl-source-stream": {
+      "version": "1.1.0",
+      "from": "vinyl-source-stream@>=1.1.0 <1.2.0",
+      "resolved": "https://registry.npmjs.org/vinyl-source-stream/-/vinyl-source-stream-1.1.0.tgz",
+      "dependencies": {
+        "clone": {
+          "version": "0.2.0",
+          "from": "clone@>=0.2.0 <0.3.0",
+          "resolved": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz"
+        },
+        "readable-stream": {
+          "version": "1.0.34",
+          "from": "readable-stream@>=1.0.33-1 <1.1.0-0",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz"
+        },
+        "through2": {
+          "version": "0.6.5",
+          "from": "through2@>=0.6.1 <0.7.0",
+          "resolved": "https://registry.npmjs.org/through2/-/through2-0.6.5.tgz"
+        },
+        "vinyl": {
+          "version": "0.4.6",
+          "from": "vinyl@>=0.4.3 <0.5.0",
+          "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz"
+        }
+      }
+    },
+    "vinyl-sourcemaps-apply": {
+      "version": "0.2.1",
+      "from": "vinyl-sourcemaps-apply@>=0.2.0 <0.3.0",
+      "resolved": "https://registry.npmjs.org/vinyl-sourcemaps-apply/-/vinyl-sourcemaps-apply-0.2.1.tgz"
+    },
+    "vm-browserify": {
+      "version": "0.0.4",
+      "from": "vm-browserify@0.0.4",
+      "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz"
+    },
+    "ware": {
+      "version": "1.3.0",
+      "from": "ware@>=1.3.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/ware/-/ware-1.3.0.tgz"
+    },
+    "watchpack": {
+      "version": "1.3.1",
+      "from": "watchpack@>=1.2.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.3.1.tgz",
+      "dependencies": {
+        "async": {
+          "version": "2.1.5",
+          "from": "async@^2.1.2",
+          "resolved": "https://registry.npmjs.org/async/-/async-2.1.5.tgz"
+        },
+        "graceful-fs": {
+          "version": "4.1.11",
+          "from": "graceful-fs@>=4.1.2 <5.0.0",
+          "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz"
+        },
+        "lodash": {
+          "version": "4.17.4",
+          "from": "lodash@^4.14.0",
+          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz"
+        }
+      }
+    },
+    "webpack": {
+      "version": "2.2.1",
+      "from": "webpack@>=2.2.0 <2.3.0",
+      "resolved": "https://registry.npmjs.org/webpack/-/webpack-2.2.1.tgz",
+      "dependencies": {
+        "async": {
+          "version": "2.1.5",
+          "from": "async@>=2.1.2 <3.0.0",
+          "resolved": "https://registry.npmjs.org/async/-/async-2.1.5.tgz"
+        },
+        "camelcase": {
+          "version": "3.0.0",
+          "from": "camelcase@>=3.0.0 <4.0.0",
+          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz"
+        },
+        "lodash": {
+          "version": "4.17.4",
+          "from": "lodash@^4.14.0",
+          "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz"
+        },
+        "supports-color": {
+          "version": "3.2.3",
+          "from": "supports-color@>=3.1.0 <4.0.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz"
+        },
+        "yargs": {
+          "version": "6.6.0",
+          "from": "yargs@>=6.0.0 <7.0.0",
+          "resolved": "https://registry.npmjs.org/yargs/-/yargs-6.6.0.tgz"
+        },
+        "yargs-parser": {
+          "version": "4.2.1",
+          "from": "yargs-parser@>=4.2.0 <5.0.0",
+          "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-4.2.1.tgz"
+        }
+      }
+    },
+    "webpack-core": {
+      "version": "0.6.9",
+      "from": "webpack-core@>=0.6.0 <0.7.0",
+      "resolved": "https://registry.npmjs.org/webpack-core/-/webpack-core-0.6.9.tgz",
+      "dependencies": {
+        "source-map": {
+          "version": "0.4.4",
+          "from": "source-map@>=0.4.1 <0.5.0",
+          "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz"
+        }
+      }
+    },
+    "webpack-manifest-plugin": {
+      "version": "1.1.0",
+      "from": "webpack-manifest-plugin@>=1.1.0 <1.2.0",
+      "resolved": "https://registry.npmjs.org/webpack-manifest-plugin/-/webpack-manifest-plugin-1.1.0.tgz"
+    },
+    "webpack-sources": {
+      "version": "0.1.5",
+      "from": "webpack-sources@>=0.1.4 <0.2.0",
+      "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-0.1.5.tgz"
+    },
+    "webpack-stream": {
+      "version": "3.2.0",
+      "from": "webpack-stream@>=3.2.0 <3.3.0",
+      "resolved": "https://registry.npmjs.org/webpack-stream/-/webpack-stream-3.2.0.tgz",
+      "dependencies": {
+        "acorn": {
+          "version": "3.3.0",
+          "from": "acorn@>=3.0.0 <4.0.0",
+          "resolved": "https://registry.npmjs.org/acorn/-/acorn-3.3.0.tgz"
+        },
+        "browserify-aes": {
+          "version": "0.4.0",
+          "from": "browserify-aes@0.4.0",
+          "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-0.4.0.tgz"
+        },
+        "crypto-browserify": {
+          "version": "3.3.0",
+          "from": "crypto-browserify@3.3.0",
+          "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.3.0.tgz"
+        },
+        "enhanced-resolve": {
+          "version": "0.9.1",
+          "from": "enhanced-resolve@>=0.9.0 <0.10.0",
+          "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-0.9.1.tgz",
+          "dependencies": {
+            "memory-fs": {
+              "version": "0.2.0",
+              "from": "memory-fs@>=0.2.0 <0.3.0",
+              "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.2.0.tgz"
+            }
+          }
+        },
+        "graceful-fs": {
+          "version": "4.1.11",
+          "from": "graceful-fs@^4.1.2",
+          "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz"
+        },
+        "interpret": {
+          "version": "0.6.6",
+          "from": "interpret@>=0.6.4 <0.7.0",
+          "resolved": "https://registry.npmjs.org/interpret/-/interpret-0.6.6.tgz"
+        },
+        "isarray": {
+          "version": "1.0.0",
+          "from": "isarray@~1.0.0",
+          "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz"
+        },
+        "memory-fs": {
+          "version": "0.3.0",
+          "from": "memory-fs@>=0.3.0 <0.4.0",
+          "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.3.0.tgz"
+        },
+        "node-libs-browser": {
+          "version": "0.7.0",
+          "from": "node-libs-browser@>=0.7.0 <0.8.0",
+          "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-0.7.0.tgz"
+        },
+        "readable-stream": {
+          "version": "2.2.3",
+          "from": "readable-stream@^2.0.1",
+          "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.2.3.tgz"
+        },
+        "ripemd160": {
+          "version": "0.2.0",
+          "from": "ripemd160@0.2.0",
+          "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-0.2.0.tgz"
+        },
+        "sha.js": {
+          "version": "2.2.6",
+          "from": "sha.js@2.2.6",
+          "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.2.6.tgz"
+        },
+        "supports-color": {
+          "version": "3.2.3",
+          "from": "supports-color@^3.1.0",
+          "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz"
+        },
+        "tapable": {
+          "version": "0.1.10",
+          "from": "tapable@>=0.1.8 <0.2.0",
+          "resolved": "https://registry.npmjs.org/tapable/-/tapable-0.1.10.tgz"
+        },
+        "url": {
+          "version": "0.11.0",
+          "from": "url@^0.11.0",
+          "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz",
+          "dependencies": {
+            "punycode": {
+              "version": "1.3.2",
+              "from": "punycode@1.3.2",
+              "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz"
+            }
+          }
+        },
+        "vinyl": {
+          "version": "1.2.0",
+          "from": "vinyl@>=1.1.0 <2.0.0",
+          "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-1.2.0.tgz"
+        },
+        "watchpack": {
+          "version": "0.2.9",
+          "from": "watchpack@>=0.2.1 <0.3.0",
+          "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-0.2.9.tgz",
+          "dependencies": {
+            "async": {
+              "version": "0.9.2",
+              "from": "async@>=0.9.0 <0.10.0",
+              "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz"
+            }
+          }
+        },
+        "webpack": {
+          "version": "1.14.0",
+          "from": "webpack@>=1.12.9 <2.0.0",
+          "resolved": "https://registry.npmjs.org/webpack/-/webpack-1.14.0.tgz"
+        }
+      }
+    },
+    "whatwg-fetch": {
+      "version": "2.0.2",
+      "from": "whatwg-fetch@>=2.0.1 <3.0.0",
+      "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-2.0.2.tgz"
+    },
+    "which": {
+      "version": "1.2.12",
+      "from": "which@>=1.2.12 <2.0.0",
+      "resolved": "https://registry.npmjs.org/which/-/which-1.2.12.tgz"
+    },
+    "which-module": {
+      "version": "1.0.0",
+      "from": "which-module@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz"
+    },
+    "wide-align": {
+      "version": "1.1.0",
+      "from": "wide-align@>=1.1.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.0.tgz"
+    },
+    "window-size": {
+      "version": "0.1.4",
+      "from": "window-size@>=0.1.2 <0.2.0",
+      "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.4.tgz"
+    },
+    "wordwrap": {
+      "version": "1.0.0",
+      "from": "wordwrap@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz"
+    },
+    "wordwrapjs": {
+      "version": "1.2.1",
+      "from": "wordwrapjs@>=1.2.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/wordwrapjs/-/wordwrapjs-1.2.1.tgz"
+    },
+    "wrap-ansi": {
+      "version": "2.1.0",
+      "from": "wrap-ansi@>=2.0.0 <3.0.0",
+      "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz"
+    },
+    "wrap-fn": {
+      "version": "0.1.5",
+      "from": "wrap-fn@>=0.1.0 <0.2.0",
+      "resolved": "https://registry.npmjs.org/wrap-fn/-/wrap-fn-0.1.5.tgz"
+    },
+    "wrappy": {
+      "version": "1.0.2",
+      "from": "wrappy@>=1.0.0 <2.0.0",
+      "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz"
+    },
+    "ws": {
+      "version": "1.1.1",
+      "from": "ws@>=1.0.1 <2.0.0",
+      "resolved": "https://registry.npmjs.org/ws/-/ws-1.1.1.tgz"
+    },
+    "xml2js": {
+      "version": "0.4.15",
+      "from": "xml2js@0.4.15",
+      "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.15.tgz"
+    },
+    "xmlbuilder": {
+      "version": "2.6.2",
+      "from": "xmlbuilder@2.6.2",
+      "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-2.6.2.tgz"
+    },
+    "xmlhttprequest": {
+      "version": "1.5.0",
+      "from": "https://github.com/rase-/node-XMLHttpRequest/archive/a6b6f2.tar.gz",
+      "resolved": "https://github.com/rase-/node-XMLHttpRequest/archive/a6b6f2.tar.gz"
+    },
+    "xtend": {
+      "version": "4.0.1",
+      "from": "xtend@>=4.0.0 <5.0.0",
+      "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz"
+    },
+    "y18n": {
+      "version": "3.2.1",
+      "from": "y18n@>=3.2.0 <4.0.0",
+      "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz"
+    },
+    "yallist": {
+      "version": "2.0.0",
+      "from": "yallist@>=2.0.0 <3.0.0",
+      "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.0.0.tgz"
+    },
+    "yargs": {
+      "version": "3.29.0",
+      "from": "yargs@3.29.0",
+      "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.29.0.tgz"
+    },
+    "yargs-parser": {
+      "version": "2.4.1",
+      "from": "yargs-parser@>=2.4.1 <3.0.0",
+      "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-2.4.1.tgz",
+      "dependencies": {
+        "camelcase": {
+          "version": "3.0.0",
+          "from": "camelcase@>=3.0.0 <4.0.0",
+          "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz"
+        }
+      }
+    }
+  }
+}

+ 32 - 29
package.json

@@ -1,6 +1,6 @@
 {
   "name": "crowi",
-  "version": "1.5.2",
+  "version": "1.6.0",
   "description": "The simple & powerful Wiki",
   "tags": [
     "wiki",
@@ -24,19 +24,18 @@
     "url": "https://github.com/crowi/crowi.git"
   },
   "engines": {
-    "node": "4.x",
-    "npm": "3.x"
+    "node": "6.x",
+    "npm": "4.x"
   },
   "dependencies": {
     "async": "~1.5.0",
     "aws-sdk": "~2.2.26",
-    "axios": "0.13.x",
+    "axios": "0.15.x",
     "babel-core": "~6.7.6",
-    "babel-loader": "~6.2.4",
-    "babel-preset-es2015": "~6.6.0",
-    "babel-preset-react": "~6.5.0",
+    "babel-loader": "~6.3.0",
+    "babel-preset-es2015": "~6.22.0",
+    "babel-preset-react": "~6.23.0",
     "basic-auth-connect": "~1.0.0",
-    "bluebird": "~3.0.5",
     "body-parser": "~1.14.1",
     "bootstrap-sass": "~3.3.6",
     "botkit": "~0.1.1",
@@ -45,58 +44,62 @@
     "commander": "~2.9.0",
     "connect-flash": "~0.1.1",
     "connect-redis": "~2.1.0",
-    "consolidate": "~0.11.0",
+    "consolidate": "~0.14.0",
     "cookie-parser": "~1.3.4",
     "csrf": "~3.0.3",
     "debug": "~2.2.0",
     "del": "~2.2.0",
-    "diff": "~2.2.2",
-    "elasticsearch": "~11.0.1",
+    "diff": "~3.2.0",
+    "diff2html": "~2.0.12",
+    "elasticsearch": "^12.1.3",
     "emojify.js": "^1.1.0",
     "errorhandler": "~1.3.4",
-    "express": "~4.13.3",
+    "express": "~4.14.0",
     "express-form": "~0.12.0",
-    "express-session": "~1.12.0",
-    "font-awesome": "~4.5.0",
+    "express-session": "~1.14.0",
+    "font-awesome": "~4.7.0",
     "googleapis": "=12.3.0",
     "gulp": "~3.9.0",
     "gulp-concat": "~2.6.0",
     "gulp-cssmin": "~0.1.7",
     "gulp-jshint": "~1.12.0",
     "gulp-rename": "~1.2.2",
-    "gulp-sass": "~2.1.0",
+    "gulp-sass": "~3.1.0",
     "gulp-spawn-mocha": "~2.2.1",
     "gulp-uglify": "~1.4.2",
     "gulp-watch": "~4.3.5",
-    "highlight.js": "~9.0.0",
-    "inline-attachment": "git+https://github.com/Rovak/InlineAttachment.git#2.0.2",
+    "highlight.js": "~9.9.0",
+    "i18next": "~4.1.0",
+    "i18next-express-middleware": "~1.0.2",
+    "i18next-node-fs-backend": "~0.1.3",
+    "i18next-sprintf-postprocessor": "~0.2.2",
+    "inline-attachment": "git+https://github.com/Rovak/InlineAttachment.git#2.0.3",
     "jquery": "~2.1.4",
     "jquery.cookie": "~1.4.1",
     "jshint-stylish": "~2.1.0",
-    "kerberos": "0.0.17",
+    "kerberos": "0.0.22",
     "marked": "~0.3.5",
     "method-override": "~2.3.1",
     "mkdirp": "~0.5.1",
     "moment": "~2.13.0",
-    "mongoose": "4.2.5",
-    "mongoose-paginate": "4.2.0",
-    "morgan": "~1.5.1",
-    "multer": "~0.1.8",
-    "nodemailer": "~1.2.2",
-    "nodemailer-ses-transport": "~1.1.0",
+    "mongoose": "4.7.x",
+    "mongoose-paginate": "5.0.x",
+    "morgan": "~1.7.0",
+    "multer": "~1.2.1",
+    "nodemailer": "~2.7.0",
+    "nodemailer-ses-transport": "~1.5.0",
     "react": "~15.0.1",
     "react-dom": "~15.0.1",
-    "redis": "~0.12.1",
+    "redis": "~2.6.5",
     "reveal.js": "~3.2.0",
     "socket.io": "~1.3.0",
     "socket.io-client": "~1.3.0",
     "sprintf": "~0.1.5",
     "swig": "~1.4.0",
-    "time": "~0.11.0",
     "vinyl-source-stream": "~1.1.0",
-    "webpack": "~1.13.0",
-    "webpack-manifest-plugin": "~1.0.1",
-    "webpack-stream": "~3.1.0"
+    "webpack": "~2.2.0",
+    "webpack-manifest-plugin": "~1.1.0",
+    "webpack-stream": "~3.2.0"
   },
   "devDependencies": {
     "chai": "~1.10.0",

BIN
public/android-chrome-192x192.png


BIN
public/apple-touch-icon-114x114-precomposed.png


BIN
public/apple-touch-icon-120x120.png


BIN
public/apple-touch-icon-180x180.png


BIN
public/apple-touch-icon-57x57-precomposed.png


BIN
public/apple-touch-icon-72x72-precomposed.png


BIN
public/apple-touch-icon-72x72.png


BIN
public/apple-touch-icon-precomposed.png


BIN
public/apple-touch-icon.png


+ 1 - 0
public/css/diff2html

@@ -0,0 +1 @@
+../../node_modules/diff2html/dist

BIN
public/favicon-16x16.png


BIN
public/favicon-32x32.png


BIN
public/favicon-96x96.png


BIN
public/favicon.ico


+ 24 - 7
public/nginx-mime.types

@@ -277,22 +277,39 @@
     .revision-hisory-outer {
       margin-top: 8px;
 
-      .picture {
-        float: left;
-        width: 32px;
-        height: 32px;
-      }
-
       .revision-history-main {
-        margin-left: 40px;
+
+        .picture {
+          float: left;
+          width: 32px;
+          height: 32px;
+        }
 
         .revision-history-author {
+          margin-left: 40px;
           color: #666;
         }
         .revision-history-comment {
+          margin-left: 40px;
         }
         .revision-history-meta {
+          margin-left: 40px;
+
+          p {
+            margin-bottom: 8px;
+          }
+
+          a {
+            margin-right: 8px;
+          }
+          a:hover {
+            cursor: pointer;
+          }
         }
+
+      }
+      .revision-history-diff {
+        margin-left: 40px;
       }
     }
 

+ 6 - 0
resource/css/crowi.scss

@@ -251,6 +251,12 @@ footer {
   border-radius: 3px;
 }
 
+// adjust
+// this is for diff2html. hide page name from diff view
+.d2h-file-header {
+  display: none;
+}
+
 // components
 .flip-container { // {{{
   perspective: 1000;

+ 18 - 2
resource/js/app.js

@@ -5,13 +5,22 @@ import Crowi from './util/Crowi';
 import CrowiRenderer from './util/CrowiRenderer';
 
 import HeaderSearchBox  from './components/HeaderSearchBox';
-import SearchPage  from './components/SearchPage';
-import PageListSearch  from './components/PageListSearch';
+import SearchPage       from './components/SearchPage';
+import PageListSearch   from './components/PageListSearch';
+import PageHistory      from './components/PageHistory';
+import SeenUserList     from './components/SeenUserList';
 //import PageComment  from './components/PageComment';
 
 if (!window) {
   window = {};
 }
+
+const mainContent = document.querySelector('#content-main');
+let pageId = null;
+if (mainContent !== null) {
+  pageId = mainContent.attributes['data-page-id'].value;
+}
+
 // FIXME
 const crowi = new Crowi({me: $('#content-main').data('current-username')}, window);
 window.crowi = crowi;
@@ -24,7 +33,9 @@ const componentMappings = {
   'search-top': <HeaderSearchBox />,
   'search-page': <SearchPage />,
   'page-list-search': <PageListSearch />,
+  //'revision-history': <PageHistory pageId={pageId} />,
   //'page-comment': <PageComment />,
+  'seen-user-list': <SeenUserList />,
 };
 
 Object.keys(componentMappings).forEach((key) => {
@@ -33,3 +44,8 @@ Object.keys(componentMappings).forEach((key) => {
     ReactDOM.render(componentMappings[key], elem);
   }
 });
+
+// うわーもうー
+$('a[data-toggle="tab"][href="#revision-history"]').on('show.bs.tab', function() {
+  ReactDOM.render(<PageHistory pageId={pageId} crowi={crowi} />, document.getElementById('revision-history'));
+});

+ 22 - 0
resource/js/components/Common/Icon.js

@@ -0,0 +1,22 @@
+import React from 'react';
+
+export default class Icon extends React.Component {
+
+  render() {
+    const name = this.props.name || null;
+
+    if (!name) {
+      return '';
+    }
+
+    return (
+      <i className={"fa fa-" + name} />
+    );
+  }
+}
+
+// TODO: support spin, size and so far
+Icon.propTypes = {
+  name: React.PropTypes.string.isRequired,
+};
+

+ 34 - 0
resource/js/components/Common/UserDate.js

@@ -0,0 +1,34 @@
+import React from 'react';
+
+import moment from 'moment';
+
+/**
+ * UserDate
+ *
+ * display date depends on user timezone of user settings
+ */
+export default class UserDate extends React.Component {
+
+  render() {
+    const dt = moment(this.props.dateTime).format(this.props.format);
+
+    return (
+      <span className={this.props.className}>
+        {dt}
+      </span>
+    );
+  }
+}
+
+UserDate.propTypes = {
+  dateTime: React.PropTypes.string.isRequired,
+  format: React.PropTypes.string,
+  className: React.PropTypes.string,
+};
+
+UserDate.defaultProps = {
+  dateTime: 'now',
+  format: 'YYYY/MM/DD HH:mm:ss',
+  className: '',
+};
+

+ 139 - 0
resource/js/components/PageHistory.js

@@ -0,0 +1,139 @@
+import React from 'react';
+
+import Icon from './Common/Icon';
+import PageRevisionList from './PageHistory/PageRevisionList';
+
+export default class PageHistory extends React.Component {
+
+  constructor(props) {
+    super(props);
+
+    this.state = {
+      revisions: [],
+      diffOpened: {},
+    };
+
+    this.getPreviousRevision = this.getPreviousRevision.bind(this);
+    this.onDiffOpenClicked = this.onDiffOpenClicked.bind(this);
+  }
+
+  componentDidMount() {
+    const pageId = this.props.pageId;
+
+    if (!pageId) {
+      return ;
+    }
+
+    this.props.crowi.apiGet('/revisions.ids', {page_id: pageId})
+    .then(res => {
+
+      const rev = res.revisions;
+      let diffOpened = {};
+      const lastId = rev.length - 1;
+      res.revisions.map((revision, i) => {
+        const user = this.props.crowi.findUserById(revision.author);
+        if (user) {
+          rev[i].author = user;
+        }
+
+        if (i === 0 || i === lastId) {
+          diffOpened[revision._id] = true;
+        } else {
+          diffOpened[revision._id] = false;
+        }
+      });
+
+      this.setState({
+        revisions: rev,
+        diffOpened: diffOpened,
+      });
+
+      // load 0, and last default
+      if (rev[0]) {
+        this.fetchPageRevisionBody(rev[0]);
+      }
+      if (rev[1]) {
+        this.fetchPageRevisionBody(rev[1]);
+      }
+      if (lastId !== 0 && lastId !== 1 && rev[lastId]) {
+        this.fetchPageRevisionBody(rev[lastId]);
+      }
+    }).catch(err => {
+      // do nothing
+    });
+  }
+
+  getPreviousRevision(currentRevision) {
+    let cursor = null;
+    for (let revision of this.state.revisions) {
+      if (cursor && cursor._id == currentRevision._id) {
+        cursor = revision;
+        break;
+      }
+
+      cursor = revision;
+    }
+
+    return cursor;
+  }
+
+  onDiffOpenClicked(revision) {
+    const diffOpened = this.state.diffOpened,
+      revisionId = revision._id;
+
+    if (diffOpened[revisionId]) {
+      return ;
+    }
+
+    diffOpened[revisionId] = true;
+    this.setState({
+      diffOpened
+    });
+
+    this.fetchPageRevisionBody(revision);
+    this.fetchPageRevisionBody(this.getPreviousRevision(revision));
+  }
+
+  fetchPageRevisionBody(revision) {
+    if (revision.body) {
+      return ;
+    }
+
+    this.props.crowi.apiGet('/revisions.get', {revision_id: revision._id})
+    .then(res => {
+      if (res.ok) {
+        this.setState({
+          revisions: this.state.revisions.map((rev) => {
+            if (rev._id == res.revision._id) {
+              return res.revision;
+            }
+
+            return rev;
+          })
+        })
+      }
+    }).catch(err => {
+
+    });
+
+  }
+
+  render() {
+    return (
+      <div>
+        <h1><Icon name="history" /> History</h1>
+        <PageRevisionList
+          revisions={this.state.revisions}
+          diffOpened={this.state.diffOpened}
+          getPreviousRevision={this.getPreviousRevision}
+          onDiffOpenClicked={this.onDiffOpenClicked}
+        />
+      </div>
+    );
+  }
+}
+
+PageHistory.propTypes = {
+  pageId: React.PropTypes.string,
+  crowi: React.PropTypes.object.isRequired,
+};

+ 54 - 0
resource/js/components/PageHistory/PageRevisionList.js

@@ -0,0 +1,54 @@
+import React from 'react';
+
+import Revision     from './Revision';
+import RevisionDiff from './RevisionDiff';
+
+export default class PageRevisionList extends React.Component {
+
+  render() {
+    const revisions = this.props.revisions,
+      revisionCount = this.props.revisions.length;
+
+    const revisionList = this.props.revisions.map((revision, idx) => {
+      const revisionId = revision._id
+        , revisionDiffOpened = this.props.diffOpened[revisionId] || false
+
+
+      let previousRevision;
+      if (idx+1 < revisionCount) {
+        previousRevision = revisions[idx + 1];
+      } else {
+        previousRevision = revision; // if it is the first revision, show full text as diff text
+      }
+
+      return (
+        <div className="revision-hisory-outer" key={"revision-history-" + revisionId}>
+          <Revision
+            revision={revision}
+            onDiffOpenClicked={this.props.onDiffOpenClicked}
+            key={"revision-history-rev-" + revisionId}
+            />
+          <RevisionDiff
+            revisionDiffOpened={revisionDiffOpened}
+            currentRevision={revision}
+            previousRevision={previousRevision}
+            key={"revision-diff-" + revisionId}
+          />
+        </div>
+      );
+    });
+
+    return (
+      <div className="revision-history-list">
+        {revisionList}
+      </div>
+    );
+  }
+}
+
+PageRevisionList.propTypes = {
+  revisions: React.PropTypes.array,
+  diffOpened: React.PropTypes.object,
+  onDiffOpenClicked: React.PropTypes.func.isRequired,
+}
+

+ 59 - 0
resource/js/components/PageHistory/Revision.js

@@ -0,0 +1,59 @@
+import React from 'react';
+
+import UserDate     from '../Common/UserDate';
+import Icon         from '../Common/Icon';
+import UserPicture  from '../User/UserPicture';
+
+export default class Revision extends React.Component {
+
+  constructor(props) {
+    super(props);
+
+    this._onDiffOpenClicked = this._onDiffOpenClicked.bind(this);
+  }
+
+  componentDidMount() {
+  }
+
+  _onDiffOpenClicked() {
+    this.props.onDiffOpenClicked(this.props.revision);
+  }
+
+  render() {
+    const revision = this.props.revision;
+    const author = revision.author;
+
+    let pic = '';
+    if (typeof author === 'object') {
+      pic = <UserPicture user={author} />;
+    }
+
+    return (
+      <div className="revision-history-main">
+        {pic}
+        <div className="revision-history-author">
+          <strong>{author.username}</strong>
+        </div>
+        <div className="revision-history-meta">
+          <p>
+            <UserDate dateTime={revision.createdAt} />
+          </p>
+          <p>
+            <a href={"?revision=" + revision._id }>
+              <Icon name="history" /> View this version
+            </a>
+            <a className="diff-view" onClick={this._onDiffOpenClicked}>
+              <Icon name="level-down" /> View diff
+            </a>
+          </p>
+        </div>
+      </div>
+    );
+  }
+}
+
+Revision.propTypes = {
+  revision: React.PropTypes.object,
+  onDiffOpenClicked: React.PropTypes.func.isRequired,
+}
+

+ 42 - 0
resource/js/components/PageHistory/RevisionDiff.js

@@ -0,0 +1,42 @@
+import React from 'react';
+
+import { createPatch } from 'diff';
+import { Diff2Html } from 'diff2html';
+
+export default class RevisionDiff extends React.Component {
+
+  render() {
+    const currentRevision = this.props.currentRevision,
+      previousRevision = this.props.previousRevision,
+      revisionDiffOpened = this.props.revisionDiffOpened;
+
+
+    let diffViewHTML = '';
+    if (currentRevision.body
+      && previousRevision.body
+      && revisionDiffOpened) {
+
+      let previousText = previousRevision.body;
+      if (currentRevision._id == previousRevision._id) {
+        previousText = '';
+      }
+
+      const patch = createPatch(
+        currentRevision.path,
+        previousText,
+        currentRevision.body
+      );
+
+      diffViewHTML = Diff2Html.getPrettyHtml(patch);
+    }
+
+    const diffView = {__html: diffViewHTML};
+    return <div className="revision-history-diff" dangerouslySetInnerHTML={diffView} />;
+  }
+}
+
+RevisionDiff.propTypes = {
+  currentRevision: React.PropTypes.object.isRequired,
+  previousRevision: React.PropTypes.object.isRequired,
+  revisionDiffOpened: React.PropTypes.bool.isRequired,
+}

+ 6 - 2
resource/js/components/SearchPage/SearchResultList.js

@@ -14,7 +14,12 @@ export default class SearchResultList extends React.Component {
     let returnBody = body;
 
     this.props.searchingKeyword.split(' ').forEach((keyword) => {
-      const k = keyword.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
+      if (keyword === '') {
+        return;
+      }
+      const k = keyword
+            .replace(/[.*+?^${}()|[\]\\]/g, "\\$&")
+            .replace(/(^"|"$)/g, ''); // for phrase (quoted) keyword
       const keywordExp = new RegExp(`(${k}(?!(.*?\]|.*?\\)|.*?"|.*?>)))`, 'ig');
       returnBody = returnBody.replace(keywordExp, '<em class="highlighted">$&</em>');
     });
@@ -53,4 +58,3 @@ SearchResultList.defaultProps = {
   pages: [],
   searchingKeyword: '',
 };
-

+ 53 - 0
resource/js/components/SeenUserList.js

@@ -0,0 +1,53 @@
+import React from 'react';
+import UserList from './SeenUserList/UserList';
+
+export default class SeenUserList extends React.Component {
+
+  constructor(props) {
+    super(props);
+
+    this.crowi = window.crowi; // FIXME
+
+    this.state = {
+      seenUsers: [],
+    };
+  }
+
+  componentDidMount() {
+    const seenUserIds = this.getSeenUserIds();
+
+    if (seenUserIds.length > 0) {
+      // FIXME: user data cache
+      this.crowi.apiGet('/users.list', {user_ids: seenUserIds.join(',')})
+      .then(res => {
+        this.setState({seenUsers: res.users});
+      }).catch(err => {
+        // do nothing
+      });
+    }
+  }
+
+  getSeenUserIds() {
+    // FIXME: Consider another way to bind values.
+    const $seenUserList = $("#seen-user-list");
+    if ($seenUserList.length > 0) {
+      const seenUsers = $seenUserList.data('seen-users');
+      if (seenUsers) {
+        return seenUsers.split(',');
+      }
+    }
+
+    return [];
+  }
+
+  render() {
+    return (
+      <div className="seen-user-list">
+        <p className="seen-user-count">
+          {this.state.seenUsers.length}
+        </p>
+        <UserList users={this.state.seenUsers} />
+      </div>
+    );
+  }
+}

+ 42 - 0
resource/js/components/SeenUserList/UserList.js

@@ -0,0 +1,42 @@
+import React from 'react';
+import UserPicture from '../User/UserPicture';
+
+export default class UserList extends React.Component {
+
+  isSeenUserListShown() {
+    const userCount = this.props.users.length;
+    if (0 < userCount && userCount <= 10) {
+      return true;
+    }
+
+    return false;
+  }
+
+  render() {
+    if (!this.isSeenUserListShown()) {
+      return null;
+    }
+
+    const users = this.props.users.map((user) => {
+      return (
+        <a key={user._id} data-user-id={user._id} href={'/user/' + user.username} title={user.name}>
+          <UserPicture user={user} size="xs" />
+        </a>
+      );
+    });
+
+    return (
+      <p className="seen-user-list">
+        {users}
+      </p>
+    );
+  }
+}
+
+UserList.propTypes = {
+  users: React.PropTypes.array,
+};
+
+UserList.defaultProps = {
+  users: [],
+};

+ 12 - 1
resource/js/components/User/UserPicture.js

@@ -13,6 +13,15 @@ export default class UserPicture extends React.Component {
     }
   }
 
+  getClassName() {
+    let className = ['picture', 'picture-rounded'];
+    if (this.props.size) {
+      className.push('picture-' + this.props.size);
+    }
+
+    return className.join(' ');
+  }
+
   render() {
     const user = this.props.user;
 
@@ -20,7 +29,7 @@ export default class UserPicture extends React.Component {
       <img
         src={this.getUserPicture(user)}
         alt={user.username}
-        className="picture picture-rounded"
+        className={this.getClassName()}
         />
     );
   }
@@ -28,8 +37,10 @@ export default class UserPicture extends React.Component {
 
 UserPicture.propTypes = {
   user: React.PropTypes.object.isRequired,
+  size: React.PropTypes.string,
 };
 
 UserPicture.defaultProps = {
   user: {},
+  size: null,
 };

+ 8 - 3
resource/js/crowi-form.js

@@ -254,7 +254,10 @@ $(function() {
         }
       }
       //$target.selection('insert', {text: "\n" + listMark, mode: 'before'});
-      insertText(currentLine.start, currentLine.end, "\n" + listMark, 'after');
+      var pos = $target.selection('getPos');
+      insertText(pos.start, pos.start, "\n" + listMark, 'replace');
+      var newPosition = pos.start + ("\n" + listMark).length;
+      $target.selection('setPos', {start: newPosition, end: newPosition});
     } else if (currentLine.text.match(/^(\s*(?:-|\+|\*|\d+\.) )/)) {
       // remove list
       $target.selection('setPos', {start: currentLine.start, end: currentLine.end});
@@ -276,11 +279,13 @@ $(function() {
       var prevLine = getPrevLine(event);
       if (!prevLine || (!currentLine.text.match(/---/) && !prevLine.text.match(/\|/g))) {
         //$target.selection('insert', {text: "\n" + row.join(' --- ') + "\n" + row.join('  '), mode: 'before'});
-        insertText(currentLine.start, currentLine.end, "\n" + row.join(' --- ') + "\n" + row.join('  '), 'after');
+        var pos = $target.selection('getPos');
+        insertText(pos.start, pos.start, "\n" + row.join(' --- ') + "\n" + row.join('  '), 'after');
         $target.selection('setPos', {start: currentLine.caret + 6 * row.length - 1, end: currentLine.caret + 6 * row.length - 1});
       } else {
         //$target.selection('insert', {text: "\n" + row.join('  '), mode: 'before'});
-        insertText(currentLine.start, currentLine.end, "\n" + row.join('  '), 'after');
+        var pos = $target.selection('getPos');
+        insertText(pos.start, pos.end, "\n" + row.join('  '), 'after');
         $target.selection('setPos', {start: currentLine.caret + 3, end: currentLine.caret + 3});
       }
     }

+ 4 - 105
resource/js/crowi.js

@@ -2,7 +2,6 @@
 /* Author: Sotaro KARASAWA <sotarok@crocos.co.jp>
 */
 
-var jsdiff = require('diff');
 var io = require('socket.io-client');
 
 //require('bootstrap-sass');
@@ -271,7 +270,9 @@ $(function() {
         var page = res.page;
 
         $('#newPageNameCheck').removeClass('alert-danger');
-        $('#newPageNameCheck').html('<img src="/images/loading_s.gif"> 移動しました。移動先にジャンプします。');
+        //$('#newPageNameCheck').html('<img src="/images/loading_s.gif"> 移動しました。移動先にジャンプします。');
+        // fix
+        $('#newPageNameCheck').html('<img src="/images/loading_s.gif"> Page moved! Redirecting to new page location.');
 
         setTimeout(function() {
           top.location.href = page.path + '?renamed=' + pagePath;
@@ -404,7 +405,7 @@ $(function() {
 
     $.getJSON('/_api/check_username', {username: username}, function(json) {
       if (!json.valid) {
-        $('#help-block-username').html('<i class="fa fa-warning"></i>このユーザーIDは利用できません。<br>');
+        $('#help-block-username').html('<i class="fa fa-warning"></i> This User ID is not available.<br>');
         $('#input-group-username').addClass('has-error');
       }
     });
@@ -685,21 +686,6 @@ $(function() {
       });
     }
 
-    var $seenUserList = $("#seen-user-list");
-    if ($seenUserList && $seenUserList.length > 0) {
-      var seenUsers = $seenUserList.data('seen-users');
-      var seenUsersArray = seenUsers.split(',');
-      if (seenUsers && seenUsersArray.length > 0 && seenUsersArray.length <= 10) {
-        // FIXME: user data cache
-        $.get('/_api/users.list', {user_ids: seenUsers}, function(res) {
-          // ignore unless response has error
-          if (res.ok) {
-            AddToSeenUser(res.users);
-          }
-        });
-      }
-    }
-
     function CreateUserLinkWithPicture (user) {
       var $userHtml = $('<a>');
       $userHtml.data('user-id', user._id);
@@ -714,93 +700,6 @@ $(function() {
       return $userHtml;
     }
 
-    function AddToSeenUser (users) {
-      $.each(users, function(i, user) {
-        $seenUserList.append(CreateUserLinkWithPicture(user));
-      });
-    }
-
-    // History Diff
-    var allRevisionIds = [];
-    $.each($('.diff-view'), function() {
-      allRevisionIds.push($(this).data('revisionId'));
-    });
-
-    $('.diff-view').on('click', function(e) {
-      e.preventDefault();
-
-      var getBeforeRevisionId = function(revisionId) {
-        var currentPos = $.inArray(revisionId, allRevisionIds);
-        if (currentPos < 0) {
-          return false;
-        }
-
-        var beforeRevisionId = allRevisionIds[currentPos + 1];
-        if (typeof beforeRevisionId === 'undefined') {
-          return false;
-        }
-
-        return beforeRevisionId;
-      };
-
-      var revisionId = $(this).data('revisionId');
-      var beforeRevisionId = getBeforeRevisionId(revisionId);
-      var $diffDisplay = $('#diff-display-' + revisionId);
-      var $diffIcon = $('#diff-icon-' + revisionId);
-
-      if ($diffIcon.hasClass('fa-arrow-circle-right')) {
-        $diffIcon.removeClass('fa-arrow-circle-right');
-        $diffIcon.addClass('fa-arrow-circle-down');
-      } else {
-        $diffIcon.removeClass('fa-arrow-circle-down');
-        $diffIcon.addClass('fa-arrow-circle-right');
-      }
-
-      if (beforeRevisionId === false) {
-        $diffDisplay.text('差分はありません');
-        $diffDisplay.slideToggle();
-      } else {
-        var revisionIds = revisionId + ',' + beforeRevisionId;
-
-        if ($diffDisplay.data('loaded')) {
-          $diffDisplay.slideToggle();
-          return true;
-        }
-
-        $.ajax({
-          type: 'GET',
-          url: '/_api/revisions.list?revision_ids=' + revisionIds,
-          dataType: 'json'
-        }).done(function(res) {
-          var currentText = res[0].body;
-          var previousText = res[1].body;
-
-          $diffDisplay.text('');
-
-          var diff = jsdiff.diffLines(previousText, currentText);
-          diff.forEach(function(part) {
-            var color = part.added ? 'green' : part.removed ? 'red' : 'grey';
-            var $span = $('<span>');
-            $span.css('color', color);
-            $span.text(part.value);
-            $diffDisplay.append($span);
-          });
-
-          $diffDisplay.data('loaded', 1);
-          $diffDisplay.slideToggle();
-        });
-      }
-    });
-
-    // default open
-    $('a[data-toggle="tab"][href="#revision-history"]').on('show.bs.tab', function() {
-      $('.diff-view').each(function(i, diffView) {
-        if (i < 2) {
-          $(diffView).click();
-        }
-      });
-    });
-
     // presentation
     var presentaionInitialized = false
       , $b = $('body');

+ 16 - 1
resource/js/util/Crowi.js

@@ -22,6 +22,7 @@ export default class Crowi {
 
     this.users = [];
     this.userByName = {};
+    this.userById   = {};
     this.draft = {};
 
     this.recoverData();
@@ -34,6 +35,7 @@ export default class Crowi {
   recoverData() {
     const keys = [
       'userByName',
+      'userById',
       'users',
       'draft',
     ];
@@ -50,7 +52,7 @@ export default class Crowi {
   }
 
   fetchUsers () {
-    const interval = 1000*60*10; // 5min
+    const interval = 1000*60*15; // 15min
     const currentTime = new Date();
     if (!this.localStorage.lastFetched && interval > currentTime - new Date(this.localStorage.lastFetched)) {
       return ;
@@ -62,13 +64,18 @@ export default class Crowi {
       this.localStorage.users = JSON.stringify(data.users);
 
       let userByName = {};
+      let userById = {};
       for (let i = 0; i < data.users.length; i++) {
         const user = data.users[i];
         userByName[user.username] = user;
+        userById[user._id] = user;
       }
       this.userByName = userByName;
       this.localStorage.userByName = JSON.stringify(userByName);
 
+      this.userById = userById;
+      this.localStorage.userById = JSON.stringify(userById);
+
       this.localStorage.lastFetched = new Date();
     }).catch(err => {
       this.localStorage.removeItem('lastFetched');
@@ -94,6 +101,14 @@ export default class Crowi {
     return null;
   }
 
+  findUserById(userId) {
+    if (this.userById && this.userById[userId]) {
+      return this.userById[userId];
+    }
+
+    return null;
+  }
+
   findUser(username) {
     if (this.userByName && this.userByName[username]) {
       return this.userByName[username];

+ 52 - 18
resource/search/mappings.json

@@ -40,46 +40,80 @@
       "properties" : {
         "name": {
           "type": "string",
-          "analyzer": "autocomplete"
+          "analyzer": "autocomplete",
+          "include_in_all": false
         }
       }
     },
     "pages": {
       "properties" : {
         "path": {
-          "type" : "multi_field",
-          "fields" : {
-            "raw": {"type" : "string", "index" : "not_analyzed"},
-            "ja": {"type" : "string", "analyzer" : "kuromoji"},
-            "en": {"type" : "string", "analyzer" : "english"}
-          }
+          "type": "string",
+          "copy_to": ["path_raw", "path_ja", "path_en"],
+          "include_in_all": false,
+          "index": "not_analyzed"
+        },
+        "path_raw": {
+          "type": "string",
+          "analyzer": "standard",
+          "include_in_all": false
+        },
+        "path_ja": {
+          "type": "string",
+          "analyzer": "kuromoji",
+          "include_in_all": false
+        },
+        "path_en": {
+          "type": "string",
+          "analyzer": "english",
+          "include_in_all": false
         },
         "body": {
-          "type" : "multi_field",
-          "fields" : {
-            "ja": {"type" : "string", "analyzer" : "kuromoji"},
-            "en": {"type" : "string", "analyzer" : "english"}
-          }
+          "type": "string",
+          "copy_to": ["body_raw", "body_ja", "body_en"],
+          "include_in_all": false,
+          "index": "not_analyzed"
+        },
+        "body_raw": {
+          "type": "string",
+          "analyzer": "standard",
+          "include_in_all": false
+        },
+        "body_ja": {
+          "type": "string",
+          "analyzer": "kuromoji",
+          "include_in_all": false
+        },
+        "body_en": {
+          "type": "string",
+          "analyzer": "english",
+          "include_in_all": false
         },
         "username": {
-          "type": "string"
+          "type": "string",
+          "include_in_all": false
         },
         "comment_count": {
-          "type": "integer"
+          "type": "integer",
+          "include_in_all": false
         },
         "bookmark_count": {
-          "type": "integer"
+          "type": "integer",
+          "include_in_all": false
         },
         "like_count": {
-          "type": "integer"
+          "type": "integer",
+          "include_in_all": false
         },
         "created_at": {
           "type": "date",
-          "format": "dateOptionalTime"
+          "format": "dateOptionalTime",
+          "include_in_all": false
         },
         "updated_at": {
           "type": "date",
-          "format": "dateOptionalTime"
+          "format": "dateOptionalTime",
+          "include_in_all": false
         }
       }
     }

+ 0 - 2
test/bootstrap.js

@@ -1,10 +1,8 @@
 'use strict';
 
 var express = require('express')
-  , async = require('async')
   , ROOT_DIR = __dirname + '/..'
   , MODEL_DIR = __dirname + '/../lib/models'
-  , Promise = require('bluebird')
   , testDBUtil
   ;
 

+ 3 - 1
test/crowi/crowi.test.js

@@ -5,7 +5,6 @@ var chai = require('chai')
   , proxyquire = require('proxyquire')
 
   , path = require('path')
-  , Promise = require('bluebird')
   ;
 chai.use(sinonChai);
 
@@ -38,6 +37,9 @@ describe('Test for Crowi application context', function () {
   });
 
   describe('.setupDatabase', function() {
+    before(function() {
+      mongoose.disconnect(); // avoid error of Trying to open unclosed connection
+    });
     it('setup completed', function(done) {
       var crowi = new Crowi(path.normalize(__dirname + '/../../'), process.env);
       // set

+ 0 - 1
test/models/config.test.js

@@ -2,7 +2,6 @@ var chai = require('chai')
   , expect = chai.expect
   , sinon = require('sinon')
   , sinonChai = require('sinon-chai')
-  , Promise = require('bluebird')
   , utils = require('../utils.js')
   ;
 chai.use(sinonChai);

+ 0 - 1
test/models/page.test.js

@@ -2,7 +2,6 @@ var chai = require('chai')
   , expect = chai.expect
   , sinon = require('sinon')
   , sinonChai = require('sinon-chai')
-  , Promise = require('bluebird')
   , utils = require('../utils.js')
   ;
 chai.use(sinonChai);

+ 0 - 1
test/models/updatePost.test.js

@@ -2,7 +2,6 @@ var chai = require('chai')
   , expect = chai.expect
   , sinon = require('sinon')
   , sinonChai = require('sinon-chai')
-  , Promise = require('bluebird')
   , utils = require('../utils.js')
   ;
 chai.use(sinonChai);

+ 1 - 2
test/models/user.test.js

@@ -2,7 +2,6 @@ var chai = require('chai')
   , expect = chai.expect
   , sinon = require('sinon')
   , sinonChai = require('sinon-chai')
-  , Promise = require('bluebird')
   , utils = require('../utils.js')
   ;
 chai.use(sinonChai);
@@ -15,7 +14,7 @@ describe('User', function () {
   describe('Create and Find.', function () {
     context('The user', function() {
       it('should created', function(done) {
-        User.createUserByEmailAndPassword('Aoi Miyazaki', 'aoi', 'aoi@example.com', 'hogefuga11', function (err, userData) {
+        User.createUserByEmailAndPassword('Aoi Miyazaki', 'aoi', 'aoi@example.com', 'hogefuga11', 'en', function (err, userData) {
           expect(err).to.be.null;
           expect(userData).to.instanceof(User);
           done();

+ 1 - 0
test/utils.js

@@ -7,6 +7,7 @@ var mongoUri = process.env.MONGOLAB_URI || process.env.MONGOHQ_URL || process.en
   , crowi = new (require(ROOT_DIR + '/lib/crowi'))(ROOT_DIR, process.env)
   ;
 
+mongoose.Promise = global.Promise;
 
 before('Create database connection and clean up', function (done) {
   if (!mongoUri) {

+ 1 - 0
tmp/uploads/.gitignore

@@ -0,0 +1 @@
+*

+ 7 - 7
webpack.config.js

@@ -1,5 +1,6 @@
 var path = require('path');
 var webpack = require('webpack');
+var UglifyJsPlugin = require('webpack/lib/optimize/UglifyJsPlugin');
 
 var ManifestPlugin = require('webpack-manifest-plugin');
 
@@ -16,19 +17,18 @@ var config = {
     filename: "[name].[hash].js"
   },
   resolve: {
-    modulesDirectories: [
+    modules: [
       './node_modules', './resource/thirdparty-js',
     ],
   },
   module: {
-    loaders: [
+    rules: [
       {
         test: /.jsx?$/,
-        loader: 'babel-loader',
         exclude: /node_modules/,
-        query: {
-          presets: ['es2015', 'react']
-        }
+        use: [{
+          loader: 'babel-loader',
+        }]
       }
     ]
   },
@@ -42,7 +42,7 @@ if (process.env && process.env.NODE_ENV !== 'development') {
         'NODE_ENV': JSON.stringify('production')
       }
     }),
-    new webpack.optimize.UglifyJsPlugin({
+    new UglifyJsPlugin({
       compress:{
         warnings: false
       }