From 4622e4842cfe137557d8827c868cc760b49f69f1 Mon Sep 17 00:00:00 2001 From: benweet Date: Sun, 23 Jul 2017 19:42:08 +0100 Subject: [PATCH] First commit --- .babelrc | 14 + .editorconfig | 9 + .eslintignore | 3 + .eslintrc.js | 40 + .gitignore | 7 + .postcssrc.js | 8 + .stylelintrc | 7 + README.md | 21 + build/build.js | 35 + build/check-versions.js | 48 + build/dev-client.js | 9 + build/dev-server.js | 89 + build/utils.js | 71 + build/vue-loader.conf.js | 12 + build/webpack.base.conf.js | 76 + build/webpack.dev.conf.js | 35 + build/webpack.prod.conf.js | 120 + config/dev.env.js | 6 + config/index.js | 38 + config/prod.env.js | 3 + index.html | 11 + package.json | 89 + src/assets/logo.png | Bin 0 -> 6849 bytes src/cledit/cldiffutils.js | 482 ++ src/cledit/cledit.js | 11 + src/cledit/cleditCore.js | 368 ++ src/cledit/cleditHighlighter.js | 189 + src/cledit/cleditKeystroke.js | 183 + src/cledit/cleditMarker.js | 44 + src/cledit/cleditSelectionMgr.js | 399 ++ src/cledit/cleditUndoMgr.js | 178 + src/cledit/cleditUtils.js | 123 + src/cledit/cleditWatcher.js | 33 + src/cledit/clunderscore.js | 166 + src/cledit/htmlSanitizer.js | 424 ++ src/cledit/mdGrammar.js | 422 ++ src/cledit/pagedown.js | 1362 ++++ src/components/App.vue | 48 + src/components/ButtonBar.vue | 88 + src/components/Editor.vue | 64 + src/components/Layout.vue | 165 + src/components/NavigationBar.vue | 76 + src/components/Preview.vue | 48 + src/components/SideBar.vue | 17 + src/components/StatusBar.vue | 122 + src/components/Toc.vue | 6 + src/components/common/base.scss | 145 + src/components/common/flex.scss | 19 + .../common/markdownHighlighting.scss | 232 + src/components/common/prism.scss | 73 + src/components/common/variables.scss | 13 + src/extensions/index.js | 1 + src/extensions/markdownExt.js | 197 + src/icons/CodeBraces.vue | 5 + src/icons/Eye.vue | 5 + src/icons/FileImage.vue | 5 + src/icons/FormatBold.vue | 5 + src/icons/FormatHorizontalRule.vue | 5 + src/icons/FormatItalic.vue | 5 + src/icons/FormatListBulleted.vue | 5 + src/icons/FormatListNumbers.vue | 5 + src/icons/FormatQuoteClose.vue | 5 + src/icons/FormatSize.vue | 5 + src/icons/FormatStrikethrough.vue | 5 + src/icons/LinkVariant.vue | 5 + src/icons/NavigationBar.vue | 6 + src/icons/SidePreview.vue | 5 + src/icons/StatusBar.vue | 6 + src/icons/Table.vue | 5 + src/icons/index.js | 34 + src/index.js | 15 + src/markdown/sample.md | 117 + src/services/animationSvc.js | 228 + src/services/constants.js | 3 + src/services/editorEngineSvc.js | 158 + src/services/editorSvc.js | 734 +++ src/services/extensionSvc.js | 46 + src/services/markdownConversionSvc.js | 262 + src/services/markdownGrammarSvc.js | 414 ++ src/services/optional/index.js | 1 + src/services/optional/scrollSync.js | 185 + src/services/sectionUtils.js | 104 + src/services/utils.js | 11 + src/store/index.js | 22 + src/store/modules/editor.js | 16 + src/store/modules/files.js | 31 + src/store/modules/layout.js | 167 + static/.gitkeep | 0 yarn.lock | 5622 +++++++++++++++++ 89 files changed, 14701 insertions(+) create mode 100644 .babelrc create mode 100644 .editorconfig create mode 100644 .eslintignore create mode 100644 .eslintrc.js create mode 100644 .gitignore create mode 100644 .postcssrc.js create mode 100644 .stylelintrc create mode 100644 README.md create mode 100644 build/build.js create mode 100644 build/check-versions.js create mode 100644 build/dev-client.js create mode 100644 build/dev-server.js create mode 100644 build/utils.js create mode 100644 build/vue-loader.conf.js create mode 100644 build/webpack.base.conf.js create mode 100644 build/webpack.dev.conf.js create mode 100644 build/webpack.prod.conf.js create mode 100644 config/dev.env.js create mode 100644 config/index.js create mode 100644 config/prod.env.js create mode 100644 index.html create mode 100644 package.json create mode 100644 src/assets/logo.png create mode 100644 src/cledit/cldiffutils.js create mode 100644 src/cledit/cledit.js create mode 100644 src/cledit/cleditCore.js create mode 100644 src/cledit/cleditHighlighter.js create mode 100644 src/cledit/cleditKeystroke.js create mode 100644 src/cledit/cleditMarker.js create mode 100644 src/cledit/cleditSelectionMgr.js create mode 100644 src/cledit/cleditUndoMgr.js create mode 100644 src/cledit/cleditUtils.js create mode 100644 src/cledit/cleditWatcher.js create mode 100644 src/cledit/clunderscore.js create mode 100644 src/cledit/htmlSanitizer.js create mode 100644 src/cledit/mdGrammar.js create mode 100644 src/cledit/pagedown.js create mode 100644 src/components/App.vue create mode 100644 src/components/ButtonBar.vue create mode 100644 src/components/Editor.vue create mode 100644 src/components/Layout.vue create mode 100644 src/components/NavigationBar.vue create mode 100644 src/components/Preview.vue create mode 100644 src/components/SideBar.vue create mode 100644 src/components/StatusBar.vue create mode 100644 src/components/Toc.vue create mode 100644 src/components/common/base.scss create mode 100644 src/components/common/flex.scss create mode 100644 src/components/common/markdownHighlighting.scss create mode 100644 src/components/common/prism.scss create mode 100644 src/components/common/variables.scss create mode 100644 src/extensions/index.js create mode 100644 src/extensions/markdownExt.js create mode 100644 src/icons/CodeBraces.vue create mode 100644 src/icons/Eye.vue create mode 100644 src/icons/FileImage.vue create mode 100644 src/icons/FormatBold.vue create mode 100644 src/icons/FormatHorizontalRule.vue create mode 100644 src/icons/FormatItalic.vue create mode 100644 src/icons/FormatListBulleted.vue create mode 100644 src/icons/FormatListNumbers.vue create mode 100644 src/icons/FormatQuoteClose.vue create mode 100644 src/icons/FormatSize.vue create mode 100644 src/icons/FormatStrikethrough.vue create mode 100644 src/icons/LinkVariant.vue create mode 100644 src/icons/NavigationBar.vue create mode 100644 src/icons/SidePreview.vue create mode 100644 src/icons/StatusBar.vue create mode 100644 src/icons/Table.vue create mode 100644 src/icons/index.js create mode 100644 src/index.js create mode 100644 src/markdown/sample.md create mode 100644 src/services/animationSvc.js create mode 100644 src/services/constants.js create mode 100644 src/services/editorEngineSvc.js create mode 100644 src/services/editorSvc.js create mode 100644 src/services/extensionSvc.js create mode 100644 src/services/markdownConversionSvc.js create mode 100644 src/services/markdownGrammarSvc.js create mode 100644 src/services/optional/index.js create mode 100644 src/services/optional/scrollSync.js create mode 100644 src/services/sectionUtils.js create mode 100644 src/services/utils.js create mode 100644 src/store/index.js create mode 100644 src/store/modules/editor.js create mode 100644 src/store/modules/files.js create mode 100644 src/store/modules/layout.js create mode 100644 static/.gitkeep create mode 100644 yarn.lock diff --git a/.babelrc b/.babelrc new file mode 100644 index 00000000..13f0e471 --- /dev/null +++ b/.babelrc @@ -0,0 +1,14 @@ +{ + "presets": [ + ["env", { "modules": false }], + "stage-2" + ], + "plugins": ["transform-runtime"], + "comments": false, + "env": { + "test": { + "presets": ["env", "stage-2"], + "plugins": [ "istanbul" ] + } + } +} diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..9d08a1a8 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,9 @@ +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true diff --git a/.eslintignore b/.eslintignore new file mode 100644 index 00000000..6cb140a6 --- /dev/null +++ b/.eslintignore @@ -0,0 +1,3 @@ +build/*.js +config/*.js +src/cledit/*.js \ No newline at end of file diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 00000000..36ae5337 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,40 @@ +// http://eslint.org/docs/user-guide/configuring + +module.exports = { + root: true, + parser: 'babel-eslint', + parserOptions: { + sourceType: 'module' + }, + env: { + browser: true, + }, + extends: 'airbnb-base', + // required to lint *.vue files + plugins: [ + 'html' + ], + // check if imports actually resolve + 'settings': { + 'import/resolver': { + 'webpack': { + 'config': 'build/webpack.base.conf.js' + } + } + }, + // add your custom rules here + 'rules': { + 'no-param-reassign': [2, { 'props': false }], + // don't require .vue extension when importing + 'import/extensions': ['error', 'always', { + 'js': 'never', + 'vue': 'never' + }], + // allow optionalDependencies + 'import/no-extraneous-dependencies': ['error', { + 'optionalDependencies': ['test/unit/index.js'] + }], + // allow debugger during development + 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0 + } +} diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..44bcd428 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +.DS_Store +node_modules/ +dist/ +.history +npm-debug.log* +yarn-debug.log* +yarn-error.log* diff --git a/.postcssrc.js b/.postcssrc.js new file mode 100644 index 00000000..ea9a5ab8 --- /dev/null +++ b/.postcssrc.js @@ -0,0 +1,8 @@ +// https://github.com/michael-ciniawsky/postcss-load-config + +module.exports = { + "plugins": { + // to edit target browsers: use "browserlist" field in package.json + "autoprefixer": {} + } +} diff --git a/.stylelintrc b/.stylelintrc new file mode 100644 index 00000000..e9549f87 --- /dev/null +++ b/.stylelintrc @@ -0,0 +1,7 @@ +{ + "processors": ["stylelint-processor-html"], + "extends": "stylelint-config-standard", + "rules": { + "no-empty-source": null + } +} \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 00000000..2fa7d831 --- /dev/null +++ b/README.md @@ -0,0 +1,21 @@ +# my-project + +> A Vue.js project + +## Build Setup + +``` bash +# install dependencies +npm install + +# serve with hot reload at localhost:8080 +npm run dev + +# build for production with minification +npm run build + +# build for production and view the bundle analyzer report +npm run build --report +``` + +For detailed explanation on how things work, checkout the [guide](http://vuejs-templates.github.io/webpack/) and [docs for vue-loader](http://vuejs.github.io/vue-loader). diff --git a/build/build.js b/build/build.js new file mode 100644 index 00000000..6b8add10 --- /dev/null +++ b/build/build.js @@ -0,0 +1,35 @@ +require('./check-versions')() + +process.env.NODE_ENV = 'production' + +var ora = require('ora') +var rm = require('rimraf') +var path = require('path') +var chalk = require('chalk') +var webpack = require('webpack') +var config = require('../config') +var webpackConfig = require('./webpack.prod.conf') + +var spinner = ora('building for production...') +spinner.start() + +rm(path.join(config.build.assetsRoot, config.build.assetsSubDirectory), err => { + if (err) throw err + webpack(webpackConfig, function (err, stats) { + spinner.stop() + if (err) throw err + process.stdout.write(stats.toString({ + colors: true, + modules: false, + children: false, + chunks: false, + chunkModules: false + }) + '\n\n') + + console.log(chalk.cyan(' Build complete.\n')) + console.log(chalk.yellow( + ' Tip: built files are meant to be served over an HTTP server.\n' + + ' Opening index.html over file:// won\'t work.\n' + )) + }) +}) diff --git a/build/check-versions.js b/build/check-versions.js new file mode 100644 index 00000000..100f3a0f --- /dev/null +++ b/build/check-versions.js @@ -0,0 +1,48 @@ +var chalk = require('chalk') +var semver = require('semver') +var packageConfig = require('../package.json') +var shell = require('shelljs') +function exec (cmd) { + return require('child_process').execSync(cmd).toString().trim() +} + +var versionRequirements = [ + { + name: 'node', + currentVersion: semver.clean(process.version), + versionRequirement: packageConfig.engines.node + }, +] + +if (shell.which('npm')) { + versionRequirements.push({ + name: 'npm', + currentVersion: exec('npm --version'), + versionRequirement: packageConfig.engines.npm + }) +} + +module.exports = function () { + var warnings = [] + for (var i = 0; i < versionRequirements.length; i++) { + var mod = versionRequirements[i] + if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) { + warnings.push(mod.name + ': ' + + chalk.red(mod.currentVersion) + ' should be ' + + chalk.green(mod.versionRequirement) + ) + } + } + + if (warnings.length) { + console.log('') + console.log(chalk.yellow('To use this template, you must update following to modules:')) + console.log() + for (var i = 0; i < warnings.length; i++) { + var warning = warnings[i] + console.log(' ' + warning) + } + console.log() + process.exit(1) + } +} diff --git a/build/dev-client.js b/build/dev-client.js new file mode 100644 index 00000000..18aa1e21 --- /dev/null +++ b/build/dev-client.js @@ -0,0 +1,9 @@ +/* eslint-disable */ +require('eventsource-polyfill') +var hotClient = require('webpack-hot-middleware/client?noInfo=true&reload=true') + +hotClient.subscribe(function (event) { + if (event.action === 'reload') { + window.location.reload() + } +}) diff --git a/build/dev-server.js b/build/dev-server.js new file mode 100644 index 00000000..782dc6fc --- /dev/null +++ b/build/dev-server.js @@ -0,0 +1,89 @@ +require('./check-versions')() + +var config = require('../config') +if (!process.env.NODE_ENV) { + process.env.NODE_ENV = JSON.parse(config.dev.env.NODE_ENV) +} + +var opn = require('opn') +var path = require('path') +var express = require('express') +var webpack = require('webpack') +var proxyMiddleware = require('http-proxy-middleware') +var webpackConfig = require('./webpack.dev.conf') + +// default port where dev server listens for incoming traffic +var port = process.env.PORT || config.dev.port +// automatically open browser, if not set will be false +var autoOpenBrowser = !!config.dev.autoOpenBrowser +// Define HTTP proxies to your custom API backend +// https://github.com/chimurai/http-proxy-middleware +var proxyTable = config.dev.proxyTable + +var app = express() +var compiler = webpack(webpackConfig) + +var devMiddleware = require('webpack-dev-middleware')(compiler, { + publicPath: webpackConfig.output.publicPath, + quiet: true +}) + +var hotMiddleware = require('webpack-hot-middleware')(compiler, { + log: () => {} +}) +// force page reload when html-webpack-plugin template changes +compiler.plugin('compilation', function (compilation) { + compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) { + hotMiddleware.publish({ action: 'reload' }) + cb() + }) +}) + +// proxy api requests +Object.keys(proxyTable).forEach(function (context) { + var options = proxyTable[context] + if (typeof options === 'string') { + options = { target: options } + } + app.use(proxyMiddleware(options.filter || context, options)) +}) + +// handle fallback for HTML5 history API +app.use(require('connect-history-api-fallback')()) + +// serve webpack bundle output +app.use(devMiddleware) + +// enable hot-reload and state-preserving +// compilation error display +app.use(hotMiddleware) + +// serve pure static assets +var staticPath = path.posix.join(config.dev.assetsPublicPath, config.dev.assetsSubDirectory) +app.use(staticPath, express.static('./static')) + +var uri = 'http://localhost:' + port + +var _resolve +var readyPromise = new Promise(resolve => { + _resolve = resolve +}) + +console.log('> Starting dev server...') +devMiddleware.waitUntilValid(() => { + console.log('> Listening at ' + uri + '\n') + // when env is testing, don't need open it + if (autoOpenBrowser && process.env.NODE_ENV !== 'testing') { + opn(uri) + } + _resolve() +}) + +var server = app.listen(port) + +module.exports = { + ready: readyPromise, + close: () => { + server.close() + } +} diff --git a/build/utils.js b/build/utils.js new file mode 100644 index 00000000..b1d54b4d --- /dev/null +++ b/build/utils.js @@ -0,0 +1,71 @@ +var path = require('path') +var config = require('../config') +var ExtractTextPlugin = require('extract-text-webpack-plugin') + +exports.assetsPath = function (_path) { + var assetsSubDirectory = process.env.NODE_ENV === 'production' + ? config.build.assetsSubDirectory + : config.dev.assetsSubDirectory + return path.posix.join(assetsSubDirectory, _path) +} + +exports.cssLoaders = function (options) { + options = options || {} + + var cssLoader = { + loader: 'css-loader', + options: { + minimize: process.env.NODE_ENV === 'production', + sourceMap: options.sourceMap + } + } + + // generate loader string to be used with extract text plugin + function generateLoaders (loader, loaderOptions) { + var loaders = [cssLoader] + if (loader) { + loaders.push({ + loader: loader + '-loader', + options: Object.assign({}, loaderOptions, { + sourceMap: options.sourceMap + }) + }) + } + + // Extract CSS when that option is specified + // (which is the case during production build) + if (options.extract) { + return ExtractTextPlugin.extract({ + use: loaders, + fallback: 'vue-style-loader' + }) + } else { + return ['vue-style-loader'].concat(loaders) + } + } + + // https://vue-loader.vuejs.org/en/configurations/extract-css.html + return { + css: generateLoaders(), + postcss: generateLoaders(), + less: generateLoaders('less'), + sass: generateLoaders('sass', { indentedSyntax: true }), + scss: generateLoaders('sass'), + stylus: generateLoaders('stylus'), + styl: generateLoaders('stylus') + } +} + +// Generate loaders for standalone style files (outside of .vue) +exports.styleLoaders = function (options) { + var output = [] + var loaders = exports.cssLoaders(options) + for (var extension in loaders) { + var loader = loaders[extension] + output.push({ + test: new RegExp('\\.' + extension + '$'), + use: loader + }) + } + return output +} diff --git a/build/vue-loader.conf.js b/build/vue-loader.conf.js new file mode 100644 index 00000000..7aee79ba --- /dev/null +++ b/build/vue-loader.conf.js @@ -0,0 +1,12 @@ +var utils = require('./utils') +var config = require('../config') +var isProduction = process.env.NODE_ENV === 'production' + +module.exports = { + loaders: utils.cssLoaders({ + sourceMap: isProduction + ? config.build.productionSourceMap + : config.dev.cssSourceMap, + extract: isProduction + }) +} diff --git a/build/webpack.base.conf.js b/build/webpack.base.conf.js new file mode 100644 index 00000000..57dbb5fa --- /dev/null +++ b/build/webpack.base.conf.js @@ -0,0 +1,76 @@ +var path = require('path') +var utils = require('./utils') +var config = require('../config') +var vueLoaderConfig = require('./vue-loader.conf') +var StylelintPlugin = require('stylelint-webpack-plugin') + +function resolve (dir) { + return path.join(__dirname, '..', dir) +} + +module.exports = { + entry: { + app: './src/' + }, + output: { + path: config.build.assetsRoot, + filename: '[name].js', + publicPath: process.env.NODE_ENV === 'production' + ? config.build.assetsPublicPath + : config.dev.assetsPublicPath + }, + resolve: { + extensions: ['.js', '.vue', '.json'], + alias: { + '@': resolve('src') + } + }, + module: { + rules: [ + { + test: /\.(js|vue)$/, + loader: 'eslint-loader', + enforce: 'pre', + include: [resolve('src'), resolve('test')], + options: { + formatter: require('eslint-friendly-formatter') + } + }, + { + test: /\.vue$/, + loader: 'vue-loader', + options: vueLoaderConfig + }, + { + test: /\.js$/, + loader: 'babel-loader', + include: [resolve('src'), resolve('test')] + }, + { + test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, + loader: 'url-loader', + options: { + limit: 10000, + name: utils.assetsPath('img/[name].[hash:7].[ext]') + } + }, + { + test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, + loader: 'url-loader', + options: { + limit: 10000, + name: utils.assetsPath('fonts/[name].[hash:7].[ext]') + } + }, + { + test: /\.md$/, + loader: 'raw-loader' + } + ] + }, + plugins: [ + new StylelintPlugin({ + files: ['**/*.vue', '**/*.scss'] + }) + ] +} diff --git a/build/webpack.dev.conf.js b/build/webpack.dev.conf.js new file mode 100644 index 00000000..cd92c4a3 --- /dev/null +++ b/build/webpack.dev.conf.js @@ -0,0 +1,35 @@ +var utils = require('./utils') +var webpack = require('webpack') +var config = require('../config') +var merge = require('webpack-merge') +var baseWebpackConfig = require('./webpack.base.conf') +var HtmlWebpackPlugin = require('html-webpack-plugin') +var FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin') + +// add hot-reload related code to entry chunks +Object.keys(baseWebpackConfig.entry).forEach(function (name) { + baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name]) +}) + +module.exports = merge(baseWebpackConfig, { + module: { + rules: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap }) + }, + // cheap-module-eval-source-map is faster for development + devtool: 'source-map', + plugins: [ + new webpack.DefinePlugin({ + 'process.env': config.dev.env + }), + // https://github.com/glenjamin/webpack-hot-middleware#installation--usage + new webpack.HotModuleReplacementPlugin(), + new webpack.NoEmitOnErrorsPlugin(), + // https://github.com/ampedandwired/html-webpack-plugin + new HtmlWebpackPlugin({ + filename: 'index.html', + template: 'index.html', + inject: true + }), + new FriendlyErrorsPlugin() + ] +}) diff --git a/build/webpack.prod.conf.js b/build/webpack.prod.conf.js new file mode 100644 index 00000000..da44b656 --- /dev/null +++ b/build/webpack.prod.conf.js @@ -0,0 +1,120 @@ +var path = require('path') +var utils = require('./utils') +var webpack = require('webpack') +var config = require('../config') +var merge = require('webpack-merge') +var baseWebpackConfig = require('./webpack.base.conf') +var CopyWebpackPlugin = require('copy-webpack-plugin') +var HtmlWebpackPlugin = require('html-webpack-plugin') +var ExtractTextPlugin = require('extract-text-webpack-plugin') +var OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin') + +var env = config.build.env + +var webpackConfig = merge(baseWebpackConfig, { + module: { + rules: utils.styleLoaders({ + sourceMap: config.build.productionSourceMap, + extract: true + }) + }, + devtool: config.build.productionSourceMap ? '#source-map' : false, + output: { + path: config.build.assetsRoot, + filename: utils.assetsPath('js/[name].[chunkhash].js'), + chunkFilename: utils.assetsPath('js/[id].[chunkhash].js') + }, + plugins: [ + // http://vuejs.github.io/vue-loader/en/workflow/production.html + new webpack.DefinePlugin({ + 'process.env': env + }), + new webpack.optimize.UglifyJsPlugin({ + compress: { + warnings: false + }, + sourceMap: true + }), + // extract css into its own file + new ExtractTextPlugin({ + filename: utils.assetsPath('css/[name].[contenthash].css') + }), + // Compress extracted CSS. We are using this plugin so that possible + // duplicated CSS from different components can be deduped. + new OptimizeCSSPlugin({ + cssProcessorOptions: { + safe: true + } + }), + // generate dist index.html with correct asset hash for caching. + // you can customize output by editing /index.html + // see https://github.com/ampedandwired/html-webpack-plugin + new HtmlWebpackPlugin({ + filename: config.build.index, + template: 'index.html', + inject: true, + minify: { + removeComments: true, + collapseWhitespace: true, + removeAttributeQuotes: true + // more options: + // https://github.com/kangax/html-minifier#options-quick-reference + }, + // necessary to consistently work with multiple chunks via CommonsChunkPlugin + chunksSortMode: 'dependency' + }), + // split vendor js into its own file + new webpack.optimize.CommonsChunkPlugin({ + name: 'vendor', + minChunks: function (module, count) { + // any required modules inside node_modules are extracted to vendor + return ( + module.resource && + /\.js$/.test(module.resource) && + module.resource.indexOf( + path.join(__dirname, '../node_modules') + ) === 0 + ) + } + }), + // extract webpack runtime and module manifest to its own file in order to + // prevent vendor hash from being updated whenever app bundle is updated + new webpack.optimize.CommonsChunkPlugin({ + name: 'manifest', + chunks: ['vendor'] + }), + // copy custom static assets + new CopyWebpackPlugin([ + { + from: path.resolve(__dirname, '../static'), + to: config.build.assetsSubDirectory, + ignore: ['.*'] + } + ]) + ] +}) + +if (config.build.productionGzip) { + var CompressionWebpackPlugin = require('compression-webpack-plugin') + + webpackConfig.plugins.push( + new CompressionWebpackPlugin({ + asset: '[path].gz[query]', + algorithm: 'gzip', + test: new RegExp( + '\\.(' + + config.build.productionGzipExtensions.join('|') + + ')$' + ), + threshold: 10240, + minRatio: 0.8 + }) + ) +} + +if (config.build.bundleAnalyzerReport) { + var BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin + webpackConfig.plugins.push(new BundleAnalyzerPlugin()) +} + +module.exports = webpackConfig diff --git a/config/dev.env.js b/config/dev.env.js new file mode 100644 index 00000000..efead7c8 --- /dev/null +++ b/config/dev.env.js @@ -0,0 +1,6 @@ +var merge = require('webpack-merge') +var prodEnv = require('./prod.env') + +module.exports = merge(prodEnv, { + NODE_ENV: '"development"' +}) diff --git a/config/index.js b/config/index.js new file mode 100644 index 00000000..196da1fa --- /dev/null +++ b/config/index.js @@ -0,0 +1,38 @@ +// see http://vuejs-templates.github.io/webpack for documentation. +var path = require('path') + +module.exports = { + build: { + env: require('./prod.env'), + index: path.resolve(__dirname, '../dist/index.html'), + assetsRoot: path.resolve(__dirname, '../dist'), + assetsSubDirectory: 'static', + assetsPublicPath: '/', + productionSourceMap: true, + // Gzip off by default as many popular static hosts such as + // Surge or Netlify already gzip all static assets for you. + // Before setting to `true`, make sure to: + // npm install --save-dev compression-webpack-plugin + productionGzip: false, + productionGzipExtensions: ['js', 'css'], + // Run the build command with an extra argument to + // View the bundle analyzer report after build finishes: + // `npm run build --report` + // Set to `true` or `false` to always turn it on or off + bundleAnalyzerReport: process.env.npm_config_report + }, + dev: { + env: require('./dev.env'), + port: 8080, + autoOpenBrowser: true, + assetsSubDirectory: 'static', + assetsPublicPath: '/', + proxyTable: {}, + // CSS Sourcemaps off by default because relative paths are "buggy" + // with this option, according to the CSS-Loader README + // (https://github.com/webpack/css-loader#sourcemaps) + // In our experience, they generally work as expected, + // just be aware of this issue when enabling this option. + cssSourceMap: false + } +} diff --git a/config/prod.env.js b/config/prod.env.js new file mode 100644 index 00000000..773d263d --- /dev/null +++ b/config/prod.env.js @@ -0,0 +1,3 @@ +module.exports = { + NODE_ENV: '"production"' +} diff --git a/index.html b/index.html new file mode 100644 index 00000000..a8261783 --- /dev/null +++ b/index.html @@ -0,0 +1,11 @@ + + + + + my-project + + +
+ + + diff --git a/package.json b/package.json new file mode 100644 index 00000000..62e1073b --- /dev/null +++ b/package.json @@ -0,0 +1,89 @@ +{ + "name": "my-project", + "version": "1.0.0", + "description": "A Vue.js project", + "author": "", + "private": true, + "scripts": { + "dev": "node build/dev-server.js", + "start": "node build/dev-server.js", + "build": "node build/build.js", + "lint": "eslint --ext .js,.vue src" + }, + "dependencies": { + "bezier-easing": "^1.1.0", + "clunderscore": "^1.0.3", + "diff-match-patch": "^1.0.0", + "markdown-it": "^8.3.1", + "markdown-it-abbr": "^1.0.4", + "markdown-it-deflist": "^2.0.2", + "markdown-it-emoji": "^1.3.0", + "markdown-it-footnote": "^3.0.1", + "markdown-it-mathjax": "^2.0.0", + "markdown-it-pandoc-renderer": "1.1.3", + "markdown-it-sub": "^1.0.0", + "markdown-it-sup": "^1.0.0", + "normalize-scss": "^7.0.0", + "prismjs": "^1.6.0", + "raw-loader": "^0.5.1", + "vue": "^2.3.3", + "vuex": "^2.3.1" + }, + "devDependencies": { + "autoprefixer": "^6.7.2", + "babel-core": "^6.22.1", + "babel-eslint": "^7.1.1", + "babel-loader": "^6.2.10", + "babel-plugin-transform-runtime": "^6.22.0", + "babel-preset-env": "^1.3.2", + "babel-preset-stage-2": "^6.22.0", + "babel-register": "^6.22.0", + "chalk": "^1.1.3", + "connect-history-api-fallback": "^1.3.0", + "copy-webpack-plugin": "^4.0.1", + "css-loader": "^0.28.4", + "eslint": "^3.19.0", + "eslint-config-airbnb-base": "^11.1.3", + "eslint-friendly-formatter": "^2.0.7", + "eslint-import-resolver-webpack": "^0.8.1", + "eslint-loader": "^1.7.1", + "eslint-plugin-html": "^2.0.0", + "eslint-plugin-import": "^2.2.0", + "eventsource-polyfill": "^0.9.6", + "express": "^4.14.1", + "extract-text-webpack-plugin": "^2.0.0", + "file-loader": "^0.11.1", + "friendly-errors-webpack-plugin": "^1.1.3", + "html-webpack-plugin": "^2.28.0", + "http-proxy-middleware": "^0.17.3", + "node-sass": "^4.5.3", + "opn": "^4.0.2", + "optimize-css-assets-webpack-plugin": "^1.3.0", + "ora": "^1.2.0", + "rimraf": "^2.6.0", + "sass-loader": "^6.0.5", + "semver": "^5.3.0", + "shelljs": "^0.7.6", + "stylelint-config-standard": "^16.0.0", + "stylelint-processor-html": "^1.0.0", + "stylelint-webpack-plugin": "^0.7.0", + "url-loader": "^0.5.8", + "vue-loader": "^12.1.0", + "vue-style-loader": "^3.0.1", + "vue-template-compiler": "^2.3.3", + "webpack": "^2.6.1", + "webpack-bundle-analyzer": "^2.2.1", + "webpack-dev-middleware": "^1.10.0", + "webpack-hot-middleware": "^2.18.0", + "webpack-merge": "^4.1.0" + }, + "engines": { + "node": ">= 4.0.0", + "npm": ">= 3.0.0" + }, + "browserslist": [ + "> 1%", + "last 2 versions", + "not ie <= 8" + ] +} diff --git a/src/assets/logo.png b/src/assets/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..f3d2503fc2a44b5053b0837ebea6e87a2d339a43 GIT binary patch literal 6849 zcmaKRcUV(fvo}bjDT-7nLI_nlK}sT_69H+`qzVWDA|yaU?}j417wLi^B1KB1SLsC& zL0ag7$U(XW5YR7p&Ux?sP$d4lvMt8C^+TcQu4F zQqv!UF!I+kw)c0jhd6+g6oCr9P?7)?!qX1ui*iL{p}sKCAGuJ{{W)0z1pLF|=>h}& zt(2Lr0Z`2ig8<5i%Zk}cO5Fm=LByqGWaS`oqChZdEFmc`0hSb#gg|Aap^{+WKOYcj zHjINK)KDG%&s?Mt4CL(T=?;~U@bU2x_mLKN!#GJuK_CzbNw5SMEJorG!}_5;?R>@1 zSl)jns3WlU7^J%=(hUtfmuUCU&C3%8B5C^f5>W2Cy8jW3#{Od{lF1}|?c61##3dzA zsPlFG;l_FzBK}8>|H_Ru_H#!_7$UH4UKo3lKOA}g1(R&|e@}GINYVzX?q=_WLZCgh z)L|eJMce`D0EIwgRaNETDsr+?vQknSGAi=7H00r`QnI%oQnFxm`G2umXso9l+8*&Q z7WqF|$p49js$mdzo^BXpH#gURy=UO;=IMrYc5?@+sR4y_?d*~0^YP7d+y0{}0)zBM zIKVM(DBvICK#~7N0a+PY6)7;u=dutmNqK3AlsrUU9U`d;msiucB_|8|2kY=(7XA;G zwDA8AR)VCA#JOkxm#6oHNS^YVuOU;8p$N)2{`;oF|rQ?B~K$%rHDxXs+_G zF5|-uqHZvSzq}L;5Kcy_P+x0${33}Ofb6+TX&=y;;PkEOpz%+_bCw_{<&~ zeLV|!bP%l1qxywfVr9Z9JI+++EO^x>ZuCK);=$VIG1`kxK8F2M8AdC$iOe3cj1fo(ce4l-9 z7*zKy3={MixvUk=enQE;ED~7tv%qh&3lR<0m??@w{ILF|e#QOyPkFYK!&Up7xWNtL zOW%1QMC<3o;G9_S1;NkPB6bqbCOjeztEc6TsBM<(q9((JKiH{01+Ud=uw9B@{;(JJ z-DxI2*{pMq`q1RQc;V8@gYAY44Z!%#W~M9pRxI(R?SJ7sy7em=Z5DbuDlr@*q|25V)($-f}9c#?D%dU^RS<(wz?{P zFFHtCab*!rl(~j@0(Nadvwg8q|4!}L^>d?0al6}Rrv9$0M#^&@zjbfJy_n!%mVHK4 z6pLRIQ^Uq~dnyy$`ay51Us6WaP%&O;@49m&{G3z7xV3dLtt1VTOMYl3UW~Rm{Eq4m zF?Zl_v;?7EFx1_+#WFUXxcK78IV)FO>42@cm@}2I%pVbZqQ}3;p;sDIm&knay03a^ zn$5}Q$G!@fTwD$e(x-~aWP0h+4NRz$KlnO_H2c< z(XX#lPuW_%H#Q+c&(nRyX1-IadKR-%$4FYC0fsCmL9ky3 zKpxyjd^JFR+vg2!=HWf}2Z?@Td`0EG`kU?{8zKrvtsm)|7>pPk9nu@2^z96aU2<#` z2QhvH5w&V;wER?mopu+nqu*n8p~(%QkwSs&*0eJwa zMXR05`OSFpfyRb!Y_+H@O%Y z0=K^y6B8Gcbl?SA)qMP3Z+=C(?8zL@=74R=EVnE?vY!1BQy2@q*RUgRx4yJ$k}MnL zs!?74QciNb-LcG*&o<9=DSL>1n}ZNd)w1z3-0Pd^4ED1{qd=9|!!N?xnXjM!EuylY z5=!H>&hSofh8V?Jofyd!h`xDI1fYAuV(sZwwN~{$a}MX^=+0TH*SFp$vyxmUv7C*W zv^3Gl0+eTFgBi3FVD;$nhcp)ka*4gSskYIqQ&+M}xP9yLAkWzBI^I%zR^l1e?bW_6 zIn{mo{dD=)9@V?s^fa55jh78rP*Ze<3`tRCN4*mpO$@7a^*2B*7N_|A(Ve2VB|)_o z$=#_=aBkhe(ifX}MLT()@5?OV+~7cXC3r!%{QJxriXo9I%*3q4KT4Xxzyd{ z9;_%=W%q!Vw$Z7F3lUnY+1HZ*lO;4;VR2+i4+D(m#01OYq|L_fbnT;KN<^dkkCwtd zF7n+O7KvAw8c`JUh6LmeIrk4`F3o|AagKSMK3))_5Cv~y2Bb2!Ibg9BO7Vkz?pAYX zoI=B}+$R22&IL`NCYUYjrdhwjnMx_v=-Qcx-jmtN>!Zqf|n1^SWrHy zK|MwJ?Z#^>)rfT5YSY{qjZ&`Fjd;^vv&gF-Yj6$9-Dy$<6zeP4s+78gS2|t%Z309b z0^fp~ue_}i`U9j!<|qF92_3oB09NqgAoehQ`)<)dSfKoJl_A6Ec#*Mx9Cpd-p#$Ez z={AM*r-bQs6*z$!*VA4|QE7bf@-4vb?Q+pPKLkY2{yKsw{&udv_2v8{Dbd zm~8VAv!G~s)`O3|Q6vFUV%8%+?ZSVUa(;fhPNg#vab@J*9XE4#D%)$UU-T5`fwjz! z6&gA^`OGu6aUk{l*h9eB?opVdrHK>Q@U>&JQ_2pR%}TyOXGq_6s56_`U(WoOaAb+K zXQr#6H}>a-GYs9^bGP2Y&hSP5gEtW+GVC4=wy0wQk=~%CSXj=GH6q z-T#s!BV`xZVxm{~jr_ezYRpqqIcXC=Oq`b{lu`Rt(IYr4B91hhVC?yg{ol4WUr3v9 zOAk2LG>CIECZ-WIs0$N}F#eoIUEtZudc7DPYIjzGqDLWk_A4#(LgacooD z2K4IWs@N`Bddm-{%oy}!k0^i6Yh)uJ1S*90>|bm3TOZxcV|ywHUb(+CeX-o1|LTZM zwU>dY3R&U)T(}5#Neh?-CWT~@{6Ke@sI)uSuzoah8COy)w)B)aslJmp`WUcjdia-0 zl2Y}&L~XfA`uYQboAJ1;J{XLhYjH){cObH3FDva+^8ioOQy%Z=xyjGLmWMrzfFoH; zEi3AG`_v+%)&lDJE;iJWJDI@-X9K5O)LD~j*PBe(wu+|%ar~C+LK1+-+lK=t# z+Xc+J7qp~5q=B~rD!x78)?1+KUIbYr^5rcl&tB-cTtj+e%{gpZZ4G~6r15+d|J(ky zjg@@UzMW0k9@S#W(1H{u;Nq(7llJbq;;4t$awM;l&(2s+$l!Ay9^Ge|34CVhr7|BG z?dAR83smef^frq9V(OH+a+ki#q&-7TkWfFM=5bsGbU(8mC;>QTCWL5ydz9s6k@?+V zcjiH`VI=59P-(-DWXZ~5DH>B^_H~;4$)KUhnmGo*G!Tq8^LjfUDO)lASN*=#AY_yS zqW9UX(VOCO&p@kHdUUgsBO0KhXxn1sprK5h8}+>IhX(nSXZKwlNsjk^M|RAaqmCZB zHBolOHYBas@&{PT=R+?d8pZu zUHfyucQ`(umXSW7o?HQ3H21M`ZJal+%*)SH1B1j6rxTlG3hx1IGJN^M7{$j(9V;MZ zRKybgVuxKo#XVM+?*yTy{W+XHaU5Jbt-UG33x{u(N-2wmw;zzPH&4DE103HV@ER86 z|FZEmQb|&1s5#`$4!Cm}&`^{(4V}OP$bk`}v6q6rm;P!H)W|2i^e{7lTk2W@jo_9q z*aw|U7#+g59Fv(5qI`#O-qPj#@_P>PC#I(GSp3DLv7x-dmYK=C7lPF8a)bxb=@)B1 zUZ`EqpXV2dR}B&r`uM}N(TS99ZT0UB%IN|0H%DcVO#T%L_chrgn#m6%x4KE*IMfjX zJ%4veCEqbXZ`H`F_+fELMC@wuy_ch%t*+Z+1I}wN#C+dRrf2X{1C8=yZ_%Pt6wL_~ zZ2NN-hXOT4P4n$QFO7yYHS-4wF1Xfr-meG9Pn;uK51?hfel`d38k{W)F*|gJLT2#T z<~>spMu4(mul-8Q3*pf=N4DcI)zzjqAgbE2eOT7~&f1W3VsdD44Ffe;3mJp-V@8UC z)|qnPc12o~$X-+U@L_lWqv-RtvB~%hLF($%Ew5w>^NR82qC_0FB z)=hP1-OEx?lLi#jnLzH}a;Nvr@JDO-zQWd}#k^an$Kwml;MrD&)sC5b`s0ZkVyPkb zt}-jOq^%_9>YZe7Y}PhW{a)c39G`kg(P4@kxjcYfgB4XOOcmezdUI7j-!gs7oAo2o zx(Ph{G+YZ`a%~kzK!HTAA5NXE-7vOFRr5oqY$rH>WI6SFvWmahFav!CfRMM3%8J&c z*p+%|-fNS_@QrFr(at!JY9jCg9F-%5{nb5Bo~z@Y9m&SHYV`49GAJjA5h~h4(G!Se zZmK{Bo7ivCfvl}@A-ptkFGcWXAzj3xfl{evi-OG(TaCn1FAHxRc{}B|x+Ua1D=I6M z!C^ZIvK6aS_c&(=OQDZfm>O`Nxsw{ta&yiYPA~@e#c%N>>#rq)k6Aru-qD4(D^v)y z*>Rs;YUbD1S8^D(ps6Jbj0K3wJw>L4m)0e(6Pee3Y?gy9i0^bZO?$*sv+xKV?WBlh zAp*;v6w!a8;A7sLB*g-^<$Z4L7|5jXxxP1}hQZ<55f9<^KJ>^mKlWSGaLcO0=$jem zWyZkRwe~u{{tU63DlCaS9$Y4CP4f?+wwa(&1ou)b>72ydrFvm`Rj-0`kBJgK@nd(*Eh!(NC{F-@=FnF&Y!q`7){YsLLHf0_B6aHc# z>WIuHTyJwIH{BJ4)2RtEauC7Yq7Cytc|S)4^*t8Va3HR zg=~sN^tp9re@w=GTx$;zOWMjcg-7X3Wk^N$n;&Kf1RgVG2}2L-(0o)54C509C&77i zrjSi{X*WV=%C17((N^6R4Ya*4#6s_L99RtQ>m(%#nQ#wrRC8Y%yxkH;d!MdY+Tw@r zjpSnK`;C-U{ATcgaxoEpP0Gf+tx);buOMlK=01D|J+ROu37qc*rD(w`#O=3*O*w9?biwNoq3WN1`&Wp8TvKj3C z3HR9ssH7a&Vr<6waJrU zdLg!ieYz%U^bmpn%;(V%%ugMk92&?_XX1K@mwnVSE6!&%P%Wdi7_h`CpScvspMx?N zQUR>oadnG17#hNc$pkTp+9lW+MBKHRZ~74XWUryd)4yd zj98$%XmIL4(9OnoeO5Fnyn&fpQ9b0h4e6EHHw*l68j;>(ya`g^S&y2{O8U>1*>4zR zq*WSI_2o$CHQ?x0!wl9bpx|Cm2+kFMR)oMud1%n2=qn5nE&t@Fgr#=Zv2?}wtEz^T z9rrj=?IH*qI5{G@Rn&}^Z{+TW}mQeb9=8b<_a`&Cm#n%n~ zU47MvCBsdXFB1+adOO)03+nczfWa#vwk#r{o{dF)QWya9v2nv43Zp3%Ps}($lA02*_g25t;|T{A5snSY?3A zrRQ~(Ygh_ebltHo1VCbJb*eOAr;4cnlXLvI>*$-#AVsGg6B1r7@;g^L zFlJ_th0vxO7;-opU@WAFe;<}?!2q?RBrFK5U{*ai@NLKZ^};Ul}beukveh?TQn;$%9=R+DX07m82gP$=}Uo_%&ngV`}Hyv8g{u z3SWzTGV|cwQuFIs7ZDOqO_fGf8Q`8MwL}eUp>q?4eqCmOTcwQuXtQckPy|4F1on8l zP*h>d+cH#XQf|+6c|S{7SF(Lg>bR~l(0uY?O{OEVlaxa5@e%T&xju=o1`=OD#qc16 zSvyH*my(dcp6~VqR;o(#@m44Lug@~_qw+HA=mS#Z^4reBy8iV?H~I;{LQWk3aKK8$bLRyt$g?-= 0 && idx < maxIdx) { + var markerKey = markerKeys[idx] + content.text = content.text.slice(0, i) + content.text.slice(i + 1) + var discussion = content.discussions[markerKey.id] + if (discussion) { + discussion[markerKey.offsetName] = i + } + i-- // We just removed the current character, we may have multiple markers with same offset + } + } +} + +function makeContentChange (oldContent, newContent) { + var markerKeys = [] + var markerIdxMap = Object.create(null) + var oldText = makePatchableText(oldContent, markerKeys, markerIdxMap) + var newText = makePatchableText(newContent, markerKeys, markerIdxMap) + var textPatches = getTextPatches(oldText, newText) + textPatches && textPatches.cl_each(function (patch) { + // If markers are present, replace changeText with an array of text and markers + var changeText = patch.a || patch.d + var textItems = [] + var lastItem = '' + var len = changeText.length + var maxIdx = markerKeys.length + for (var i = 0; i < len; i++) { + var idx = changeText.charCodeAt(i) - 0xe000 + if (idx >= 0 && idx < maxIdx) { + var markerKey = markerKeys[idx] + lastItem.length && textItems.push(lastItem) + textItems.push({ + type: 'discussion', + name: markerKey.offsetName, + id: markerKey.id + }) + lastItem = '' + } else { + lastItem += changeText[i] + } + } + if (textItems.length) { + lastItem.length && textItems.push(lastItem) + if (patch.a) { + patch.a = textItems + } else { + patch.d = textItems + } + } + }) + var propertiesPatches = getObjectPatches(oldContent.properties, newContent.properties) + var discussionsPatches = getObjectPatches( + stripDiscussionOffsets(oldContent.discussions), + stripDiscussionOffsets(newContent.discussions) + ) + var commentsPatches = getObjectPatches(oldContent.comments, newContent.comments) + if (textPatches || propertiesPatches || discussionsPatches || commentsPatches) { + return { + text: textPatches, + properties: propertiesPatches, + discussions: discussionsPatches, + comments: commentsPatches + } + } +} + +function applyContentChanges (content, contentChanges, isBackward) { + function applyObjectPatches (obj, patches) { + if (patches) { + patches.cl_each(function (patch) { + if (!patch.a ^ !isBackward) { + obj[patch.k] = patch.a || patch.d + } else { + delete obj[patch.k] + } + }) + } + } + + var markerKeys = [] + var markerIdxMap = Object.create(null) + var result = { + text: makePatchableText(content, markerKeys, markerIdxMap), + properties: cloneObject(content.properties), + discussions: stripDiscussionOffsets(content.discussions), + comments: cloneObject(content.comments) + } + + contentChanges.cl_each(function (contentChange) { + var textPatches = contentChange.text || [] + if (isBackward) { + textPatches = textPatches.slice().reverse() + } + result.text = textPatches.cl_reduce(function (text, patch) { + var isAdd = !patch.a ^ !isBackward + var textChanges = patch.a || patch.d || '' + // When no marker is present, textChanges is a string + if (typeof textChanges === 'string') { + textChanges = [textChanges] + } + var textChange = textChanges.cl_map(function (textChange) { + if (!textChange.type) { + // textChange is a string + return textChange + } + // textChange is a marker + var markerKey = textChange.id + textChange.name + var idx = markerIdxMap[markerKey] + if (idx === undefined) { + idx = markerKeys.length + markerIdxMap[markerKey] = idx + markerKeys.push({ + id: textChange.id, + offsetName: textChange.name + }) + } + return String.fromCharCode(0xe000 + idx) + }).join('') + if (!textChange) { + return text + } else if (isAdd) { + return text.slice(0, patch.o).concat(textChange).concat(text.slice(patch.o)) + } else { + return text.slice(0, patch.o).concat(text.slice(patch.o + textChange.length)) + } + }, result.text) + + applyObjectPatches(result.properties, contentChange.properties) + applyObjectPatches(result.discussions, contentChange.discussions) + applyObjectPatches(result.comments, contentChange.comments) + }) + + restoreDiscussionOffsets(result, markerKeys) + return result +} + +function serializeObject (obj) { + return JSON.stringify(obj, function (key, value) { + return Object.prototype.toString.call(value) === '[object Object]' + ? Object.keys(value).sort().cl_reduce(function (sorted, key) { + sorted[key] = value[key] + return sorted + }, {}) + : value + }) +} + +function hashArray (arr, valueHash, valueArray) { + var hash = [] + arr.cl_each(function (obj) { + var serializedObj = serializeObject(obj) + var objHash = valueHash[serializedObj] + if (objHash === undefined) { + objHash = valueArray.length + valueArray.push(obj) + valueHash[serializedObj] = objHash + } + hash.push(objHash) + }) + return String.fromCharCode.apply(null, hash) +} + +function hashObject (obj, valueHash, valueArray) { + return hashArray(Object.keys(obj || {}).sort().cl_map(function (key) { + return [key, obj[key]] + }), valueHash, valueArray) +} + +function mergeText (oldText, newText, serverText) { + var diffs = diffMatchPatch.diff_main(oldText, newText) + diffMatchPatch.diff_cleanupSemantic(diffs) + var patches = diffMatchPatch.patch_make(oldText, diffs) + var patchResult = diffMatchPatch.patch_apply(patches, serverText) + if (!patchResult[1] + .cl_some(function (changeApplied) { + return !changeApplied + })) { + return patchResult[0] + } + + diffs = diffMatchPatchStrict.diff_main(patchResult[0], newText) + diffMatchPatch.diff_cleanupSemantic(diffs) + return diffs.cl_map(function (diff) { + return diff[1] + }).join('') +} + +function quickPatch (oldStr, newStr, destStr, strict) { + var dmp = strict ? diffMatchPatchStrict : diffMatchPatch + var diffs = dmp.diff_main(oldStr, newStr) + var patches = dmp.patch_make(oldStr, diffs) + var patchResult = dmp.patch_apply(patches, destStr) + return patchResult[0] +} + +function mergeObjects (oldObject, newObject, serverObject) { + var mergedObject = ({}).cl_extend(newObject).cl_extend(serverObject) + mergedObject.cl_each(function (value, key) { + if (!oldObject[key]) { + return // There might be conflict, keep the server value + } + var newValue = newObject[key] && serializeObject(newObject[key]) + var serverValue = serverObject[key] && serializeObject(serverObject[key]) + if (newValue === serverValue) { + return // no conflict + } + var oldValue = serializeObject(oldObject[key]) + if (oldValue !== newValue && !serverValue) { + return // Removed on server but changed on client + } + if (oldValue !== serverValue && !newValue) { + return // Removed on client but changed on server + } + if (oldValue !== newValue && oldValue === serverValue) { + // Take the client value + if (!newValue) { + delete mergedObject[key] + } else { + mergedObject[key] = newObject[key] + } + } else if (oldValue !== serverValue && oldValue === newValue) { + // Take the server value + if (!serverValue) { + delete mergedObject[key] + } + } + // Take the server value otherwise + }) + return cloneObject(mergedObject) +} + +function mergeFlattenContent (oldContent, newContent, serverContent) { + var markerKeys = [] + var markerIdxMap = Object.create(null) + var oldText = makePatchableText(oldContent, markerKeys, markerIdxMap) + var serverText = makePatchableText(serverContent, markerKeys, markerIdxMap) + var localText = makePatchableText(newContent, markerKeys, markerIdxMap) + var isServerTextChanges = oldText !== serverText + var isTextSynchronized = serverText === localText + + var result = { + text: isTextSynchronized || !isServerTextChanges + ? localText + : mergeText(oldText, serverText, localText), + properties: mergeObjects( + oldContent.properties, + newContent.properties, + serverContent.properties + ), + discussions: mergeObjects( + stripDiscussionOffsets(oldContent.discussions), + stripDiscussionOffsets(newContent.discussions), + stripDiscussionOffsets(serverContent.discussions) + ), + comments: mergeObjects( + oldContent.comments, + newContent.comments, + serverContent.comments + ) + } + restoreDiscussionOffsets(result, markerKeys) + return result +} + +export default clDiffUtils; diff --git a/src/cledit/cledit.js b/src/cledit/cledit.js new file mode 100644 index 00000000..966e11f2 --- /dev/null +++ b/src/cledit/cledit.js @@ -0,0 +1,11 @@ +import 'clunderscore'; +import cledit from './cleditCore'; +import './cleditHighlighter'; +import './cleditKeystroke'; +import './cleditMarker'; +import './cleditSelectionMgr'; +import './cleditUndoMgr'; +import './cleditUtils'; +import './cleditWatcher'; + +export default cledit; diff --git a/src/cledit/cleditCore.js b/src/cledit/cleditCore.js new file mode 100644 index 00000000..d6174aee --- /dev/null +++ b/src/cledit/cleditCore.js @@ -0,0 +1,368 @@ +var DiffMatchPatch = require('diff-match-patch'); + +function cledit(contentElt, scrollElt, windowParam) { + scrollElt = scrollElt || contentElt + var editor = { + $contentElt: contentElt, + $scrollElt: scrollElt, + $window: windowParam || window, + $keystrokes: [], + $markers: {} + } + editor.$document = editor.$window.document + cledit.Utils.createEventHooks(editor) + var debounce = cledit.Utils.debounce + + editor.toggleEditable = function (isEditable) { + if (isEditable === undefined) { + isEditable = !contentElt.contentEditable + } + contentElt.contentEditable = isEditable + } + editor.toggleEditable(true) + + function getTextContent() { + var textContent = contentElt.textContent.replace(/\r[\n\u0085]?|[\u2424\u2028\u0085]/g, '\n') // Markdown-it sanitization (Mac/DOS to Unix) + if (textContent.slice(-1) !== '\n') { + textContent += '\n' + } + return textContent + } + + var lastTextContent = getTextContent() + var highlighter = new cledit.Highlighter(editor) + + var sectionList + + function parseSections(content, isInit) { + sectionList = highlighter.parseSections(content, isInit) + editor.$allElements = Array.prototype.slice.call(contentElt.querySelectorAll('.cledit-section *')) + return sectionList + } + + // Used to detect editor changes + var watcher = new cledit.Watcher(editor, checkContentChange) + watcher.startWatching() + + /* eslint-disable new-cap */ + var diffMatchPatch = new DiffMatchPatch() + /* eslint-enable new-cap */ + var selectionMgr = new cledit.SelectionMgr(editor) + + function adjustCursorPosition(force) { + selectionMgr.saveSelectionState(true, true, force) + } + + function replaceContent(selectionStart, selectionEnd, replacement) { + var min = Math.min(selectionStart, selectionEnd) + var max = Math.max(selectionStart, selectionEnd) + var range = selectionMgr.createRange(min, max) + var rangeText = '' + range + // Range can contain a br element, which is not taken into account in rangeText + if (rangeText.length === max - min && rangeText === replacement) { + return + } + range.deleteContents() + range.insertNode(editor.$document.createTextNode(replacement)) + return range + } + + var ignoreUndo = false + var noContentFix = false + + function setContent(value, noUndo, maxStartOffset) { + var textContent = getTextContent() + maxStartOffset = maxStartOffset !== undefined && maxStartOffset < textContent.length ? maxStartOffset : textContent.length - 1 + var startOffset = Math.min( + diffMatchPatch.diff_commonPrefix(textContent, value), + maxStartOffset + ) + var endOffset = Math.min( + diffMatchPatch.diff_commonSuffix(textContent, value), + textContent.length - startOffset, + value.length - startOffset + ) + var replacement = value.substring(startOffset, value.length - endOffset) + var range = replaceContent(startOffset, textContent.length - endOffset, replacement) + if (range) { + ignoreUndo = noUndo + noContentFix = true + } + return { + start: startOffset, + end: value.length - endOffset, + range: range + } + } + + function replace(selectionStart, selectionEnd, replacement) { + undoMgr.setDefaultMode('single') + replaceContent(selectionStart, selectionEnd, replacement) + var endOffset = selectionStart + replacement.length + selectionMgr.setSelectionStartEnd(endOffset, endOffset) + selectionMgr.updateCursorCoordinates(true) + } + + function replaceAll(search, replacement) { + undoMgr.setDefaultMode('single') + var textContent = getTextContent() + var value = textContent.replace(search, replacement) + if (value !== textContent) { + var offset = editor.setContent(value) + selectionMgr.setSelectionStartEnd(offset.end, offset.end) + selectionMgr.updateCursorCoordinates(true) + } + } + + function focus() { + selectionMgr.restoreSelection() + } + + var undoMgr = new cledit.UndoMgr(editor) + + function addMarker(marker) { + editor.$markers[marker.id] = marker + } + + function removeMarker(marker) { + delete editor.$markers[marker.id] + } + + var triggerSpellCheck = debounce(function () { + var selection = editor.$window.getSelection() + if (!selectionMgr.hasFocus || highlighter.isComposing || selectionMgr.selectionStart !== selectionMgr.selectionEnd || !selection.modify) { + return + } + // Hack for Chrome to trigger the spell checker + if (selectionMgr.selectionStart) { + selection.modify('move', 'backward', 'character') + selection.modify('move', 'forward', 'character') + } else { + selection.modify('move', 'forward', 'character') + selection.modify('move', 'backward', 'character') + } + }, 10) + + function checkContentChange(mutations) { + watcher.noWatch(function () { + var removedSections = [] + var modifiedSections = [] + + function markModifiedSection(node) { + while (node && node !== contentElt) { + if (node.section) { + var array = node.parentNode ? modifiedSections : removedSections + return array.indexOf(node.section) === -1 && array.push(node.section) + } + node = node.parentNode + } + } + + mutations.cl_each(function (mutation) { + markModifiedSection(mutation.target) + mutation.addedNodes.cl_each(markModifiedSection) + mutation.removedNodes.cl_each(markModifiedSection) + }) + highlighter.fixContent(modifiedSections, removedSections, noContentFix) + noContentFix = false + }) + + var newTextContent = getTextContent() + var diffs = diffMatchPatch.diff_main(lastTextContent, newTextContent) + editor.$markers.cl_each(function (marker) { + marker.adjustOffset(diffs) + }) + + selectionMgr.saveSelectionState() + var sectionList = parseSections(newTextContent) + editor.$trigger('contentChanged', newTextContent, diffs, sectionList) + if (!ignoreUndo) { + undoMgr.addDiffs(lastTextContent, newTextContent, diffs) + undoMgr.setDefaultMode('typing') + undoMgr.saveState() + } + ignoreUndo = false + lastTextContent = newTextContent + triggerSpellCheck() + } + + function setSelection(start, end) { + end = end === undefined ? start : end + selectionMgr.setSelectionStartEnd(start, end) + selectionMgr.updateCursorCoordinates() + } + + function keydownHandler(handler) { + return function (evt) { + if ( + evt.which !== 17 && // Ctrl + evt.which !== 91 && // Cmd + evt.which !== 18 && // Alt + evt.which !== 16 // Shift + ) { + handler(evt) + } + } + } + + function tryDestroy() { + if (!editor.$window.document.contains(contentElt)) { + watcher.stopWatching() + editor.$window.removeEventListener('keydown', windowKeydownListener) + editor.$window.removeEventListener('mouseup', windowMouseupListener) + editor.$trigger('destroy') + return true + } + } + + // In case of Ctrl/Cmd+A outside the editor element + function windowKeydownListener(evt) { + if (!tryDestroy()) { + keydownHandler(function () { + adjustCursorPosition() + })(evt) + } + } + editor.$window.addEventListener('keydown', windowKeydownListener, false) + + // Mouseup can happen outside the editor element + function windowMouseupListener() { + if (!tryDestroy()) { + selectionMgr.saveSelectionState(true, false) + } + } + editor.$window.addEventListener('mouseup', windowMouseupListener) + // This can also provoke selection changes and does not fire mouseup event on Chrome/OSX + contentElt.addEventListener('contextmenu', selectionMgr.saveSelectionState.cl_bind(selectionMgr, true, false)) + + contentElt.addEventListener('keydown', keydownHandler(function (evt) { + selectionMgr.saveSelectionState() + adjustCursorPosition() + + // Perform keystroke + var textContent = getTextContent() + var min = Math.min(selectionMgr.selectionStart, selectionMgr.selectionEnd) + var max = Math.max(selectionMgr.selectionStart, selectionMgr.selectionEnd) + var state = { + before: textContent.slice(0, min), + after: textContent.slice(max), + selection: textContent.slice(min, max), + isBackwardSelection: selectionMgr.selectionStart > selectionMgr.selectionEnd + } + editor.$keystrokes.cl_some(function (keystroke) { + if (keystroke.handler(evt, state, editor)) { + editor.setContent(state.before + state.selection + state.after, false, min) + min = state.before.length + max = min + state.selection.length + selectionMgr.setSelectionStartEnd( + state.isBackwardSelection ? max : min, + state.isBackwardSelection ? min : max + ) + return true + } + }) + }), false) + + contentElt.addEventListener('compositionstart', function () { + highlighter.isComposing++ + }, false) + + contentElt.addEventListener('compositionend', function () { + setTimeout(function () { + highlighter.isComposing && highlighter.isComposing-- + }, 0) + }, false) + + contentElt.addEventListener('paste', function (evt) { + undoMgr.setCurrentMode('single') + evt.preventDefault() + var data + var clipboardData = evt.clipboardData + if (clipboardData) { + data = clipboardData.getData('text/plain') + } else { + clipboardData = editor.$window.clipboardData + data = clipboardData && clipboardData.getData('Text') + } + if (!data) { + return + } + replace(selectionMgr.selectionStart, selectionMgr.selectionEnd, data) + adjustCursorPosition() + }, false) + + contentElt.addEventListener('cut', function () { + undoMgr.setCurrentMode('single') + adjustCursorPosition() + }, false) + + contentElt.addEventListener('focus', function () { + selectionMgr.hasFocus = true + editor.$trigger('focus') + }, false) + + contentElt.addEventListener('blur', function () { + selectionMgr.hasFocus = false + editor.$trigger('blur') + }, false) + + function addKeystroke(keystrokes) { + if (!Array.isArray(keystrokes)) { + keystrokes = [keystrokes] + } + editor.$keystrokes = editor.$keystrokes.concat(keystrokes).sort(function (keystroke1, keystroke2) { + return keystroke1.priority - keystroke2.priority + }) + } + addKeystroke(cledit.defaultKeystrokes) + + editor.selectionMgr = selectionMgr + editor.undoMgr = undoMgr + editor.highlighter = highlighter + editor.watcher = watcher + editor.adjustCursorPosition = adjustCursorPosition + editor.setContent = setContent + editor.replace = replace + editor.replaceAll = replaceAll + editor.getContent = getTextContent + editor.focus = focus + editor.setSelection = setSelection + editor.addKeystroke = addKeystroke + editor.addMarker = addMarker + editor.removeMarker = removeMarker + + editor.init = function (options) { + options = ({ + cursorFocusRatio: 0.2, + sectionHighlighter: function (section) { + return section.text.replace(/&/g, '&').replace(/' + + this.fixContent = function (modifiedSections, removedSections, noContentFix) { + modifiedSections.cl_each(function (section) { + section.forceHighlighting = true + if (!noContentFix) { + if (useBr) { + section.elt.getElementsByClassName('hd-lf').cl_each(function (lfElt) { + lfElt.parentNode.removeChild(lfElt) + }) + section.elt.getElementsByTagName('br').cl_each(function (brElt) { + brElt.parentNode.replaceChild(editor.$document.createTextNode('\n'), brElt) + }) + } + if (section.elt.textContent.slice(-1) !== '\n') { + section.elt.appendChild(editor.$document.createTextNode('\n')) + } + } + }) + } + + this.addTrailingNode = function () { + this.trailingNode = editor.$document.createElement(trailingNodeTag) + contentElt.appendChild(this.trailingNode) + } + + function Section(text) { + this.text = text.text === undefined ? text : text.text + this.data = text.data + } + + Section.prototype.setElement = function (elt) { + this.elt = elt + elt.section = this + } + + this.parseSections = function (content, isInit) { + if (this.isComposing) { + return sectionList + } + + var newSectionList = editor.options.sectionParser ? editor.options.sectionParser(content) : [content] + newSectionList = newSectionList.cl_map(function (sectionText) { + return new Section(sectionText) + }) + + var modifiedSections = [] + var sectionsToRemove = [] + insertBeforeSection = undefined + + if (isInit) { + // Render everything if isInit + sectionsToRemove = sectionList + sectionList = newSectionList + modifiedSections = newSectionList + } else { + // Find modified section starting from top + var leftIndex = sectionList.length + sectionList.cl_some(function (section, index) { + var newSection = newSectionList[index] + if (index >= newSectionList.length || + section.forceHighlighting || + // Check text modification + section.text !== newSection.text || + // Check that section has not been detached or moved + section.elt.parentNode !== contentElt || + // Check also the content since nodes can be injected in sections via copy/paste + section.elt.textContent !== newSection.text) { + leftIndex = index + return true + } + }) + + // Find modified section starting from bottom + var rightIndex = -sectionList.length + sectionList.slice().reverse().cl_some(function (section, index) { + var newSection = newSectionList[newSectionList.length - index - 1] + if (index >= newSectionList.length || + section.forceHighlighting || + // Check modified + section.text !== newSection.text || + // Check that section has not been detached or moved + section.elt.parentNode !== contentElt || + // Check also the content since nodes can be injected in sections via copy/paste + section.elt.textContent !== newSection.text) { + rightIndex = -index + return true + } + }) + + if (leftIndex - rightIndex > sectionList.length) { + // Prevent overlap + rightIndex = leftIndex - sectionList.length + } + + var leftSections = sectionList.slice(0, leftIndex) + modifiedSections = newSectionList.slice(leftIndex, newSectionList.length + rightIndex) + var rightSections = sectionList.slice(sectionList.length + rightIndex, sectionList.length) + insertBeforeSection = rightSections[0] + sectionsToRemove = sectionList.slice(leftIndex, sectionList.length + rightIndex) + sectionList = leftSections.concat(modifiedSections).concat(rightSections) + } + + var newSectionEltList = editor.$document.createDocumentFragment() + modifiedSections.cl_each(function (section) { + section.forceHighlighting = false + highlight(section) + newSectionEltList.appendChild(section.elt) + }) + editor.watcher.noWatch(function () { + if (isInit) { + contentElt.innerHTML = '' + contentElt.appendChild(newSectionEltList) + return this.addTrailingNode() + } + + // Remove outdated sections + sectionsToRemove.cl_each(function (section) { + // section may be already removed + section.elt.parentNode === contentElt && contentElt.removeChild(section.elt) + // To detect sections that come back with built-in undo + section.elt.section = undefined + }) + + if (insertBeforeSection !== undefined) { + contentElt.insertBefore(newSectionEltList, insertBeforeSection.elt) + } else { + contentElt.appendChild(newSectionEltList) + } + + // Remove unauthorized nodes (text nodes outside of sections or duplicated sections via copy/paste) + var childNode = contentElt.firstChild + while (childNode) { + var nextNode = childNode.nextSibling + if (!childNode.section) { + contentElt.removeChild(childNode) + } + childNode = nextNode + } + this.addTrailingNode() + self.$trigger('highlighted') + editor.selectionMgr.restoreSelection() + editor.selectionMgr.updateCursorCoordinates() + }.cl_bind(this)) + + return sectionList + } + + function highlight(section) { + var html = editor.options.sectionHighlighter(section).replace(/\n/g, lfHtml) + var sectionElt = editor.$document.createElement('div') + sectionElt.className = 'cledit-section' + sectionElt.innerHTML = html + section.setElement(sectionElt) + self.$trigger('sectionHighlighted', section) + } +} + +cledit.Highlighter = Highlighter + diff --git a/src/cledit/cleditKeystroke.js b/src/cledit/cleditKeystroke.js new file mode 100644 index 00000000..0dedbbce --- /dev/null +++ b/src/cledit/cleditKeystroke.js @@ -0,0 +1,183 @@ +var cledit = require('./cleditCore') + +function Keystroke(handler, priority) { + this.handler = handler + this.priority = priority || 100 +} + +cledit.Keystroke = Keystroke + +var clearNewline +var charTypes = Object.create(null) + +// Word separators, as in Sublime Text +'./\\()"\'-:,.;<>~!@#$%^&*|+=[]{}`~?'.split('').cl_each(function (wordSeparator) { + charTypes[wordSeparator] = 'wordSeparator' +}) +charTypes[' '] = 'space' +charTypes['\t'] = 'space' +charTypes['\n'] = 'newLine' + +function getNextWordOffset(text, offset, isBackward) { + var previousType + while ((isBackward && offset > 0) || (!isBackward && offset < text.length)) { + var currentType = charTypes[isBackward ? text[offset - 1] : text[offset]] || 'word' + if (previousType && currentType !== previousType) { + if (previousType === 'word' || currentType === 'space' || previousType === 'newLine' || currentType === 'newLine') { + break + } + } + previousType = currentType + isBackward ? offset-- : offset++ + } + return offset +} + +cledit.defaultKeystrokes = [ + + new Keystroke(function (evt, state, editor) { + if ((!evt.ctrlKey && !evt.metaKey) || evt.altKey) { + return + } + var keyCode = evt.charCode || evt.keyCode + var keyCodeChar = String.fromCharCode(keyCode).toLowerCase() + var action + switch (keyCodeChar) { + case 'y': + action = 'redo' + break + case 'z': + action = evt.shiftKey ? 'redo' : 'undo' + break + } + if (action) { + evt.preventDefault() + setTimeout(function () { + editor.undoMgr[action]() + }, 10) + return true + } + }), + + new Keystroke(function (evt, state) { + if (evt.which !== 9 /* tab */ || evt.metaKey || evt.ctrlKey) { + return + } + + function strSplice(str, i, remove, add) { + remove = +remove || 0 + add = add || '' + return str.slice(0, i) + add + str.slice(i + remove) + } + + evt.preventDefault() + var isInverse = evt.shiftKey + var lf = state.before.lastIndexOf('\n') + 1 + if (isInverse) { + if (/\s/.test(state.before.charAt(lf))) { + state.before = strSplice(state.before, lf, 1) + } + state.selection = state.selection.replace(/^[ \t]/gm, '') + } else { + if (state.selection) { + state.before = strSplice(state.before, lf, 0, '\t') + state.selection = state.selection.replace(/\n(?=[\s\S])/g, '\n\t') + } else { + state.before += '\t' + } + } + return true + }), + + new Keystroke(function (evt, state, editor) { + if (evt.which !== 13 /* enter */) { + clearNewline = false + return + } + + evt.preventDefault() + var lf = state.before.lastIndexOf('\n') + 1 + if (clearNewline) { + state.before = state.before.substring(0, lf) + state.selection = '' + clearNewline = false + return true + } + clearNewline = false + var previousLine = state.before.slice(lf) + var indent = previousLine.match(/^\s*/)[0] + if (indent.length) { + clearNewline = true + } + + editor.undoMgr.setCurrentMode('single') + state.before += '\n' + indent + state.selection = '' + return true + }), + + new Keystroke(function (evt, state, editor) { + if (evt.which !== 8 /* backspace */ && evt.which !== 46 /* delete */) { + return + } + + editor.undoMgr.setCurrentMode('delete') + if (!state.selection) { + var isJump = (cledit.Utils.isMac && evt.altKey) || (!cledit.Utils.isMac && evt.ctrlKey) + if (isJump) { + // Custom kill word behavior + var text = state.before + state.after + var offset = getNextWordOffset(text, state.before.length, evt.which === 8) + if (evt.which === 8) { + state.before = state.before.slice(0, offset) + } else { + state.after = state.after.slice(offset - text.length) + } + evt.preventDefault() + return true + } else if (evt.which === 8 && state.before.slice(-1) === '\n') { + // Special treatment for end of lines + state.before = state.before.slice(0, -1) + evt.preventDefault() + return true + } else if (evt.which === 46 && state.after.slice(0, 1) === '\n') { + state.after = state.after.slice(1) + evt.preventDefault() + return true + } + } else { + state.selection = '' + evt.preventDefault() + return true + } + }), + + new Keystroke(function (evt, state, editor) { + if (evt.which !== 37 /* left arrow */ && evt.which !== 39 /* right arrow */) { + return + } + var isJump = (cledit.Utils.isMac && evt.altKey) || (!cledit.Utils.isMac && evt.ctrlKey) + if (!isJump) { + return + } + + // Custom jump behavior + var textContent = editor.getContent() + var offset = getNextWordOffset(textContent, editor.selectionMgr.selectionEnd, evt.which === 37) + if (evt.shiftKey) { + // rebuild the state completely + var min = Math.min(editor.selectionMgr.selectionStart, offset) + var max = Math.max(editor.selectionMgr.selectionStart, offset) + state.before = textContent.slice(0, min) + state.after = textContent.slice(max) + state.selection = textContent.slice(min, max) + state.isBackwardSelection = editor.selectionMgr.selectionStart > offset + } else { + state.before = textContent.slice(0, offset) + state.after = textContent.slice(offset) + state.selection = '' + } + evt.preventDefault() + return true + }) +] diff --git a/src/cledit/cleditMarker.js b/src/cledit/cleditMarker.js new file mode 100644 index 00000000..590688b1 --- /dev/null +++ b/src/cledit/cleditMarker.js @@ -0,0 +1,44 @@ +var cledit = require('./cleditCore') + +var DIFF_DELETE = -1 +var DIFF_INSERT = 1 +var DIFF_EQUAL = 0 + +var idCounter = 0 + +function Marker(offset, trailing) { + this.id = idCounter++ + this.offset = offset + this.trailing = trailing +} + +Marker.prototype.adjustOffset = function (diffs) { + var startOffset = 0 + diffs.cl_each(function (diff) { + var diffType = diff[0] + var diffText = diff[1] + var diffOffset = diffText.length + switch (diffType) { + case DIFF_EQUAL: + startOffset += diffOffset + break + case DIFF_INSERT: + if ( + this.trailing + ? this.offset > startOffset + : this.offset >= startOffset + ) { + this.offset += diffOffset + } + startOffset += diffOffset + break + case DIFF_DELETE: + if (this.offset > startOffset) { + this.offset -= Math.min(diffOffset, this.offset - startOffset) + } + break + } + }.cl_bind(this)) +} + +cledit.Marker = Marker diff --git a/src/cledit/cleditSelectionMgr.js b/src/cledit/cleditSelectionMgr.js new file mode 100644 index 00000000..2f8bad6f --- /dev/null +++ b/src/cledit/cleditSelectionMgr.js @@ -0,0 +1,399 @@ +var cledit = require('./cleditCore') + +function SelectionMgr(editor) { + var debounce = cledit.Utils.debounce + var contentElt = editor.$contentElt + var scrollElt = editor.$scrollElt + cledit.Utils.createEventHooks(this) + + var self = this + var lastSelectionStart = 0 + var lastSelectionEnd = 0 + this.selectionStart = 0 + this.selectionEnd = 0 + this.cursorCoordinates = {} + this.adjustTop = 0 + this.adjustBottom = 0 + + this.findContainer = function (offset) { + var result = cledit.Utils.findContainer(contentElt, offset) + if (result.container.nodeValue === '\n') { + var hdLfElt = result.container.parentNode + if (hdLfElt.className === 'hd-lf' && hdLfElt.previousSibling && hdLfElt.previousSibling.tagName === 'BR') { + result.container = hdLfElt.parentNode + result.offsetInContainer = Array.prototype.indexOf.call(result.container.childNodes, result.offsetInContainer === 0 ? hdLfElt.previousSibling : hdLfElt) + } + } + return result + } + + this.createRange = function (start, end) { + var range = editor.$document.createRange() + if (start === end) { + end = start = isNaN(start) ? start : this.findContainer(start < 0 ? 0 : start) + } else { + start = isNaN(start) ? start : this.findContainer(start < 0 ? 0 : start) + end = isNaN(end) ? end : this.findContainer(end < 0 ? 0 : end) + } + range.setStart(start.container, start.offsetInContainer) + range.setEnd(end.container, end.offsetInContainer) + return range + } + + var adjustScroll + var debouncedUpdateCursorCoordinates = debounce(function () { + var coordinates = this.getCoordinates(this.selectionEnd, this.selectionEndContainer, this.selectionEndOffset) + if (this.cursorCoordinates.top !== coordinates.top || + this.cursorCoordinates.height !== coordinates.height || + this.cursorCoordinates.left !== coordinates.left + ) { + this.cursorCoordinates = coordinates + this.$trigger('cursorCoordinatesChanged', coordinates) + } + if (adjustScroll) { + var adjustTop, adjustBottom + adjustTop = adjustBottom = scrollElt.clientHeight / 2 * editor.options.cursorFocusRatio + adjustTop = this.adjustTop || adjustTop + adjustBottom = this.adjustBottom || adjustTop + if (adjustTop && adjustBottom) { + var cursorMinY = scrollElt.scrollTop + adjustTop + var cursorMaxY = scrollElt.scrollTop + scrollElt.clientHeight - adjustBottom + if (this.cursorCoordinates.top < cursorMinY) { + scrollElt.scrollTop += this.cursorCoordinates.top - cursorMinY + } else if (this.cursorCoordinates.top + this.cursorCoordinates.height > cursorMaxY) { + scrollElt.scrollTop += this.cursorCoordinates.top + this.cursorCoordinates.height - cursorMaxY + } + } + } + adjustScroll = false + }.cl_bind(this)) + + this.updateCursorCoordinates = function (adjustScrollParam) { + adjustScroll = adjustScroll || adjustScrollParam + debouncedUpdateCursorCoordinates() + } + + var oldSelectionRange + + function checkSelection(selectionRange) { + if (!oldSelectionRange || + oldSelectionRange.startContainer !== selectionRange.startContainer || + oldSelectionRange.startOffset !== selectionRange.startOffset || + oldSelectionRange.endContainer !== selectionRange.endContainer || + oldSelectionRange.endOffset !== selectionRange.endOffset + ) { + oldSelectionRange = selectionRange + self.$trigger('selectionChanged', self.selectionStart, self.selectionEnd, selectionRange) + return true + } + } + + this.restoreSelection = function () { + var min = Math.min(this.selectionStart, this.selectionEnd) + var max = Math.max(this.selectionStart, this.selectionEnd) + var selectionRange = this.createRange(min, max) + if (editor.$document.contains(selectionRange.commonAncestorContainer)) { + var selection = editor.$window.getSelection() + selection.removeAllRanges() + var isBackward = this.selectionStart > this.selectionEnd + if (selection.extend) { + var beginRange = selectionRange.cloneRange() + beginRange.collapse(!isBackward) + selection.addRange(beginRange) + if (isBackward) { + selection.extend(selectionRange.startContainer, selectionRange.startOffset) + } else { + selection.extend(selectionRange.endContainer, selectionRange.endOffset) + } + } else { + selection.addRange(selectionRange) + } + checkSelection(selectionRange) + return selectionRange + } + } + + var saveLastSelection = debounce(function () { + lastSelectionStart = self.selectionStart + lastSelectionEnd = self.selectionEnd + }, 50) + + function setSelection(start, end) { + if (start === undefined) { + start = self.selectionStart + } + if (start < 0) { + start = 0 + } + if (end === undefined) { + end = this.selectionEnd + } + if (end < 0) { + end = 0 + } + self.selectionStart = start + self.selectionEnd = end + saveLastSelection() + } + + this.setSelectionStartEnd = function (start, end, focus) { + setSelection(start, end) + return focus !== false && this.restoreSelection() + } + + this.saveSelectionState = (function () { + // Credit: https://github.com/timdown/rangy + function arrayContains(arr, val) { + var i = arr.length + while (i--) { + if (arr[i] === val) { + return true + } + } + return false + } + + function getClosestAncestorIn(node, ancestor, selfIsAncestor) { + var p + var n = selfIsAncestor ? node : node.parentNode + while (n) { + p = n.parentNode + if (p === ancestor) { + return n + } + n = p + } + return null + } + + function getNodeIndex(node) { + var i = 0 + while ((node = node.previousSibling)) { + ++i + } + return i + } + + function getCommonAncestor(node1, node2) { + var ancestors = [] + var n + for (n = node1; n; n = n.parentNode) { + ancestors.push(n) + } + + for (n = node2; n; n = n.parentNode) { + if (arrayContains(ancestors, n)) { + return n + } + } + + return null + } + + function comparePoints(nodeA, offsetA, nodeB, offsetB) { + // See http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-Range-Comparing + var nodeC, root, childA, childB, n + if (nodeA === nodeB) { + // Case 1: nodes are the same + return offsetA === offsetB ? 0 : (offsetA < offsetB) ? -1 : 1 + } else if ( + (nodeC = getClosestAncestorIn(nodeB, nodeA, true)) + ) { + // Case 2: node C (container B or an ancestor) is a child node of A + return offsetA <= getNodeIndex(nodeC) ? -1 : 1 + } else if ( + (nodeC = getClosestAncestorIn(nodeA, nodeB, true)) + ) { + // Case 3: node C (container A or an ancestor) is a child node of B + return getNodeIndex(nodeC) < offsetB ? -1 : 1 + } else { + root = getCommonAncestor(nodeA, nodeB) + if (!root) { + throw new Error('comparePoints error: nodes have no common ancestor') + } + + // Case 4: containers are siblings or descendants of siblings + childA = (nodeA === root) ? root : getClosestAncestorIn(nodeA, root, true) + childB = (nodeB === root) ? root : getClosestAncestorIn(nodeB, root, true) + + if (childA === childB) { + // This shouldn't be possible + throw module.createError('comparePoints got to case 4 and childA and childB are the same!') + } else { + n = root.firstChild + while (n) { + if (n === childA) { + return -1 + } else if (n === childB) { + return 1 + } + n = n.nextSibling + } + } + } + } + + function save() { + var selectionStart = self.selectionStart + var selectionEnd = self.selectionEnd + var selection = editor.$window.getSelection() + var result + if (selection.rangeCount > 0) { + var selectionRange = selection.getRangeAt(0) + var node = selectionRange.startContainer + if ((contentElt.compareDocumentPosition(node) & window.Node.DOCUMENT_POSITION_CONTAINED_BY) || contentElt === node) { + var offset = selectionRange.startOffset + if (node.firstChild && offset > 0) { + node = node.childNodes[offset - 1] + offset = node.textContent.length + } + var container = node + while (node !== contentElt) { + while ((node = node.previousSibling)) { + offset += (node.textContent || '').length + } + node = container = container.parentNode + } + var selectionText = selectionRange + '' + // Fix end of line when only br is selected + var brElt = selectionRange.endContainer.firstChild + if (brElt && brElt.tagName === 'BR' && selectionRange.endOffset === 1) { + selectionText += '\n' + } + if (comparePoints(selection.anchorNode, selection.anchorOffset, selection.focusNode, selection.focusOffset) === 1) { + selectionStart = offset + selectionText.length + selectionEnd = offset + } else { + selectionStart = offset + selectionEnd = offset + selectionText.length + } + + if (selectionStart === selectionEnd && selectionStart === editor.getContent().length) { + // If cursor is after the trailingNode + selectionStart = --selectionEnd + result = self.setSelectionStartEnd(selectionStart, selectionEnd) + } else { + setSelection(selectionStart, selectionEnd) + result = checkSelection(selectionRange) + result = result || lastSelectionStart !== self.selectionStart // selectionRange doesn't change when selection is at the start of a section + } + } + } + return result + } + + function saveCheckChange() { + return save() && (lastSelectionStart !== self.selectionStart || lastSelectionEnd !== self.selectionEnd) + } + + var nextTickAdjustScroll = false + var debouncedSave = debounce(function () { + self.updateCursorCoordinates(saveCheckChange() && nextTickAdjustScroll) + // In some cases we have to wait a little longer to see the selection change (Cmd+A on Chrome OSX) + longerDebouncedSave() + }) + var longerDebouncedSave = debounce(function () { + self.updateCursorCoordinates(saveCheckChange() && nextTickAdjustScroll) + nextTickAdjustScroll = false + }, 10) + + return function (debounced, adjustScroll, forceAdjustScroll) { + if (forceAdjustScroll) { + lastSelectionStart = undefined + lastSelectionEnd = undefined + } + if (debounced) { + nextTickAdjustScroll = nextTickAdjustScroll || adjustScroll + return debouncedSave() + } else { + save() + } + } + })() + + this.getSelectedText = function () { + var min = Math.min(this.selectionStart, this.selectionEnd) + var max = Math.max(this.selectionStart, this.selectionEnd) + return editor.getContent().substring(min, max) + } + + this.getCoordinates = function (inputOffset, container, offsetInContainer) { + if (!container) { + var offset = this.findContainer(inputOffset) + container = offset.container + offsetInContainer = offset.offsetInContainer + } + var containerElt = container + if (!containerElt.hasChildNodes()) { + containerElt = container.parentNode + } + var isInvisible = false + var index = editor.$allElements.indexOf(containerElt) + while (containerElt.offsetHeight === 0 && index > 0) { + isInvisible = true + containerElt = editor.$allElements[--index] + } + var rect + var contentRect + var left = 'left' + if (isInvisible || container.textContent === '\n') { + rect = containerElt.getBoundingClientRect() + } else { + var selectedChar = editor.getContent()[inputOffset] + var startOffset = { + container: container, + offsetInContainer: offsetInContainer + } + var endOffset = { + container: container, + offsetInContainer: offsetInContainer + } + if (inputOffset > 0 && (selectedChar === undefined || selectedChar === '\n')) { + left = 'right' + if (startOffset.offsetInContainer === 0) { + // Need to calculate offset-1 + startOffset = inputOffset - 1 + } else { + startOffset.offsetInContainer -= 1 + } + } else { + if (endOffset.offsetInContainer === container.textContent.length) { + // Need to calculate offset+1 + endOffset = inputOffset + 1 + } else { + endOffset.offsetInContainer += 1 + } + } + var range = this.createRange(startOffset, endOffset) + rect = range.getBoundingClientRect() + } + contentRect = contentElt.getBoundingClientRect() + return { + top: Math.round(rect.top - contentRect.top + contentElt.scrollTop), + height: Math.round(rect.height), + left: Math.round(rect[left] - contentRect.left + contentElt.scrollLeft) + } + } + + this.getClosestWordOffset = function (offset) { + var offsetStart = 0 + var offsetEnd = 0 + var nextOffset = 0 + editor.getContent().split(/\s/).cl_some(function (word) { + if (word) { + offsetStart = nextOffset + offsetEnd = nextOffset + word.length + if (offsetEnd > offset) { + return true + } + } + nextOffset += word.length + 1 + }) + return { + start: offsetStart, + end: offsetEnd + } + } +} + +cledit.SelectionMgr = SelectionMgr diff --git a/src/cledit/cleditUndoMgr.js b/src/cledit/cleditUndoMgr.js new file mode 100644 index 00000000..a097778f --- /dev/null +++ b/src/cledit/cleditUndoMgr.js @@ -0,0 +1,178 @@ +var DiffMatchPatch = require('diff-match-patch'); +var cledit = require('./cleditCore') + +function UndoMgr(editor) { + cledit.Utils.createEventHooks(this) + + /* eslint-disable new-cap */ + var diffMatchPatch = new DiffMatchPatch() + /* eslint-enable new-cap */ + + var self = this + var selectionMgr + var undoStack = [] + var redoStack = [] + var currentState + var previousPatches = [] + var currentPatches = [] + var debounce = cledit.Utils.debounce + + self.options = { + undoStackMaxSize: 200, + bufferStateUntilIdle: 1000, + patchHandler: { + makePatches: function (oldContent, newContent, diffs) { + return diffMatchPatch.patch_make(oldContent, diffs) + }, + applyPatches: function (patches, content) { + return diffMatchPatch.patch_apply(patches, content)[0] + }, + reversePatches: function (patches) { + patches = diffMatchPatch.patch_deepCopy(patches).reverse() + patches.cl_each(function (patch) { + patch.diffs.cl_each(function (diff) { + diff[0] = -diff[0] + }) + }) + return patches + } + } + } + + function State() { } + + function StateMgr() { + var currentTime, lastTime + var lastMode + + this.isBufferState = function () { + currentTime = Date.now() + return this.currentMode !== 'single' && + this.currentMode === lastMode && + currentTime - lastTime < self.options.bufferStateUntilIdle + } + + this.setDefaultMode = function (mode) { + this.currentMode = this.currentMode || mode + } + + this.resetMode = function () { + stateMgr.currentMode = undefined + lastMode = undefined + } + + this.saveMode = function () { + lastMode = this.currentMode + this.currentMode = undefined + lastTime = currentTime + } + } + + function addToStack(stack) { + return function () { + stack.push(this) + this.patches = previousPatches + previousPatches = [] + } + } + + State.prototype.addToUndoStack = addToStack(undoStack) + State.prototype.addToRedoStack = addToStack(redoStack) + + var stateMgr = new StateMgr() + this.setCurrentMode = function (mode) { + stateMgr.currentMode = mode + } + this.setDefaultMode = stateMgr.setDefaultMode.cl_bind(stateMgr) + + this.addDiffs = function (oldContent, newContent, diffs) { + var patches = self.options.patchHandler.makePatches(oldContent, newContent, diffs) + currentPatches.push.apply(currentPatches, patches) + } + + function saveCurrentPatches() { + // Move currentPatches into previousPatches + Array.prototype.push.apply(previousPatches, currentPatches) + currentPatches = [] + } + + this.saveState = debounce(function () { + redoStack.length = 0 + if (!stateMgr.isBufferState()) { + currentState.addToUndoStack() + + // Limit the size of the stack + while (undoStack.length > self.options.undoStackMaxSize) { + undoStack.shift() + } + } + saveCurrentPatches() + currentState = new State() + stateMgr.saveMode() + self.$trigger('undoStateChange') + }) + + this.canUndo = function () { + return !!undoStack.length + } + + this.canRedo = function () { + return !!redoStack.length + } + + function restoreState(patches, isForward) { + // Update editor + var content = editor.getContent() + if (!isForward) { + patches = self.options.patchHandler.reversePatches(patches) + } + + var newContent = self.options.patchHandler.applyPatches(patches, content) + var newContentText = newContent.text || newContent + var range = editor.setContent(newContentText, true) + var selection = newContent.selection || { + start: range.end, + end: range.end + } + + selectionMgr.setSelectionStartEnd(selection.start, selection.end) + selectionMgr.updateCursorCoordinates(true) + + stateMgr.resetMode() + self.$trigger('undoStateChange') + editor.adjustCursorPosition() + } + + this.undo = function () { + var state = undoStack.pop() + if (!state) { + return + } + saveCurrentPatches() + currentState.addToRedoStack() + restoreState(currentState.patches) + previousPatches = state.patches + currentState = state + } + + this.redo = function () { + var state = redoStack.pop() + if (!state) { + return + } + currentState.addToUndoStack() + restoreState(state.patches, true) + previousPatches = state.patches + currentState = state + } + + this.init = function (options) { + self.options.cl_extend(options || {}) + selectionMgr = editor.selectionMgr + if (!currentState) { + currentState = new State() + } + } +} + +cledit.UndoMgr = UndoMgr diff --git a/src/cledit/cleditUtils.js b/src/cledit/cleditUtils.js new file mode 100644 index 00000000..c8f532d2 --- /dev/null +++ b/src/cledit/cleditUtils.js @@ -0,0 +1,123 @@ +var cledit = require('./cleditCore') + +var Utils = { + isGecko: 'MozAppearance' in document.documentElement.style, + isWebkit: 'WebkitAppearance' in document.documentElement.style, + isMsie: 'msTransform' in document.documentElement.style, + isMac: navigator.userAgent.indexOf('Mac OS X') !== -1 +} + +// Faster than setTimeout(0). Credit: https://github.com/stefanpenner/es6-promise +Utils.defer = (function () { + var queue = new Array(1000) + var queueLength = 0 + function flush() { + for (var i = 0; i < queueLength; i++) { + try { + queue[i]() + } catch (e) { + console.error(e.message, e.stack) + } + queue[i] = undefined + } + queueLength = 0 + } + + var iterations = 0 + var observer = new window.MutationObserver(flush) + var node = document.createTextNode('') + observer.observe(node, { characterData: true }) + + return function (fn) { + queue[queueLength++] = fn + if (queueLength === 1) { + node.data = (iterations = ++iterations % 2) + } + } +})() + +Utils.debounce = function (func, wait) { + var timeoutId, isExpected + return wait + ? function () { + clearTimeout(timeoutId) + timeoutId = setTimeout(func, wait) + } + : function () { + if (!isExpected) { + isExpected = true + Utils.defer(function () { + isExpected = false + func() + }) + } + } +} + +Utils.createEventHooks = function (object) { + var listenerMap = Object.create(null) + object.$trigger = function (eventType) { + var listeners = listenerMap[eventType] + if (listeners) { + var args = Array.prototype.slice.call(arguments, 1) + listeners.cl_each(function (listener) { + try { + listener.apply(object, args) + } catch (e) { + console.error(e.message, e.stack) + } + }) + } + } + object.on = function (eventType, listener) { + var listeners = listenerMap[eventType] + if (!listeners) { + listeners = [] + listenerMap[eventType] = listeners + } + listeners.push(listener) + } + object.off = function (eventType, listener) { + var listeners = listenerMap[eventType] + if (listeners) { + var index = listeners.indexOf(listener) + if (~index) { + listeners.splice(index, 1) + } + } + } +} + +Utils.findContainer = function (elt, offset) { + var containerOffset = 0 + var container + do { + container = elt + elt = elt.firstChild + if (elt) { + do { + var len = elt.textContent.length + if (containerOffset <= offset && containerOffset + len > offset) { + break + } + containerOffset += len + } while ((elt = elt.nextSibling)) + } + } while (elt && elt.firstChild && elt.nodeType !== 3) + + if (elt) { + return { + container: elt, + offsetInContainer: offset - containerOffset + } + } + while (container.lastChild) { + container = container.lastChild + } + return { + container: container, + offsetInContainer: container.nodeType === 3 ? container.textContent.length : 0 + } +} + +cledit.Utils = Utils diff --git a/src/cledit/cleditWatcher.js b/src/cledit/cleditWatcher.js new file mode 100644 index 00000000..942597c0 --- /dev/null +++ b/src/cledit/cleditWatcher.js @@ -0,0 +1,33 @@ +var cledit = require('./cleditCore') + +function Watcher(editor, listener) { + this.isWatching = false + var contentObserver + this.startWatching = function () { + this.stopWatching() + this.isWatching = true + contentObserver = new window.MutationObserver(listener) + contentObserver.observe(editor.$contentElt, { + childList: true, + subtree: true, + characterData: true + }) + } + this.stopWatching = function () { + if (contentObserver) { + contentObserver.disconnect() + contentObserver = undefined + } + this.isWatching = false + } + this.noWatch = function (cb) { + if (this.isWatching === true) { + this.stopWatching() + cb() + return this.startWatching() + } + cb() + } +} + +cledit.Watcher = Watcher diff --git a/src/cledit/clunderscore.js b/src/cledit/clunderscore.js new file mode 100644 index 00000000..d6667167 --- /dev/null +++ b/src/cledit/clunderscore.js @@ -0,0 +1,166 @@ +var arrayProperties = {} +var liveCollectionProperties = {} +var functionProperties = {} +var objectProperties = {} +var slice = Array.prototype.slice + +arrayProperties.cl_each = function (cb) { + var i = 0 + var length = this.length + for (; i < length; i++) { + cb(this[i], i, this) + } +} + +arrayProperties.cl_map = function (cb) { + var i = 0 + var length = this.length + var result = Array(length) + for (; i < length; i++) { + result[i] = cb(this[i], i, this) + } + return result +} + +arrayProperties.cl_reduce = function (cb, memo) { + var i = 0 + var length = this.length + for (; i < length; i++) { + memo = cb(memo, this[i], i, this) + } + return memo +} + +arrayProperties.cl_some = function (cb) { + var i = 0 + var length = this.length + for (; i < length; i++) { + if (cb(this[i], i, this)) { + return true + } + } +} + +arrayProperties.cl_filter = function (cb) { + var i = 0 + var length = this.length + var result = [] + for (; i < length; i++) { + cb(this[i], i, this) && result.push(this[i]) + } + return result +} + +liveCollectionProperties.cl_each = function (cb) { + slice.call(this).cl_each(cb) +} + +liveCollectionProperties.cl_map = function (cb) { + return slice.call(this).cl_map(cb) +} + +liveCollectionProperties.cl_reduce = function (cb, memo) { + return slice.call(this).cl_reduce(cb, memo) +} + +functionProperties.cl_bind = function (context) { + var self = this + var args = slice.call(arguments, 1) + context = context || null + return args.length + ? function () { + return arguments.length + ? self.apply(context, args.concat(slice.call(arguments))) + : self.apply(context, args) + } + : function () { + return arguments.length + ? self.apply(context, arguments) + : self.call(context) + } +} + +objectProperties.cl_each = function (cb) { + var i = 0 + var keys = Object.keys(this) + var length = keys.length + for (; i < length; i++) { + cb(this[keys[i]], keys[i], this) + } +} + +objectProperties.cl_map = function (cb) { + var i = 0 + var keys = Object.keys(this) + var length = keys.length + var result = Array(length) + for (; i < length; i++) { + result[i] = cb(this[keys[i]], keys[i], this) + } + return result +} + +objectProperties.cl_reduce = function (cb, memo) { + var i = 0 + var keys = Object.keys(this) + var length = keys.length + for (; i < length; i++) { + memo = cb(memo, this[keys[i]], keys[i], this) + } + return memo +} + +objectProperties.cl_some = function (cb) { + var i = 0 + var keys = Object.keys(this) + var length = keys.length + for (; i < length; i++) { + if (cb(this[keys[i]], keys[i], this)) { + return true + } + } +} + +objectProperties.cl_extend = function (obj) { + if (obj) { + var i = 0 + var keys = Object.keys(obj) + var length = keys.length + for (; i < length; i++) { + this[keys[i]] = obj[keys[i]] + } + } + return this +} + +function build(properties) { + return objectProperties.cl_reduce.call(properties, function (memo, value, key) { + memo[key] = { + value: value + } + return memo + }, {}) +} + +arrayProperties = build(arrayProperties) +liveCollectionProperties = build(liveCollectionProperties) +functionProperties = build(functionProperties) +objectProperties = build(objectProperties) + +/* eslint-disable no-extend-native */ +Object.defineProperties(Array.prototype, arrayProperties) +Object.defineProperties(Int8Array.prototype, arrayProperties) +Object.defineProperties(Uint8Array.prototype, arrayProperties) +Object.defineProperties(Uint8ClampedArray.prototype, arrayProperties) +Object.defineProperties(Int16Array.prototype, arrayProperties) +Object.defineProperties(Uint16Array.prototype, arrayProperties) +Object.defineProperties(Int32Array.prototype, arrayProperties) +Object.defineProperties(Uint32Array.prototype, arrayProperties) +Object.defineProperties(Float32Array.prototype, arrayProperties) +Object.defineProperties(Float64Array.prototype, arrayProperties) +Object.defineProperties(Function.prototype, functionProperties) +Object.defineProperties(Object.prototype, objectProperties) +if (typeof window !== 'undefined') { + Object.defineProperties(HTMLCollection.prototype, liveCollectionProperties) + Object.defineProperties(NodeList.prototype, liveCollectionProperties) +} diff --git a/src/cledit/htmlSanitizer.js b/src/cledit/htmlSanitizer.js new file mode 100644 index 00000000..b11f29b7 --- /dev/null +++ b/src/cledit/htmlSanitizer.js @@ -0,0 +1,424 @@ +const aHrefSanitizationWhitelist = /^\s*(https?|ftp|mailto|tel|file):/; +const imgSrcSanitizationWhitelist = /^\s*((https?|ftp|file|blob):|data:image\/)/; + +const urlParsingNode = window.document.createElement('a'); + +function sanitizeUri(uri, isImage) { + const regex = isImage ? imgSrcSanitizationWhitelist : aHrefSanitizationWhitelist; + urlParsingNode.setAttribute('href', uri); + const normalizedVal = urlParsingNode.href; + if (normalizedVal !== '' && !normalizedVal.match(regex)) { + return `unsafe:${normalizedVal}`; + } + return uri; +} + +var buf; + +/* jshint -W083 */ + +// Regular Expressions for parsing tags and attributes +var START_TAG_REGEXP = + /^<((?:[a-zA-Z])[\w:-]*)((?:\s+[\w:-]+(?:\s*=\s*(?:(?:"[^"]*")|(?:'[^']*')|[^>\s]+))?)*)\s*(\/?)\s*(>?)/, + END_TAG_REGEXP = /^<\/\s*([\w:-]+)[^>]*>/, + ATTR_REGEXP = /([\w:-]+)(?:\s*=\s*(?:(?:"((?:[^"])*)")|(?:'((?:[^'])*)')|([^>\s]+)))?/g, + BEGIN_TAG_REGEXP = /^/g, + DOCTYPE_REGEXP = /]*?)>/i, + CDATA_REGEXP = //g, + SURROGATE_PAIR_REGEXP = /[\uD800-\uDBFF][\uDC00-\uDFFF]/g, + // Match everything outside of normal chars and " (quote character) + NON_ALPHANUMERIC_REGEXP = /([^\#-~| |!])/g; + + +// Good source of info about elements and attributes +// http://dev.w3.org/html5/spec/Overview.html#semantics +// http://simon.html5.org/html-elements + +// Safe Void Elements - HTML5 +// http://dev.w3.org/html5/spec/Overview.html#void-elements +var voidElements = makeMap("area,br,col,hr,img,wbr"); + +// Elements that you can, intentionally, leave open (and which close themselves) +// http://dev.w3.org/html5/spec/Overview.html#optional-tags +var optionalEndTagBlockElements = makeMap("colgroup,dd,dt,li,p,tbody,td,tfoot,th,thead,tr"), + optionalEndTagInlineElements = makeMap("rp,rt"), + optionalEndTagElements = { + ...optionalEndTagInlineElements, + ...optionalEndTagBlockElements, + }; + +// Safe Block Elements - HTML5 +var blockElements = { + ...optionalEndTagBlockElements, + ...makeMap("address,article," + + "aside,blockquote,caption,center,del,dir,div,dl,figure,figcaption,footer,h1,h2,h3,h4,h5," + + "h6,header,hgroup,hr,ins,map,menu,nav,ol,pre,script,section,table,ul") +}; + +// benweet: Add iframe +blockElements.iframe = true; + +// Inline Elements - HTML5 +var inlineElements = { + ...optionalEndTagInlineElements, + ...makeMap("a,abbr,acronym,b," + + "bdi,bdo,big,br,cite,code,del,dfn,em,font,i,img,ins,kbd,label,map,mark,q,ruby,rp,rt,s," + + "samp,small,span,strike,strong,sub,sup,time,tt,u,var") +}; + +// SVG Elements +// https://wiki.whatwg.org/wiki/Sanitization_rules#svg_Elements +// Note: the elements animate,animateColor,animateMotion,animateTransform,set are intentionally omitted. +// They can potentially allow for arbitrary javascript to be executed. See #11290 +var svgElements = makeMap("circle,defs,desc,ellipse,font-face,font-face-name,font-face-src,g,glyph," + + "hkern,image,linearGradient,line,marker,metadata,missing-glyph,mpath,path,polygon,polyline," + + "radialGradient,rect,stop,svg,switch,text,title,tspan,use"); + +// Special Elements (can contain anything) +var specialElements = makeMap("script,style"); + +var validElements = { + ...voidElements, + ...blockElements, + ...inlineElements, + ...optionalEndTagElements, + ...svgElements, +}; + +//Attributes that have href and hence need to be sanitized +var uriAttrs = makeMap("background,cite,href,longdesc,src,usemap,xlink:href"); + +var htmlAttrs = makeMap('abbr,align,alt,axis,bgcolor,border,cellpadding,cellspacing,class,clear,' + + 'color,cols,colspan,compact,coords,dir,face,headers,height,hreflang,hspace,' + + 'ismap,lang,language,nohref,nowrap,rel,rev,rows,rowspan,rules,' + + 'scope,scrolling,shape,size,span,start,summary,tabindex,target,title,type,' + + 'valign,value,vspace,width'); + +// SVG attributes (without "id" and "name" attributes) +// https://wiki.whatwg.org/wiki/Sanitization_rules#svg_Attributes +var svgAttrs = makeMap('accent-height,accumulate,additive,alphabetic,arabic-form,ascent,' + + 'baseProfile,bbox,begin,by,calcMode,cap-height,class,color,color-rendering,content,' + + 'cx,cy,d,dx,dy,descent,display,dur,end,fill,fill-rule,font-family,font-size,font-stretch,' + + 'font-style,font-variant,font-weight,from,fx,fy,g1,g2,glyph-name,gradientUnits,hanging,' + + 'height,horiz-adv-x,horiz-origin-x,ideographic,k,keyPoints,keySplines,keyTimes,lang,' + + 'marker-end,marker-mid,marker-start,markerHeight,markerUnits,markerWidth,mathematical,' + + 'max,min,offset,opacity,orient,origin,overline-position,overline-thickness,panose-1,' + + 'path,pathLength,points,preserveAspectRatio,r,refX,refY,repeatCount,repeatDur,' + + 'requiredExtensions,requiredFeatures,restart,rotate,rx,ry,slope,stemh,stemv,stop-color,' + + 'stop-opacity,strikethrough-position,strikethrough-thickness,stroke,stroke-dasharray,' + + 'stroke-dashoffset,stroke-linecap,stroke-linejoin,stroke-miterlimit,stroke-opacity,' + + 'stroke-width,systemLanguage,target,text-anchor,to,transform,type,u1,u2,underline-position,' + + 'underline-thickness,unicode,unicode-range,units-per-em,values,version,viewBox,visibility,' + + 'width,widths,x,x-height,x1,x2,xlink:actuate,xlink:arcrole,xlink:role,xlink:show,xlink:title,' + + 'xlink:type,xml:base,xml:lang,xml:space,xmlns,xmlns:xlink,y,y1,y2,zoomAndPan', true); + +var validAttrs = { + ...uriAttrs, + ...svgAttrs, + ...htmlAttrs, +}; + +// benweet: Add id and allowfullscreen (YouTube iframe) +validAttrs.id = true; +validAttrs.allowfullscreen = true; + +function makeMap(str, lowercaseKeys) { + var obj = {}, + items = str.split(','), + i; + for (i = 0; i < items.length; i++) { + obj[lowercaseKeys ? items[i].toLowerCase() : items[i]] = true; + } + return obj; +} + + +/** + * @example + * htmlParser(htmlString, { + * start: function(tag, attrs, unary) {}, + * end: function(tag) {}, + * chars: function(text) {}, + * comment: function(text) {} + * }); + * + * @param {string} html string + * @param {object} handler + */ +function htmlParser(html, handler) { + if (typeof html !== 'string') { + if (html === null || typeof html === 'undefined') { + html = ''; + } else { + html = '' + html; + } + } + var index, chars, match, stack = [], + last = html, + text; + stack.last = function () { + return stack[stack.length - 1]; + }; + + while (html) { + text = ''; + chars = true; + + // Make sure we're not in a script or style element + if (!stack.last() || !specialElements[stack.last()]) { + + // Comment + if (html.indexOf("", index) === index) { + if (handler.comment) handler.comment(html.substring(4, index)); + html = html.substring(index + 3); + chars = false; + } + // DOCTYPE + } else if (DOCTYPE_REGEXP.test(html)) { + match = html.match(DOCTYPE_REGEXP); + + if (match) { + html = html.replace(match[0], ''); + chars = false; + } + // end tag + } else if (BEGING_END_TAGE_REGEXP.test(html)) { + match = html.match(END_TAG_REGEXP); + + if (match) { + html = html.substring(match[0].length); + match[0].replace(END_TAG_REGEXP, parseEndTag); + chars = false; + } + + // start tag + } else if (BEGIN_TAG_REGEXP.test(html)) { + match = html.match(START_TAG_REGEXP); + + if (match) { + // We only have a valid start-tag if there is a '>'. + if (match[4]) { + html = html.substring(match[0].length); + match[0].replace(START_TAG_REGEXP, parseStartTag); + } + chars = false; + } else { + // no ending tag found --- this piece should be encoded as an entity. + text += '<'; + html = html.substring(1); + } + } + + if (chars) { + index = html.indexOf("<"); + + text += index < 0 ? html : html.substring(0, index); + html = index < 0 ? "" : html.substring(index); + + if (handler.chars) handler.chars(decodeEntities(text)); + } + + } else { + // IE versions 9 and 10 do not understand the regex '[^]', so using a workaround with [\W\w]. + html = html.replace(new RegExp("([\\W\\w]*)<\\s*\\/\\s*" + stack.last() + "[^>]*>", 'i'), + function (all, text) { + text = text.replace(COMMENT_REGEXP, "$1").replace(CDATA_REGEXP, "$1"); + + if (handler.chars) handler.chars(decodeEntities(text)); + + return ""; + }); + + parseEndTag("", stack.last()); + } + + if (html == last) { + // benweet + // throw $sanitizeMinErr('badparse', "The sanitizer was unable to parse the following block " + + // "of html: {0}", html); + stack.reverse(); + return stack.cl_each(function (tag) { + buf.push(''); + }); + } + last = html; + } + + // Clean up any remaining tags + parseEndTag(); + + function parseStartTag(tag, tagName, rest, unary) { + tagName = tagName && tagName.toLowerCase(); + if (blockElements[tagName]) { + while (stack.last() && inlineElements[stack.last()]) { + parseEndTag("", stack.last()); + } + } + + if (optionalEndTagElements[tagName] && stack.last() == tagName) { + parseEndTag("", tagName); + } + + unary = voidElements[tagName] || !!unary; + + if (!unary) { + stack.push(tagName); + } + + var attrs = {}; + + rest.replace(ATTR_REGEXP, + function (match, name, doubleQuotedValue, singleQuotedValue, unquotedValue) { + var value = doubleQuotedValue || singleQuotedValue || unquotedValue || ''; + + attrs[name] = decodeEntities(value); + }); + if (handler.start) handler.start(tagName, attrs, unary); + } + + function parseEndTag(tag, tagName) { + var pos = 0, + i; + tagName = tagName && tagName.toLowerCase(); + if (tagName) { + // Find the closest opened tag of the same type + for (pos = stack.length - 1; pos >= 0; pos--) { + if (stack[pos] == tagName) break; + } + } + + if (pos >= 0) { + // Close all the open elements, up the stack + for (i = stack.length - 1; i >= pos; i--) + if (handler.end) handler.end(stack[i]); + + // Remove the open elements from the stack + stack.length = pos; + } + } +} + +var hiddenPre = document.createElement("pre"); +/** + * decodes all entities into regular string + * @param value + * @returns {string} A string with decoded entities. + */ +function decodeEntities(value) { + if (!value) { + return ''; + } + + hiddenPre.innerHTML = value.replace(//g, '>'); +} + +/** + * create an HTML/XML writer which writes to buffer + * @param {Array} buf use buf.jain('') to get out sanitized html string + * @returns {object} in the form of { + * start: function(tag, attrs, unary) {}, + * end: function(tag) {}, + * chars: function(text) {}, + * comment: function(text) {} + * } + */ +function htmlSanitizeWriter(buf, uriValidator) { + var ignore = false; + var out = buf.push.bind(buf); + return { + start: function (tag, attrs, unary) { + tag = tag && tag.toLowerCase(); + if (!ignore && specialElements[tag]) { + ignore = tag; + } + if (!ignore && validElements[tag] === true) { + out('<'); + out(tag); + Object.keys(attrs).forEach(function (key) { + var value = attrs[key]; + var lkey = key && key.toLowerCase(); + var isImage = (tag === 'img' && lkey === 'src') || (lkey === 'background'); + if (validAttrs[lkey] === true && + (uriAttrs[lkey] !== true || uriValidator(value, isImage))) { + out(' '); + out(key); + out('="'); + out(encodeEntities(value)); + out('"'); + } + }); + out(unary ? '/>' : '>'); + } + }, + end: function (tag) { + tag = tag && tag.toLowerCase(); + if (!ignore && validElements[tag] === true) { + out(''); + } + if (tag == ignore) { + ignore = false; + } + }, + chars: function (chars) { + if (!ignore) { + out(encodeEntities(chars)); + } + }, + comment: function (comment) { + if (!ignore) { + out(''); + } + } + }; +} + +function sanitizeHtml(html) { + buf = []; + htmlParser(html, htmlSanitizeWriter(buf, function (uri, isImage) { + return !/^unsafe/.test(sanitizeUri(uri, isImage)); + })); + return buf.join(''); +} + + +export default { + sanitizeHtml, + sanitizeUri, +} diff --git a/src/cledit/mdGrammar.js b/src/cledit/mdGrammar.js new file mode 100644 index 00000000..faa634b8 --- /dev/null +++ b/src/cledit/mdGrammar.js @@ -0,0 +1,422 @@ +var charInsideUrl = '(&|[-A-Z0-9+@#/%?=~_|[\\]()!:,.;])' +var charEndingUrl = '(&|[-A-Z0-9+@#/%=~_|[\\])])' +var urlPattern = new RegExp('(https?|ftp)(://' + charInsideUrl + '*' + charEndingUrl + ')(?=$|\\W)', 'gi') +var emailPattern = /(?:mailto:)?([-.\w]+\@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)/gi + +var markup = { + 'comment': //g, + 'tag': { + pattern: /<\/?[\w:-]+\s*(?:\s+[\w:-]+(?:=(?:("|')(\\?[\w\W])*?\1|[^\s'">=]+))?\s*)*\/?>/gi, + inside: { + 'tag': { + pattern: /^<\/?[\w:-]+/i, + inside: { + 'punctuation': /^<\/?/, + 'namespace': /^[\w-]+?:/ + } + }, + 'attr-value': { + pattern: /=(?:('|")[\w\W]*?(\1)|[^\s>]+)/gi, + inside: { + 'punctuation': /=|>|"/g + } + }, + 'punctuation': /\/?>/g, + 'attr-name': { + pattern: /[\w:-]+/g, + inside: { + 'namespace': /^[\w-]+?:/ + } + } + } + }, + 'entity': /&#?[\da-z]{1,8};/gi +} + +var latex = { + // A tex command e.g. \foo + 'keyword': /\\(?:[^a-zA-Z]|[a-zA-Z]+)/g, + // Curly and square braces + 'lparen': /[[({]/g, + // Curly and square braces + 'rparen': /[\])}]/g, + // A comment. Tex comments start with % and go to + // the end of the line + 'comment': /%.*/g +} + +module.exports = function (options) { + options = options || {} + var grammar = {} + var insideFences = options.insideFences || {} + insideFences['cl cl-pre'] = /`{3}|~{3}/ + if (options.fences) { + grammar['pre gfm'] = { + pattern: /^(`{3}|~{3}).*\n(?:[\s\S]*?)\n\1 *$/gm, + inside: insideFences + } + } + grammar.li = { + pattern: new RegExp( + [ + '^ {0,3}(?:[*+\\-]|\\d+\\.)[ \\t].+\\n', // Item line + '(?:', + '(?:', + '.*\\S.*\\n', // Non-empty line + '|', + '[ \\t]*\\n(?! ?\\S)', // Or empty line not followed by unindented line + ')', + ')*' + ].join(''), + 'gm' + ), + inside: { + 'cl cl-li': /^[ \t]*([*+\-]|\d+\.)[ \t]/gm + } + } + if (options.fences) { + grammar.li.inside['pre gfm'] = { + pattern: /^((?: {4}|\t)+)(`{3}|~{3}).*\n(?:[\s\S]*?)\n\1\2\s*$/gm, + inside: insideFences + } + } + grammar.blockquote = { + pattern: /^ {0,3}>.+(?:\n[ \t]*\S.*)*/gm, + inside: { + 'cl cl-gt': /^\s*>/gm, + 'li': grammar.li + } + } + grammar['h1 alt'] = { + pattern: /^.+\n=+[ \t]*$/gm, + inside: { + 'cl cl-hash': /=+[ \t]*$/ + } + } + grammar['h2 alt'] = { + pattern: /^.+\n-+[ \t]*$/gm, + inside: { + 'cl cl-hash': /-+[ \t]*$/ + } + } + for (var i = 6; i >= 1; i--) { + grammar['h' + i] = { + pattern: new RegExp('^#{' + i + '}[ \t].+$', 'gm'), + inside: { + 'cl cl-hash': new RegExp('^#{' + i + '}') + } + } + } + if (options.tables) { + grammar.table = { + pattern: new RegExp( + [ + '^', + '[ ]{0,3}', + '[|]', // Initial pipe + '.+\\n', // Header Row + '[ ]{0,3}', + '[|][ ]*[-:]+[-| :]*\\n', // Separator + '(?:[ \t]*[|].*\\n?)*', // Table rows + '$' + ].join(''), + 'gm' + ), + inside: {} + } + grammar['table alt'] = { + pattern: new RegExp( + [ + '^', + '[ ]{0,3}', + '\\S.*[|].*\\n', // Header Row + '[ ]{0,3}', + '[-:]+[ ]*[|][-| :]*\\n', // Separator + '(?:.*[|].*\\n?)*', // Table rows + '$' // Stop at final newline + ].join(''), + 'gm' + ), + inside: {} + } + } + if (options.deflists) { + grammar.deflist = { + pattern: new RegExp( + [ + '^ {0,3}\\S.*\\n', // Description line + '(?:[ \\t]*\\n)?', // Optional empty line + '(?:', + '[ \\t]*:[ \\t].*\\n', // Colon line + '(?:', + '(?:', + '.*\\S.*\\n', // Non-empty line + '|', + '[ \\t]*\\n(?! ?\\S)', // Or empty line not followed by unindented line + ')', + ')*', + '(?:[ \\t]*\\n)*', // Empty lines + ')+' + ].join(''), + 'gm' + ), + inside: { + 'deflist-desc': { + pattern: /( {0,3}\S.*\n(?:[ \t]*\n)?)[\s\S]*/, + lookbehind: true, + inside: { + 'cl': /^[ \t]*:[ \t]/gm + } + }, + 'term': /.+/g + } + } + if (options.fences) { + grammar.deflist.inside['deflist-desc'].inside['pre gfm'] = { + pattern: /^((?: {4}|\t)+)(`{3}|~{3}).*\n(?:[\s\S]*?)\n\1\2\s*$/gm, + inside: insideFences + } + } + } + grammar.hr = { + pattern: /^ {0,3}([*\-_] *){3,}$/gm + } + if (options.footnotes) { + grammar.fndef = { + pattern: /^ {0,3}\[\^.*?\]:.*$/gm, + inside: { + 'ref-id': { + pattern: /^ {0,3}\[\^.*?\]/, + inside: { + cl: /(\[\^|\])/ + } + } + } + } + } + if (options.abbrs) { + grammar.abbrdef = { + pattern: /^ {0,3}\*\[.*?\]:.*$/gm, + inside: { + 'abbr-id': { + pattern: /^ {0,3}\*\[.*?\]/, + inside: { + cl: /(\*\[|\])/ + } + } + } + } + } + grammar.linkdef = { + pattern: /^ {0,3}\[.*?\]:.*$/gm, + inside: { + 'link-id': { + pattern: /^ {0,3}\[.*?\]/, + inside: { + cl: /[\[\]]/ + } + }, + url: urlPattern + } + } + grammar.p = { + pattern: /^ {0,3}\S.*$(\n.*\S.*)*/gm, + inside: {} + } + if (options.tocs) { + grammar.p.inside['cl cl-toc'] = /^[ \t]*\[toc\]$/mi + } + grammar.pre = { + pattern: /(?: {4}|\t).*\S.*\n((?: {4}|\t).*\n)*/g + } + + var rest = {} + rest.code = { + pattern: /(`+)[\s\S]*?\1/g, + inside: { + 'cl cl-code': /`/ + } + } + if (options.maths) { + rest['math block'] = { + pattern: /\\\\\[[\s\S]*?\\\\\]/g, + inside: { + 'cl cl-bracket-start': /^\\\\\[/, + 'cl cl-bracket-end': /\\\\\]$/, + rest: latex + } + } + rest['math inline'] = { + pattern: /\\\\\([\s\S]*?\\\\\)/g, + inside: { + 'cl cl-bracket-start': /^\\\\\(/, + 'cl cl-bracket-end': /\\\\\)$/, + rest: latex + } + } + rest['math expr block'] = { + pattern: /(\$\$)[\s\S]*?\1/g, + inside: { + 'cl cl-bracket-start': /^\$\$/, + 'cl cl-bracket-end': /\$\$$/, + rest: latex + } + } + rest['math expr inline'] = { + pattern: /\$(?!\s)[\s\S]*?\S\$(?!\d)/g, + inside: { + 'cl cl-bracket-start': /^\$/, + 'cl cl-bracket-end': /\$$/, + rest: latex + } + } + rest['latex block'] = { + pattern: /\\begin\{([a-z]*\*?)\}[\s\S]*?\\?\\end\{\1\}/g, + inside: { + 'keyword': /\\(begin|end)/, + rest: latex + } + } + } + if (options.footnotes) { + rest.inlinefn = { + pattern: /\^\[.+?\]/g, + inside: { + 'cl': /(\^\[|\])/ + } + } + rest.fn = { + pattern: /\[\^.+?\]/g, + inside: { + 'cl': /(\[\^|\])/ + } + } + } + rest.img = { + pattern: /!\[.*?\]\(.+?\)/g, + inside: { + 'cl cl-title': /['‘][^'’]*['’]|["“][^"”]*["”](?=\)$)/, + 'cl cl-src': { + pattern: /(\]\()[^\('" \t]+(?=[\)'" \t])/, + lookbehind: true + } + } + } + rest.link = { + pattern: /\[.*?\]\(.+?\)/gm, + inside: { + 'cl cl-underlined-text': { + pattern: /(\[)[^\]]*/, + lookbehind: true + }, + 'cl cl-title': /['‘][^'’]*['’]|["“][^"”]*["”](?=\)$)/ + } + } + rest.imgref = { + pattern: /!\[.*?\][ \t]*\[.*?\]/g + } + rest.linkref = { + pattern: /\[.*?\][ \t]*\[.*?\]/g, + inside: { + 'cl cl-underlined-text': { + pattern: /^(\[)[^\]]*(?=\][ \t]*\[)/, + lookbehind: true + } + } + } + rest.comment = markup.comment + rest.tag = markup.tag + rest.url = urlPattern + rest.email = emailPattern + rest.strong = { + pattern: /(^|[^\w*])([_\*])\2(?![_\*])[\s\S]*?\2{2}(?=([^\w*]|$))/gm, + lookbehind: true, + inside: { + 'cl cl-strong cl-start': /^([_\*])\1/, + 'cl cl-strong cl-close': /([_\*])\1$/ + } + } + rest.em = { + pattern: /(^|[^\w*])([_\*])(?![_\*])[\s\S]*?\2(?=([^\w*]|$))/gm, + lookbehind: true, + inside: { + 'cl cl-em cl-start': /^[_\*]/, + 'cl cl-em cl-close': /[_\*]$/ + } + } + if (options.dels) { + rest.del = { + pattern: /(^|[^\w*])(~~)[\s\S]*?\2(?=([^\w*]|$))/gm, + lookbehind: true, + inside: { + 'cl': /~~/, + 'cl-del-text': /[^~]+/ + } + } + } + if (options.subs) { + rest.sub = { + pattern: /(~)(?=\S)(.*?\S)\1/gm, + inside: { + 'cl': /~/ + } + } + } + if (options.sups) { + rest.sup = { + pattern: /(\^)(?=\S)(.*?\S)\1/gm, + inside: { + 'cl': /\^/ + } + } + } + rest.entity = markup.entity + + for (var c = 6; c >= 1; c--) { + grammar['h' + c].inside.rest = rest + } + grammar['h1 alt'].inside.rest = rest + grammar['h2 alt'].inside.rest = rest + if (options.tables) { + grammar.table.inside.rest = rest + grammar['table alt'].inside.rest = rest + } + grammar.p.inside.rest = rest + grammar.blockquote.inside.rest = rest + grammar.li.inside.rest = rest + if (options.footnotes) { + grammar.fndef.inside.rest = rest + } + if (options.deflists) { + grammar.deflist.inside['deflist-desc'].inside.rest = rest + } + + var restLight = { + code: rest.code, + inlinefn: rest.inlinefn, + fn: rest.fn, + link: rest.link, + linkref: rest.linkref + } + rest.strong.inside.rest = restLight + rest.em.inside.rest = restLight + if (options.dels) { + rest.del.inside.rest = restLight + } + + var inside = { + code: rest.code, + comment: rest.comment, + tag: rest.tag, + strong: rest.strong, + em: rest.em, + del: rest.del, + sub: rest.sub, + sup: rest.sup, + entity: markup.entity + } + rest.link.inside['cl cl-underlined-text'].inside = inside + rest.linkref.inside['cl cl-underlined-text'].inside = inside + + return grammar +} diff --git a/src/cledit/pagedown.js b/src/cledit/pagedown.js new file mode 100644 index 00000000..3e77eaef --- /dev/null +++ b/src/cledit/pagedown.js @@ -0,0 +1,1362 @@ +var util = {}, + re = window.RegExp, + SETTINGS = { + lineLength: 72 + }; + +var defaultsStrings = { + bold: "Strong Ctrl/Cmd+B", + boldexample: "strong text", + + italic: "Emphasis Ctrl/Cmd+I", + italicexample: "emphasized text", + + strikethrough: "Strikethrough Ctrl/Cmd+I", + strikethroughexample: "strikethrough text", + + link: "Hyperlink Ctrl/Cmd+L", + linkdescription: "enter link description here", + linkdialog: "

Insert Hyperlink

http://example.com/ \"optional title\"

", + + quote: "Blockquote
Ctrl/Cmd+Q", + quoteexample: "Blockquote", + + code: "Code Sample
 Ctrl/Cmd+K",
+  codeexample: "enter code here",
+
+  image: "Image  Ctrl/Cmd+G",
+  imagedescription: "enter image description here",
+  imagedialog: "

Insert Image

http://example.com/images/diagram.jpg \"optional title\"

Need
free image hosting?

", + + olist: "Numbered List
    Ctrl/Cmd+O", + ulist: "Bulleted List
      Ctrl/Cmd+U", + litem: "List item", + + heading: "Heading

      /

      Ctrl/Cmd+H", + headingexample: "Heading", + + hr: "Horizontal Rule
      Ctrl/Cmd+R", + + undo: "Undo - Ctrl/Cmd+Z", + redo: "Redo - Ctrl/Cmd+Y", + + help: "Markdown Editing Help" +}; + +// options, if given, can have the following properties: +// options.helpButton = { handler: yourEventHandler } +// options.strings = { italicexample: "slanted text" } +// `yourEventHandler` is the click handler for the help button. +// If `options.helpButton` isn't given, not help button is created. +// `options.strings` can have any or all of the same properties as +// `defaultStrings` above, so you can just override some string displayed +// to the user on a case-by-case basis, or translate all strings to +// a different language. +// +// For backwards compatibility reasons, the `options` argument can also +// be just the `helpButton` object, and `strings.help` can also be set via +// `helpButton.title`. This should be considered legacy. +// +// The constructed editor object has the methods: +// - getConverter() returns the markdown converter object that was passed to the constructor +// - run() actually starts the editor; should be called after all necessary plugins are registered. Calling this more than once is a no-op. +// - refreshPreview() forces the preview to be updated. This method is only available after run() was called. +function Pagedown(options) { + + options = options || {}; + + if (typeof options.handler === "function") { //backwards compatible behavior + options = { + helpButton: options + }; + } + options.strings = options.strings || {}; + var getString = function (identifier) { + return options.strings[identifier] || defaultsStrings[identifier]; + }; + + function identity(x) { + return x; + } + + function returnFalse() { + return false; + } + + function HookCollection() { } + HookCollection.prototype = { + + chain: function (hookname, func) { + var original = this[hookname]; + if (!original) { + throw new Error("unknown hook " + hookname); + } + + if (original === identity) { + this[hookname] = func; + } else { + this[hookname] = function () { + var args = Array.prototype.slice.call(arguments, 0); + args[0] = original.apply(null, args); + return func.apply(null, args); + }; + } + }, + set: function (hookname, func) { + if (!this[hookname]) { + throw new Error("unknown hook " + hookname); + } + this[hookname] = func; + }, + addNoop: function (hookname) { + this[hookname] = identity; + }, + addFalse: function (hookname) { + this[hookname] = returnFalse; + } + }; + + var hooks = this.hooks = new HookCollection(); + hooks.addNoop("onPreviewRefresh"); // called with no arguments after the preview has been refreshed + hooks.addNoop("postBlockquoteCreation"); // called with the user's selection *after* the blockquote was created; should return the actual to-be-inserted text + hooks.addFalse("insertImageDialog"); + /* called with one parameter: a callback to be called with the URL of the image. If the application creates + * its own image insertion dialog, this hook should return true, and the callback should be called with the chosen + * image url (or null if the user cancelled). If this hook returns false, the default dialog will be used. + */ + hooks.addFalse("insertLinkDialog"); + + var that = this, + input; + + this.run = function () { + if (input) + return; // already initialized + + input = options.input; + var commandManager = new CommandManager(hooks, getString); + var uiManager; + + uiManager = new UIManager(input, commandManager); + + that.uiManager = uiManager; + }; + +} + +// before: contains all the text in the input box BEFORE the selection. +// after: contains all the text in the input box AFTER the selection. +function Chunks() { } + +// startRegex: a regular expression to find the start tag +// endRegex: a regular expresssion to find the end tag +Chunks.prototype.findTags = function (startRegex, endRegex) { + + var chunkObj = this; + var regex; + + if (startRegex) { + + regex = util.extendRegExp(startRegex, "", "$"); + + this.before = this.before.replace(regex, + function (match) { + chunkObj.startTag = chunkObj.startTag + match; + return ""; + }); + + regex = util.extendRegExp(startRegex, "^", ""); + + this.selection = this.selection.replace(regex, + function (match) { + chunkObj.startTag = chunkObj.startTag + match; + return ""; + }); + } + + if (endRegex) { + + regex = util.extendRegExp(endRegex, "", "$"); + + this.selection = this.selection.replace(regex, + function (match) { + chunkObj.endTag = match + chunkObj.endTag; + return ""; + }); + + regex = util.extendRegExp(endRegex, "^", ""); + + this.after = this.after.replace(regex, + function (match) { + chunkObj.endTag = match + chunkObj.endTag; + return ""; + }); + } +}; + +// If remove is false, the whitespace is transferred +// to the before/after regions. +// +// If remove is true, the whitespace disappears. +Chunks.prototype.trimWhitespace = function (remove) { + var beforeReplacer, afterReplacer, that = this; + if (remove) { + beforeReplacer = afterReplacer = ""; + } else { + beforeReplacer = function (s) { + that.before += s; + return ""; + }; + afterReplacer = function (s) { + that.after = s + that.after; + return ""; + }; + } + + this.selection = this.selection.replace(/^(\s*)/, beforeReplacer).replace(/(\s*)$/, afterReplacer); +}; + + +Chunks.prototype.skipLines = function (nLinesBefore, nLinesAfter, findExtraNewlines) { + + if (nLinesBefore === undefined) { + nLinesBefore = 1; + } + + if (nLinesAfter === undefined) { + nLinesAfter = 1; + } + + nLinesBefore++; + nLinesAfter++; + + var regexText; + var replacementText; + + // chrome bug ... documented at: http://meta.stackoverflow.com/questions/63307/blockquote-glitch-in-editor-in-chrome-6-and-7/65985#65985 + if (navigator.userAgent.match(/Chrome/)) { + "X".match(/()./); + } + + this.selection = this.selection.replace(/(^\n*)/, ""); + + this.startTag = this.startTag + re.$1; + + this.selection = this.selection.replace(/(\n*$)/, ""); + this.endTag = this.endTag + re.$1; + this.startTag = this.startTag.replace(/(^\n*)/, ""); + this.before = this.before + re.$1; + this.endTag = this.endTag.replace(/(\n*$)/, ""); + this.after = this.after + re.$1; + + if (this.before) { + + regexText = replacementText = ""; + + while (nLinesBefore--) { + regexText += "\\n?"; + replacementText += "\n"; + } + + if (findExtraNewlines) { + regexText = "\\n*"; + } + this.before = this.before.replace(new re(regexText + "$", ""), replacementText); + } + + if (this.after) { + + regexText = replacementText = ""; + + while (nLinesAfter--) { + regexText += "\\n?"; + replacementText += "\n"; + } + if (findExtraNewlines) { + regexText = "\\n*"; + } + + this.after = this.after.replace(new re(regexText, ""), replacementText); + } +}; + +// end of Chunks + +// Converts \r\n and \r to \n. +util.fixEolChars = function (text) { + text = text.replace(/\r\n/g, "\n"); + text = text.replace(/\r/g, "\n"); + return text; +}; + +// Extends a regular expression. Returns a new RegExp +// using pre + regex + post as the expression. +// Used in a few functions where we have a base +// expression and we want to pre- or append some +// conditions to it (e.g. adding "$" to the end). +// The flags are unchanged. +// +// regex is a RegExp, pre and post are strings. +util.extendRegExp = function (regex, pre, post) { + + if (pre === null || pre === undefined) { + pre = ""; + } + if (post === null || post === undefined) { + post = ""; + } + + var pattern = regex.toString(); + var flags; + + // Replace the flags with empty space and store them. + pattern = pattern.replace(/\/([gim]*)$/, function (wholeMatch, flagsPart) { + flags = flagsPart; + return ""; + }); + + // Remove the slash delimiters on the regular expression. + pattern = pattern.replace(/(^\/|\/$)/g, ""); + pattern = pre + pattern + post; + + return new re(pattern, flags); +}; + +// The input textarea state/contents. +// This is used to implement undo/redo by the undo manager. +function TextareaState(input) { + + // Aliases + var stateObj = this; + var inputArea = input; + this.init = function () { + this.setInputAreaSelectionStartEnd(); + this.text = inputArea.getContent(); + }; + + // Sets the selected text in the input box after we've performed an + // operation. + this.setInputAreaSelection = function () { + inputArea.focus(); + inputArea.setSelection(stateObj.start, stateObj.end); + }; + + this.setInputAreaSelectionStartEnd = function () { + stateObj.start = Math.min( + inputArea.selectionMgr.selectionStart, + inputArea.selectionMgr.selectionEnd + ); + stateObj.end = Math.max( + inputArea.selectionMgr.selectionStart, + inputArea.selectionMgr.selectionEnd + ); + }; + + // Restore this state into the input area. + this.restore = function () { + + if (stateObj.text !== undefined && stateObj.text != inputArea.getContent()) { + inputArea.setContent(stateObj.text); + } + this.setInputAreaSelection(); + }; + + // Gets a collection of HTML chunks from the inptut textarea. + this.getChunks = function () { + + var chunk = new Chunks(); + chunk.before = util.fixEolChars(stateObj.text.substring(0, stateObj.start)); + chunk.startTag = ""; + chunk.selection = util.fixEolChars(stateObj.text.substring(stateObj.start, stateObj.end)); + chunk.endTag = ""; + chunk.after = util.fixEolChars(stateObj.text.substring(stateObj.end)); + + return chunk; + }; + + // Sets the TextareaState properties given a chunk of markdown. + this.setChunks = function (chunk) { + + chunk.before = chunk.before + chunk.startTag; + chunk.after = chunk.endTag + chunk.after; + + this.start = chunk.before.length; + this.end = chunk.before.length + chunk.selection.length; + this.text = chunk.before + chunk.selection + chunk.after; + }; + this.init(); +} + +function UIManager(input, commandManager) { + + var inputBox = input, + buttons = {}; // buttons.undo, buttons.link, etc. The actual DOM elements. + + makeSpritedButtonRow(); + + // Perform the button's action. + function doClick(buttonName) { + var button = buttons[buttonName]; + if (!button) { + return; + } + + inputBox.focus(); + var linkOrImage = button === buttons.link || button.id === buttons.image; + + var state = new TextareaState(input); + + if (!state) { + return; + } + + var chunks = state.getChunks(); + + // Some commands launch a "modal" prompt dialog. Javascript + // can't really make a modal dialog box and the WMD code + // will continue to execute while the dialog is displayed. + // This prevents the dialog pattern I'm used to and means + // I can't do something like this: + // + // var link = CreateLinkDialog(); + // makeMarkdownLink(link); + // + // Instead of this straightforward method of handling a + // dialog I have to pass any code which would execute + // after the dialog is dismissed (e.g. link creation) + // in a function parameter. + // + // Yes this is awkward and I think it sucks, but there's + // no real workaround. Only the image and link code + // create dialogs and require the function pointers. + var fixupInputArea = function () { + + inputBox.focus(); + + if (chunks) { + state.setChunks(chunks); + } + + state.restore(); + }; + + var noCleanup = button(chunks, fixupInputArea); + + if (!noCleanup) { + fixupInputArea(); + if (!linkOrImage) { + inputBox.adjustCursorPosition(); + } + } + } + + function bindCommand(method) { + if (typeof method === "string") + method = commandManager[method]; + return function () { + method.apply(commandManager, arguments); + }; + } + + function makeSpritedButtonRow() { + + buttons.bold = bindCommand("doBold"); + buttons.italic = bindCommand("doItalic"); + buttons.strikethrough = bindCommand("doStrikethrough"); + buttons.link = bindCommand(function (chunk, postProcessing) { + return this.doLinkOrImage(chunk, postProcessing, false); + }); + buttons.quote = bindCommand("doBlockquote"); + buttons.code = bindCommand("doCode"); + buttons.image = bindCommand(function (chunk, postProcessing) { + return this.doLinkOrImage(chunk, postProcessing, true); + }); + buttons.olist = bindCommand(function (chunk, postProcessing) { + this.doList(chunk, postProcessing, true); + }); + buttons.ulist = bindCommand(function (chunk, postProcessing) { + this.doList(chunk, postProcessing, false); + }); + buttons.heading = bindCommand("doHeading"); + buttons.hr = bindCommand("doHorizontalRule"); + buttons.table = bindCommand("doTable"); + } + + this.doClick = doClick; + +} + +function CommandManager(pluginHooks, getString) { + this.hooks = pluginHooks; + this.getString = getString; +} + +var commandProto = CommandManager.prototype; + +// The markdown symbols - 4 spaces = code, > = blockquote, etc. +commandProto.prefixes = "(?:\\s{4,}|\\s*>|\\s*-\\s+|\\s*\\d+\\.|=|\\+|-|_|\\*|#|\\s*\\[[^\n]]+\\]:)"; + +// Remove markdown symbols from the chunk selection. +commandProto.unwrap = function (chunk) { + var txt = new re("([^\\n])\\n(?!(\\n|" + this.prefixes + "))", "g"); + chunk.selection = chunk.selection.replace(txt, "$1 $2"); +}; + +commandProto.wrap = function (chunk, len) { + this.unwrap(chunk); + var regex = new re("(.{1," + len + "})( +|$\\n?)", "gm"), + that = this; + + chunk.selection = chunk.selection.replace(regex, function (line, marked) { + if (new re("^" + that.prefixes, "").test(line)) { + return line; + } + return marked + "\n"; + }); + + chunk.selection = chunk.selection.replace(/\s+$/, ""); +}; + +commandProto.doBold = function (chunk, postProcessing) { + return this.doBorI(chunk, postProcessing, 2, this.getString("boldexample")); +}; + +commandProto.doItalic = function (chunk, postProcessing) { + return this.doBorI(chunk, postProcessing, 1, this.getString("italicexample")); +}; + +// chunk: The selected region that will be enclosed with */** +// nStars: 1 for italics, 2 for bold +// insertText: If you just click the button without highlighting text, this gets inserted +commandProto.doBorI = function (chunk, postProcessing, nStars, insertText) { + + // Get rid of whitespace and fixup newlines. + chunk.trimWhitespace(); + chunk.selection = chunk.selection.replace(/\n{2,}/g, "\n"); + + // Look for stars before and after. Is the chunk already marked up? + // note that these regex matches cannot fail + var starsBefore = /(\**$)/.exec(chunk.before)[0]; + var starsAfter = /(^\**)/.exec(chunk.after)[0]; + + var prevStars = Math.min(starsBefore.length, starsAfter.length); + + // Remove stars if we have to since the button acts as a toggle. + if ((prevStars >= nStars) && (prevStars != 2 || nStars != 1)) { + chunk.before = chunk.before.replace(re("[*]{" + nStars + "}$", ""), ""); + chunk.after = chunk.after.replace(re("^[*]{" + nStars + "}", ""), ""); + } else if (!chunk.selection && starsAfter) { + // It's not really clear why this code is necessary. It just moves + // some arbitrary stuff around. + chunk.after = chunk.after.replace(/^([*_]*)/, ""); + chunk.before = chunk.before.replace(/(\s?)$/, ""); + var whitespace = re.$1; + chunk.before = chunk.before + starsAfter + whitespace; + } else { + + // In most cases, if you don't have any selected text and click the button + // you'll get a selected, marked up region with the default text inserted. + if (!chunk.selection && !starsAfter) { + chunk.selection = insertText; + } + + // Add the true markup. + var markup = nStars <= 1 ? "*" : "**"; // shouldn't the test be = ? + chunk.before = chunk.before + markup; + chunk.after = markup + chunk.after; + } + + return; +}; + +commandProto.doStrikethrough = function (chunk, postProcessing) { + + // Get rid of whitespace and fixup newlines. + chunk.trimWhitespace(); + chunk.selection = chunk.selection.replace(/\n{2,}/g, "\n"); + + // Look for stars before and after. Is the chunk already marked up? + // note that these regex matches cannot fail + var starsBefore = /(~*$)/.exec(chunk.before)[0]; + var starsAfter = /(^~*)/.exec(chunk.after)[0]; + + var prevStars = Math.min(starsBefore.length, starsAfter.length); + + var nStars = 2; + + // Remove stars if we have to since the button acts as a toggle. + if ((prevStars >= nStars) && (prevStars != 2 || nStars != 1)) { + chunk.before = chunk.before.replace(re("[~]{" + nStars + "}$", ""), ""); + chunk.after = chunk.after.replace(re("^[~]{" + nStars + "}", ""), ""); + } else if (!chunk.selection && starsAfter) { + // It's not really clear why this code is necessary. It just moves + // some arbitrary stuff around. + chunk.after = chunk.after.replace(/^(~*)/, ""); + chunk.before = chunk.before.replace(/(\s?)$/, ""); + var whitespace = re.$1; + chunk.before = chunk.before + starsAfter + whitespace; + } else { + + // In most cases, if you don't have any selected text and click the button + // you'll get a selected, marked up region with the default text inserted. + if (!chunk.selection && !starsAfter) { + chunk.selection = this.getString("strikethroughexample"); + } + + // Add the true markup. + var markup = "~~"; // shouldn't the test be = ? + chunk.before = chunk.before + markup; + chunk.after = markup + chunk.after; + } + + return; +}; + +commandProto.stripLinkDefs = function (text, defsToAdd) { + + text = text.replace(/^[ ]{0,3}\[(\d+)\]:[ \t]*\n?[ \t]*?[ \t]*\n?[ \t]*(?:(\n*)["(](.+?)[")][ \t]*)?(?:\n+|$)/gm, + function (totalMatch, id, link, newlines, title) { + defsToAdd[id] = totalMatch.replace(/\s*$/, ""); + if (newlines) { + // Strip the title and return that separately. + defsToAdd[id] = totalMatch.replace(/["(](.+?)[")]$/, ""); + return newlines + title; + } + return ""; + }); + + return text; +}; + +commandProto.addLinkDef = function (chunk, linkDef) { + + var refNumber = 0; // The current reference number + var defsToAdd = {}; // + // Start with a clean slate by removing all previous link definitions. + chunk.before = this.stripLinkDefs(chunk.before, defsToAdd); + chunk.selection = this.stripLinkDefs(chunk.selection, defsToAdd); + chunk.after = this.stripLinkDefs(chunk.after, defsToAdd); + + var defs = ""; + var regex = /(\[)((?:\[[^\]]*\]|[^\[\]])*)(\][ ]?(?:\n[ ]*)?\[)(\d+)(\])/g; + + var addDefNumber = function (def) { + refNumber++; + def = def.replace(/^[ ]{0,3}\[(\d+)\]:/, " [" + refNumber + "]:"); + defs += "\n" + def; + }; + + // note that + // a) the recursive call to getLink cannot go infinite, because by definition + // of regex, inner is always a proper substring of wholeMatch, and + // b) more than one level of nesting is neither supported by the regex + // nor making a lot of sense (the only use case for nesting is a linked image) + var getLink = function (wholeMatch, before, inner, afterInner, id, end) { + inner = inner.replace(regex, getLink); + if (defsToAdd[id]) { + addDefNumber(defsToAdd[id]); + return before + inner + afterInner + refNumber + end; + } + return wholeMatch; + }; + + chunk.before = chunk.before.replace(regex, getLink); + + if (linkDef) { + addDefNumber(linkDef); + } else { + chunk.selection = chunk.selection.replace(regex, getLink); + } + + var refOut = refNumber; + + chunk.after = chunk.after.replace(regex, getLink); + + if (chunk.after) { + chunk.after = chunk.after.replace(/\n*$/, ""); + } + if (!chunk.after) { + chunk.selection = chunk.selection.replace(/\n*$/, ""); + } + + chunk.after += "\n\n" + defs; + + return refOut; +}; + +// takes the line as entered into the add link/as image dialog and makes +// sure the URL and the optinal title are "nice". +function properlyEncoded(linkdef) { + return linkdef.replace(/^\s*(.*?)(?:\s+"(.+)")?\s*$/, function (wholematch, link, title) { + link = link.replace(/\?.*$/, function (querypart) { + return querypart.replace(/\+/g, " "); // in the query string, a plus and a space are identical + }); + link = decodeURIComponent(link); // unencode first, to prevent double encoding + link = encodeURI(link).replace(/'/g, '%27').replace(/\(/g, '%28').replace(/\)/g, '%29'); + link = link.replace(/\?.*$/, function (querypart) { + return querypart.replace(/\+/g, "%2b"); // since we replaced plus with spaces in the query part, all pluses that now appear where originally encoded + }); + if (title) { + title = title.trim ? title.trim() : title.replace(/^\s*/, "").replace(/\s*$/, ""); + title = title.replace(/"/g, "quot;").replace(/\(/g, "(").replace(/\)/g, ")").replace(//g, ">"); + } + return title ? link + ' "' + title + '"' : link; + }); +} + +commandProto.doLinkOrImage = function (chunk, postProcessing, isImage) { + + chunk.trimWhitespace(); + //chunk.findTags(/\s*!?\[/, /\][ ]?(?:\n[ ]*)?(\[.*?\])?/); + chunk.findTags(/\s*!?\[/, /\][ ]?(?:\n[ ]*)?(\(.*?\))?/); + + if (chunk.endTag.length > 1 && chunk.startTag.length > 0) { + + chunk.startTag = chunk.startTag.replace(/!?\[/, ""); + chunk.endTag = ""; + this.addLinkDef(chunk, null); + + } else { + + // We're moving start and end tag back into the selection, since (as we're in the else block) we're not + // *removing* a link, but *adding* one, so whatever findTags() found is now back to being part of the + // link text. linkEnteredCallback takes care of escaping any brackets. + chunk.selection = chunk.startTag + chunk.selection + chunk.endTag; + chunk.startTag = chunk.endTag = ""; + + if (/\n\n/.test(chunk.selection)) { + this.addLinkDef(chunk, null); + return; + } + var that = this; + // The function to be executed when you enter a link and press OK or Cancel. + // Marks up the link and adds the ref. + var linkEnteredCallback = function (link) { + + if (link !== null) { + // ( $1 + // [^\\] anything that's not a backslash + // (?:\\\\)* an even number (this includes zero) of backslashes + // ) + // (?= followed by + // [[\]] an opening or closing bracket + // ) + // + // In other words, a non-escaped bracket. These have to be escaped now to make sure they + // don't count as the end of the link or similar. + // Note that the actual bracket has to be a lookahead, because (in case of to subsequent brackets), + // the bracket in one match may be the "not a backslash" character in the next match, so it + // should not be consumed by the first match. + // The "prepend a space and finally remove it" steps makes sure there is a "not a backslash" at the + // start of the string, so this also works if the selection begins with a bracket. We cannot solve + // this by anchoring with ^, because in the case that the selection starts with two brackets, this + // would mean a zero-width match at the start. Since zero-width matches advance the string position, + // the first bracket could then not act as the "not a backslash" for the second. + chunk.selection = (" " + chunk.selection).replace(/([^\\](?:\\\\)*)(?=[[\]])/g, "$1\\").substr(1); + + /* + var linkDef = " [999]: " + properlyEncoded(link); + + var num = that.addLinkDef(chunk, linkDef); + */ + chunk.startTag = isImage ? "![" : "["; + //chunk.endTag = "][" + num + "]"; + chunk.endTag = "](" + properlyEncoded(link) + ")"; + + if (!chunk.selection) { + if (isImage) { + chunk.selection = that.getString("imagedescription"); + } else { + chunk.selection = that.getString("linkdescription"); + } + } + } + postProcessing(); + }; + + if (isImage) { + this.hooks.insertImageDialog(linkEnteredCallback); + } else { + this.hooks.insertLinkDialog(linkEnteredCallback); + } + return true; + } +}; + +// When making a list, hitting shift-enter will put your cursor on the next line +// at the current indent level. +commandProto.doAutoindent = function (chunk) { + + var commandMgr = this, + fakeSelection = false; + + chunk.before = chunk.before.replace(/(\n|^)[ ]{0,3}([*+-]|\d+[.])[ \t]*\n$/, "\n\n"); + chunk.before = chunk.before.replace(/(\n|^)[ ]{0,3}>[ \t]*\n$/, "\n\n"); + chunk.before = chunk.before.replace(/(\n|^)[ \t]+\n$/, "\n\n"); + + // There's no selection, end the cursor wasn't at the end of the line: + // The user wants to split the current list item / code line / blockquote line + // (for the latter it doesn't really matter) in two. Temporarily select the + // (rest of the) line to achieve this. + if (!chunk.selection && !/^[ \t]*(?:\n|$)/.test(chunk.after)) { + chunk.after = chunk.after.replace(/^[^\n]*/, function (wholeMatch) { + chunk.selection = wholeMatch; + return ""; + }); + fakeSelection = true; + } + + if (/(\n|^)[ ]{0,3}([*+-]|\d+[.])[ \t]+.*\n$/.test(chunk.before)) { + if (commandMgr.doList) { + commandMgr.doList(chunk); + } + } + if (/(\n|^)[ ]{0,3}>[ \t]+.*\n$/.test(chunk.before)) { + if (commandMgr.doBlockquote) { + commandMgr.doBlockquote(chunk); + } + } + if (/(\n|^)(\t|[ ]{4,}).*\n$/.test(chunk.before)) { + if (commandMgr.doCode) { + commandMgr.doCode(chunk); + } + } + + if (fakeSelection) { + chunk.after = chunk.selection + chunk.after; + chunk.selection = ""; + } +}; + +commandProto.doBlockquote = function (chunk) { + + chunk.selection = chunk.selection.replace(/^(\n*)([^\r]+?)(\n*)$/, + function (totalMatch, newlinesBefore, text, newlinesAfter) { + chunk.before += newlinesBefore; + chunk.after = newlinesAfter + chunk.after; + return text; + }); + + chunk.before = chunk.before.replace(/(>[ \t]*)$/, + function (totalMatch, blankLine) { + chunk.selection = blankLine + chunk.selection; + return ""; + }); + + chunk.selection = chunk.selection.replace(/^(\s|>)+$/, ""); + chunk.selection = chunk.selection || this.getString("quoteexample"); + + // The original code uses a regular expression to find out how much of the + // text *directly before* the selection already was a blockquote: + + /* + if (chunk.before) { + chunk.before = chunk.before.replace(/\n?$/, "\n"); + } + chunk.before = chunk.before.replace(/(((\n|^)(\n[ \t]*)*>(.+\n)*.*)+(\n[ \t]*)*$)/, + function (totalMatch) { + chunk.startTag = totalMatch; + return ""; + }); + */ + + // This comes down to: + // Go backwards as many lines a possible, such that each line + // a) starts with ">", or + // b) is almost empty, except for whitespace, or + // c) is preceeded by an unbroken chain of non-empty lines + // leading up to a line that starts with ">" and at least one more character + // and in addition + // d) at least one line fulfills a) + // + // Since this is essentially a backwards-moving regex, it's susceptible to + // catstrophic backtracking and can cause the browser to hang; + // see e.g. http://meta.stackoverflow.com/questions/9807. + // + // Hence we replaced this by a simple state machine that just goes through the + // lines and checks for a), b), and c). + + var match = "", + leftOver = "", + line; + if (chunk.before) { + var lines = chunk.before.replace(/\n$/, "").split("\n"); + var inChain = false; + for (var i = 0; i < lines.length; i++) { + var good = false; + line = lines[i]; + inChain = inChain && line.length > 0; // c) any non-empty line continues the chain + if (/^>/.test(line)) { // a) + good = true; + if (!inChain && line.length > 1) // c) any line that starts with ">" and has at least one more character starts the chain + inChain = true; + } else if (/^[ \t]*$/.test(line)) { // b) + good = true; + } else { + good = inChain; // c) the line is not empty and does not start with ">", so it matches if and only if we're in the chain + } + if (good) { + match += line + "\n"; + } else { + leftOver += match + line; + match = "\n"; + } + } + if (!/(^|\n)>/.test(match)) { // d) + leftOver += match; + match = ""; + } + } + + chunk.startTag = match; + chunk.before = leftOver; + + // end of change + + if (chunk.after) { + chunk.after = chunk.after.replace(/^\n?/, "\n"); + } + + chunk.after = chunk.after.replace(/^(((\n|^)(\n[ \t]*)*>(.+\n)*.*)+(\n[ \t]*)*)/, + function (totalMatch) { + chunk.endTag = totalMatch; + return ""; + } + ); + + var replaceBlanksInTags = function (useBracket) { + + var replacement = useBracket ? "> " : ""; + + if (chunk.startTag) { + chunk.startTag = chunk.startTag.replace(/\n((>|\s)*)\n$/, + function (totalMatch, markdown) { + return "\n" + markdown.replace(/^[ ]{0,3}>?[ \t]*$/gm, replacement) + "\n"; + }); + } + if (chunk.endTag) { + chunk.endTag = chunk.endTag.replace(/^\n((>|\s)*)\n/, + function (totalMatch, markdown) { + return "\n" + markdown.replace(/^[ ]{0,3}>?[ \t]*$/gm, replacement) + "\n"; + }); + } + }; + + if (/^(?![ ]{0,3}>)/m.test(chunk.selection)) { + this.wrap(chunk, SETTINGS.lineLength - 2); + chunk.selection = chunk.selection.replace(/^/gm, "> "); + replaceBlanksInTags(true); + chunk.skipLines(); + } else { + chunk.selection = chunk.selection.replace(/^[ ]{0,3}> ?/gm, ""); + this.unwrap(chunk); + replaceBlanksInTags(false); + + if (!/^(\n|^)[ ]{0,3}>/.test(chunk.selection) && chunk.startTag) { + chunk.startTag = chunk.startTag.replace(/\n{0,2}$/, "\n\n"); + } + + if (!/(\n|^)[ ]{0,3}>.*$/.test(chunk.selection) && chunk.endTag) { + chunk.endTag = chunk.endTag.replace(/^\n{0,2}/, "\n\n"); + } + } + + chunk.selection = this.hooks.postBlockquoteCreation(chunk.selection); + + if (!/\n/.test(chunk.selection)) { + chunk.selection = chunk.selection.replace(/^(> *)/, + function (wholeMatch, blanks) { + chunk.startTag += blanks; + return ""; + }); + } +}; + +commandProto.doCode = function (chunk) { + + var hasTextBefore = /\S[ ]*$/.test(chunk.before); + var hasTextAfter = /^[ ]*\S/.test(chunk.after); + + // Use 'four space' markdown if the selection is on its own + // line or is multiline. + if ((!hasTextAfter && !hasTextBefore) || /\n/.test(chunk.selection)) { + + chunk.before = chunk.before.replace(/[ ]{4}$/, + function (totalMatch) { + chunk.selection = totalMatch + chunk.selection; + return ""; + }); + + var nLinesBack = 1; + var nLinesForward = 1; + + if (/(\n|^)(\t|[ ]{4,}).*\n$/.test(chunk.before)) { + nLinesBack = 0; + } + if (/^\n(\t|[ ]{4,})/.test(chunk.after)) { + nLinesForward = 0; + } + + chunk.skipLines(nLinesBack, nLinesForward); + + if (!chunk.selection) { + chunk.startTag = " "; + chunk.selection = this.getString("codeexample"); + } else { + if (/^[ ]{0,3}\S/m.test(chunk.selection)) { + if (/\n/.test(chunk.selection)) + chunk.selection = chunk.selection.replace(/^/gm, " "); + else // if it's not multiline, do not select the four added spaces; this is more consistent with the doList behavior + chunk.before += " "; + } else { + chunk.selection = chunk.selection.replace(/^(?:[ ]{4}|[ ]{0,3}\t)/gm, ""); + } + } + } else { + // Use backticks (`) to delimit the code block. + + chunk.trimWhitespace(); + chunk.findTags(/`/, /`/); + + if (!chunk.startTag && !chunk.endTag) { + chunk.startTag = chunk.endTag = "`"; + if (!chunk.selection) { + chunk.selection = this.getString("codeexample"); + } + } else if (chunk.endTag && !chunk.startTag) { + chunk.before += chunk.endTag; + chunk.endTag = ""; + } else { + chunk.startTag = chunk.endTag = ""; + } + } +}; + +commandProto.doList = function (chunk, postProcessing, isNumberedList) { + + // These are identical except at the very beginning and end. + // Should probably use the regex extension function to make this clearer. + var previousItemsRegex = /(\n|^)(([ ]{0,3}([*+-]|\d+[.])[ \t]+.*)(\n.+|\n{2,}([*+-].*|\d+[.])[ \t]+.*|\n{2,}[ \t]+\S.*)*)\n*$/; + var nextItemsRegex = /^\n*(([ ]{0,3}([*+-]|\d+[.])[ \t]+.*)(\n.+|\n{2,}([*+-].*|\d+[.])[ \t]+.*|\n{2,}[ \t]+\S.*)*)\n*/; + + // The default bullet is a dash but others are possible. + // This has nothing to do with the particular HTML bullet, + // it's just a markdown bullet. + var bullet = "-"; + + // The number in a numbered list. + var num = 1; + + // Get the item prefix - e.g. " 1. " for a numbered list, " - " for a bulleted list. + var getItemPrefix = function () { + var prefix; + if (isNumberedList) { + prefix = " " + num + ". "; + num++; + } else { + prefix = " " + bullet + " "; + } + return prefix; + }; + + // Fixes the prefixes of the other list items. + var getPrefixedItem = function (itemText) { + + // The numbering flag is unset when called by autoindent. + if (isNumberedList === undefined) { + isNumberedList = /^\s*\d/.test(itemText); + } + + // Renumber/bullet the list element. + itemText = itemText.replace(/^[ ]{0,3}([*+-]|\d+[.])\s/gm, + function () { + return getItemPrefix(); + }); + + return itemText; + }; + + chunk.findTags(/(\n|^)*[ ]{0,3}([*+-]|\d+[.])\s+/, null); + + if (chunk.before && !/\n$/.test(chunk.before) && !/^\n/.test(chunk.startTag)) { + chunk.before += chunk.startTag; + chunk.startTag = ""; + } + + if (chunk.startTag) { + + var hasDigits = /\d+[.]/.test(chunk.startTag); + chunk.startTag = ""; + chunk.selection = chunk.selection.replace(/\n[ ]{4}/g, "\n"); + this.unwrap(chunk); + chunk.skipLines(); + + if (hasDigits) { + // Have to renumber the bullet points if this is a numbered list. + chunk.after = chunk.after.replace(nextItemsRegex, getPrefixedItem); + } + if (isNumberedList == hasDigits) { + return; + } + } + + var nLinesUp = 1; + + chunk.before = chunk.before.replace(previousItemsRegex, + function (itemText) { + if (/^\s*([*+-])/.test(itemText)) { + bullet = re.$1; + } + nLinesUp = /[^\n]\n\n[^\n]/.test(itemText) ? 1 : 0; + return getPrefixedItem(itemText); + }); + + if (!chunk.selection) { + chunk.selection = this.getString("litem"); + } + + var prefix = getItemPrefix(); + + var nLinesDown = 1; + + chunk.after = chunk.after.replace(nextItemsRegex, + function (itemText) { + nLinesDown = /[^\n]\n\n[^\n]/.test(itemText) ? 1 : 0; + return getPrefixedItem(itemText); + }); + + chunk.trimWhitespace(true); + chunk.skipLines(nLinesUp, nLinesDown, true); + chunk.startTag = prefix; + var spaces = prefix.replace(/./g, " "); + this.wrap(chunk, SETTINGS.lineLength - spaces.length); + chunk.selection = chunk.selection.replace(/\n/g, "\n" + spaces); + +}; + +commandProto.doTable = function (chunk) { + // Credit: https://github.com/fcrespo82/atom-markdown-table-formatter + + var keepFirstAndLastPipes = true, + /* + ( # header capture + (?: + (?:[^\n]*?\|[^\n]*) # line w/ at least one pipe + \ * # maybe trailing whitespace + )? # maybe header + (?:\n|^) # newline + ) + ( # format capture + (?: + \|\ *:?-+:?\ * # format starting w/pipe + |\|?(?:\ *:?-+:?\ *\|)+ # or separated by pipe + ) + (?:\ *:?-+:?\ *)? # maybe w/o trailing pipe + \ * # maybe trailing whitespace + \n # newline + ) + ( # body capture + (?: + (?:[^\n]*?\|[^\n]*) # line w/ at least one pipe + \ * # maybe trailing whitespace + (?:\n|$) # newline + )+ # at least one + ) + */ + regex = /((?:(?:[^\n]*?\|[^\n]*) *)?(?:\r?\n|^))((?:\| *:?-+:? *|\|?(?: *:?-+:? *\|)+)(?: *:?-+:? *)? *\r?\n)((?:(?:[^\n]*?\|[^\n]*) *(?:\r?\n|$))+)/; + + + function padding(len, str) { + var result = ''; + str = str || ' '; + len = Math.floor(len); + for (var i = 0; i < len; i++) { + result += str; + } + return result; + } + + function stripTailPipes(str) { + return str.trim().replace(/(^\||\|$)/g, ""); + } + + function splitCells(str) { + return str.split('|'); + } + + function addTailPipes(str) { + if (keepFirstAndLastPipes) { + return "|" + str + "|"; + } else { + return str; + } + } + + function joinCells(arr) { + return arr.join('|'); + } + + function formatTable(text, appendNewline) { + var i, j, len1, ref1, ref2, ref3, k, len2, results, formatline, headerline, just, formatrow, data, line, lines, justify, cell, cells, first, last, ends, columns, content, widths, formatted, front, back; + formatline = text[2].trim(); + headerline = text[1].trim(); + ref1 = headerline.length === 0 ? [0, text[3]] : [1, text[1] + text[3]], formatrow = ref1[0], data = ref1[1]; + lines = data.trim().split('\n'); + justify = []; + ref2 = splitCells(stripTailPipes(formatline)); + for (j = 0, len1 = ref2.length; j < len1; j++) { + cell = ref2[j]; + ref3 = cell.trim(), first = ref3[0], last = ref3[ref3.length - 1]; + switch ((ends = (first ? first : ':') + (last ? last : ''))) { + case '::': + case '-:': + case ':-': + justify.push(ends); + break; + default: + justify.push('--'); + } + } + columns = justify.length; + content = []; + for (j = 0, len1 = lines.length; j < len1; j++) { + line = lines[j]; + cells = splitCells(stripTailPipes(line)); + cells[columns - 1] = joinCells(cells.slice(columns - 1)); + results = []; + for (k = 0, len2 = cells.length; k < len2; k++) { + cell = cells[k]; + results.push(padding(' ') + ((ref2 = cell ? typeof cell.trim === "function" ? cell.trim() : void 0 : void 0) ? ref2 : '') + padding(' ')); + } + content.push(results); + } + widths = []; + for (i = j = 0, ref2 = columns - 1; 0 <= ref2 ? j <= ref2 : j >= ref2; i = 0 <= ref2 ? ++j : --j) { + results = []; + for (k = 0, len1 = content.length; k < len1; k++) { + cells = content[k]; + results.push(cells[i].length); + } + widths.push(Math.max.apply(Math, [2].concat(results))); + } + just = function (string, col) { + var back, front, length; + length = widths[col] - string.length; + switch (justify[col]) { + case '::': + front = padding[0], back = padding[1]; + return padding(length / 2) + string + padding((length + 1) / 2); + case '-:': + return padding(length) + string; + default: + return string + padding(length); + } + }; + formatted = []; + for (j = 0, len1 = content.length; j < len1; j++) { + cells = content[j]; + results = []; + for (i = k = 0, ref2 = columns - 1; 0 <= ref2 ? k <= ref2 : k >= ref2; i = 0 <= ref2 ? ++k : --k) { + results.push(just(cells[i], i)); + } + formatted.push(addTailPipes(joinCells(results))); + } + formatline = addTailPipes(joinCells((function () { + var j, ref2, ref3, results; + results = []; + for (i = j = 0, ref2 = columns - 1; 0 <= ref2 ? j <= ref2 : j >= ref2; i = 0 <= ref2 ? ++j : --j) { + ref3 = justify[i], front = ref3[0], back = ref3[1]; + results.push(front + padding(widths[i] - 2, '-') + back); + } + return results; + })())); + formatted.splice(formatrow, 0, formatline); + var result = (headerline.length === 0 && text[1] !== '' ? '\n' : '') + formatted.join('\n'); + if (appendNewline !== false) { + result += '\n' + } + return result; + } + + if (chunk.before.slice(-1) !== '\n') { + chunk.before += '\n'; + } + var match = chunk.selection.match(regex); + if (match) { + chunk.selection = formatTable(match, chunk.selection.slice(-1) === '\n'); + } else { + var table = chunk.selection + '|\n-|-\n|'; + match = table.match(regex); + if (!match || match[0].slice(0, table.length) !== table) { + return; + } + table = formatTable(match); + var selectionOffset = keepFirstAndLastPipes ? 1 : 0; + var pipePos = table.indexOf('|', selectionOffset); + chunk.before += table.slice(0, selectionOffset); + chunk.selection = table.slice(selectionOffset, pipePos); + chunk.after = table.slice(pipePos) + chunk.after; + } +}; + +commandProto.doHeading = function (chunk) { + + // Remove leading/trailing whitespace and reduce internal spaces to single spaces. + chunk.selection = chunk.selection.replace(/\s+/g, " "); + chunk.selection = chunk.selection.replace(/(^\s+|\s+$)/g, ""); + + // If we clicked the button with no selected text, we just + // make a level 2 hash header around some default text. + if (!chunk.selection) { + chunk.startTag = "## "; + chunk.selection = this.getString("headingexample"); + return; + } + + var headerLevel = 0; // The existing header level of the selected text. + + // Remove any existing hash heading markdown and save the header level. + chunk.findTags(/#+[ ]*/, /[ ]*#+/); + if (/#+/.test(chunk.startTag)) { + headerLevel = re.lastMatch.length; + } + chunk.startTag = chunk.endTag = ""; + + // Try to get the current header level by looking for - and = in the line + // below the selection. + chunk.findTags(null, /\s?(-+|=+)/); + if (/=+/.test(chunk.endTag)) { + headerLevel = 1; + } + if (/-+/.test(chunk.endTag)) { + headerLevel = 2; + } + + // Skip to the next line so we can create the header markdown. + chunk.startTag = chunk.endTag = ""; + chunk.skipLines(1, 1); + + // We make a level 2 header if there is no current header. + // If there is a header level, we substract one from the header level. + // If it's already a level 1 header, it's removed. + var headerLevelToCreate = headerLevel === 0 ? 2 : headerLevel - 1; + + if (headerLevelToCreate > 0) { + + chunk.startTag = ''; + while (headerLevelToCreate--) { + chunk.startTag += '#'; + } + chunk.startTag += ' '; + } +}; + +commandProto.doHorizontalRule = function (chunk) { + chunk.startTag = "----------\n"; + chunk.selection = ""; + chunk.skipLines(2, 1, true); +}; + +export default function (options) { + return new Pagedown(options); +}; diff --git a/src/components/App.vue b/src/components/App.vue new file mode 100644 index 00000000..04508ff8 --- /dev/null +++ b/src/components/App.vue @@ -0,0 +1,48 @@ + + + + + diff --git a/src/components/ButtonBar.vue b/src/components/ButtonBar.vue new file mode 100644 index 00000000..cfb6ef6a --- /dev/null +++ b/src/components/ButtonBar.vue @@ -0,0 +1,88 @@ + + + + + + diff --git a/src/components/Editor.vue b/src/components/Editor.vue new file mode 100644 index 00000000..a67ab249 --- /dev/null +++ b/src/components/Editor.vue @@ -0,0 +1,64 @@ + + + + + + diff --git a/src/components/Layout.vue b/src/components/Layout.vue new file mode 100644 index 00000000..a4dd32ed --- /dev/null +++ b/src/components/Layout.vue @@ -0,0 +1,165 @@ + + + + + diff --git a/src/components/NavigationBar.vue b/src/components/NavigationBar.vue new file mode 100644 index 00000000..fb1fa32a --- /dev/null +++ b/src/components/NavigationBar.vue @@ -0,0 +1,76 @@ + + + + + diff --git a/src/components/Preview.vue b/src/components/Preview.vue new file mode 100644 index 00000000..89b003c5 --- /dev/null +++ b/src/components/Preview.vue @@ -0,0 +1,48 @@ + + + + + + diff --git a/src/components/SideBar.vue b/src/components/SideBar.vue new file mode 100644 index 00000000..e343ccdf --- /dev/null +++ b/src/components/SideBar.vue @@ -0,0 +1,17 @@ + + + + diff --git a/src/components/StatusBar.vue b/src/components/StatusBar.vue new file mode 100644 index 00000000..2d6b481b --- /dev/null +++ b/src/components/StatusBar.vue @@ -0,0 +1,122 @@ + + + + + diff --git a/src/components/Toc.vue b/src/components/Toc.vue new file mode 100644 index 00000000..254d5b76 --- /dev/null +++ b/src/components/Toc.vue @@ -0,0 +1,6 @@ + diff --git a/src/components/common/base.scss b/src/components/common/base.scss new file mode 100644 index 00000000..8c2f50a9 --- /dev/null +++ b/src/components/common/base.scss @@ -0,0 +1,145 @@ +@import '../../node_modules/normalize-scss/sass/normalize'; + +@include normalize(); + +html, +body { + color: rgba(0, 0, 0, 0.75); + font-family: $font-family-editor; + font-variant-ligatures: common-ligatures; + line-height: 1.65; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +h1, +h2, +h3, +h4, +h5, +h6, +p, +blockquote, +pre, +ul, +ol, +dl { + margin: 1.2em 0; +} + +ol ul, +ul ol, +ul ul, +ol ol { + margin: 0; +} + +a { + color: $link-color; +} + +code, +kbd, +pre, +samp { + font-family: $font-family-monospace; + font-size: $font-size-monospace; + + * { + font-size: inherit; + } +} + +blockquote { + color: rgba(0, 0, 0, 0.4); + margin-left: 1em; + margin-right: 1em; +} + +code { + background-color: $code-bg; + border-radius: $border-radius-base; + padding: 2px 4px; +} + +hr { + border: 0; + border-top: 1px solid rgba(128, 128, 128, 0.15); + margin: 2em 0; +} + +pre > code { + background-color: $code-bg; + display: block; + overflow-x: auto; + padding: 0.5em; + -webkit-text-size-adjust: none; +} + +.toc ul { + list-style-type: none; + padding-left: 20px; +} + +table { + background-color: transparent; + border-collapse: collapse; + border-spacing: 0; +} + +td, +th { + border-right: 1px solid #e0e0e0; + padding: 8px 12px; + + &:last-child { + border-right: 0; + } +} + +td { + border-top: 1px solid #e0e0e0; +} + +kbd { + background-color: #fff; + border: 1px solid rgba(63, 63, 63, 0.25); + border-radius: 3px; + box-shadow: 0 1px 0 rgba(63, 63, 63, 0.25); + color: #333; + display: inline-block; + font-size: 0.7em; + margin: 0 0.1em; + padding: 0.1em 0.6em; + white-space: nowrap; +} + +abbr { + &[title] { + border-bottom: 1px dotted #777; + cursor: help; + } +} + +.footnote { + font-size: 0.8em; + position: relative; + top: -0.25em; + vertical-align: top; +} + +.export-container { + margin-bottom: 180px; + margin-left: auto; + margin-right: auto; + + > :not(h1):not(h2):not(h3):not(h4):not(h5):not(h6):not([align]) { + text-align: justify; + } +} + +@media (min-width: 768px) { + .export-container { + width: 750px; + } +} diff --git a/src/components/common/flex.scss b/src/components/common/flex.scss new file mode 100644 index 00000000..58ee9d08 --- /dev/null +++ b/src/components/common/flex.scss @@ -0,0 +1,19 @@ +.flex { + display: -webkit-box; + display: -webkit-flex; + display: -moz-box; + display: -ms-flexbox; + display: flex; +} + +.flex--row { + -webkit-box-orient: horizontal; + -webkit-flex-direction: row; + flex-direction: row; +} + +.flex--column { + -webkit-box-orient: vertical; + -webkit-flex-direction: column; + flex-direction: column; +} diff --git a/src/components/common/markdownHighlighting.scss b/src/components/common/markdownHighlighting.scss new file mode 100644 index 00000000..8c798b4c --- /dev/null +++ b/src/components/common/markdownHighlighting.scss @@ -0,0 +1,232 @@ +@import './variables'; + +.markdown-highlighting { + color: $editor-color; + font-family: inherit; + font-size: inherit; + -webkit-font-smoothing: auto; + -moz-osx-font-smoothing: auto; + font-weight: $editor-font-weight-base; + + .code { + font-family: $font-family-monospace; + font-size: $font-size-monospace; + + * { + font-size: inherit !important; + } + } + + .pre { + color: $editor-color; + font-family: $font-family-monospace; + font-size: $font-size-monospace; + word-break: break-all; + + [class*='language-'] { + color: $editor-color-dark; + } + + * { + font-size: inherit !important; + } + } + + .tag { + color: $editor-color; + font-family: $font-family-monospace; + font-size: $font-size-monospace; + font-weight: $editor-font-weight-bold; + + .punctuation, + .attr-value, + .attr-name { + font-weight: $editor-font-weight-base; + } + + * { + font-size: inherit !important; + } + } + + .latex, + .math { + color: $editor-color; + } + + .entity { + color: $editor-color; + font-family: $font-family-monospace; + font-size: $font-size-monospace; + font-style: italic; + + * { + font-size: inherit !important; + } + } + + .table { + font-family: $font-family-monospace; + font-size: $font-size-monospace; + + * { + font-size: inherit !important; + } + } + + .comment { + color: $editor-color-light; + } + + .keyword { + color: $editor-color-dark; + font-weight: $editor-font-weight-bold; + } + + .code, + .img, + .img-wrapper, + .imgref, + .cl-toc { + background-color: $code-bg; + border-radius: $code-border-radius; + padding: 0.15em 0; + } + + .img-wrapper { + display: inline-block; + + .img { + display: inline-block; + padding: 0; + } + + img { + max-width: 100%; + padding: 0 0.15em; + } + } + + .cl-toc { + font-size: 2.8em; + padding: 0.15em; + } + + .blockquote { + color: rgba(0, 0, 0, 0.48); + } + + .h1, + .h2, + .h3, + .h4, + .h5, + .h6 { + font-weight: $editor-font-weight-bold; + } + + .h1, + .h11 { + font-size: 2em; + } + + .h2, + .h22 { + font-size: 1.5em; + } + + .h3 { + font-size: 1.17em; + } + + .h4 { + font-size: 1em; + } + + .h5 { + font-size: 0.83em; + } + + .h6 { + font-size: 0.75em; + } + + .cl-hash { + color: $editor-color-light; + } + + .cl, + .hr { + color: $editor-color-light; + font-style: normal; + font-weight: $editor-font-weight-base; + } + + .em, + .em .cl { + font-style: italic; + } + + .strong, + .strong .cl, + .term { + font-weight: $editor-font-weight-bold; + } + + .cl-del-text { + text-decoration: line-through; + } + + .url, + .email, + .cl-underlined-text { + text-decoration: underline; + } + + .linkdef .url { + color: $editor-color-light; + } + + .fn, + .inlinefn, + .sup { + font-size: smaller; + position: relative; + top: -0.5em; + } + + .sub { + bottom: -0.25em; + font-size: smaller; + position: relative; + } + + .img, + .imgref, + .link, + .linkref { + color: $editor-color-light; + + .cl-underlined-text { + color: $editor-color-dark; + } + } + + .cl-title { + color: $editor-color; + } +} + +.markdown-highlighting--inline { + .h1, + .h11, + .h2, + .h22, + .h3, + .h4, + .h5, + .h6, + .cl-toc { + font-size: inherit; + } +} diff --git a/src/components/common/prism.scss b/src/components/common/prism.scss new file mode 100644 index 00000000..e9332d1a --- /dev/null +++ b/src/components/common/prism.scss @@ -0,0 +1,73 @@ +.token.pre.gfm, +.prism { + * { + font-weight: inherit !important; + } + + .token.comment, + .token.prolog, + .token.doctype, + .token.cdata { + color: #708090; + } + + .token.punctuation { + color: #999; + } + + .namespace { + opacity: 0.7; + } + + .token.property, + .token.tag, + .token.boolean, + .token.number, + .token.constant, + .token.symbol, + .token.deleted { + color: #905; + } + + .token.selector, + .token.attr-name, + .token.string, + .token.char, + .token.builtin, + .token.inserted { + color: #690; + } + + .token.operator, + .token.entity, + .token.url, + .language-css .token.string, + .style .token.string { + color: #a67f59; + } + + .token.atrule, + .token.attr-value, + .token.keyword { + color: #07a; + } + + .token.function { + color: #dd4a68; + } + + .token.regex, + .token.important, + .token.variable { + color: #e90; + } + + .token.important, + .token.bold { + font-weight: 500; + } + + .token.italic { + font-style: italic; + } +} diff --git a/src/components/common/variables.scss b/src/components/common/variables.scss new file mode 100644 index 00000000..217e8351 --- /dev/null +++ b/src/components/common/variables.scss @@ -0,0 +1,13 @@ +$font-family-editor: "Helvetica Neue", Helvetica, sans-serif; +$font-family-monospace: "Lucida Sans Typewriter", "Lucida Console", monaco, Courrier, monospace; +$font-size-monospace: 0.9em; +$code-bg: rgba(0, 0, 0, 0.05); +$code-border-radius: 3px; +$link-color: #0366d6; +$border-radius-base: 3px; + +$editor-color: rgba(0, 0, 0, 0.8); +$editor-color-light: rgba(0, 0, 0, 0.28); +$editor-color-dark: #000; +$editor-font-weight-base: 400; +$editor-font-weight-bold: 600; diff --git a/src/extensions/index.js b/src/extensions/index.js new file mode 100644 index 00000000..56fedeea --- /dev/null +++ b/src/extensions/index.js @@ -0,0 +1 @@ +import './markdownExt'; diff --git a/src/extensions/markdownExt.js b/src/extensions/markdownExt.js new file mode 100644 index 00000000..2b5060a8 --- /dev/null +++ b/src/extensions/markdownExt.js @@ -0,0 +1,197 @@ +import Prism from 'prismjs'; +import markdownitAbbr from 'markdown-it-abbr'; +import markdownitDeflist from 'markdown-it-deflist'; +import markdownitFootnote from 'markdown-it-footnote'; +import markdownitSub from 'markdown-it-sub'; +import markdownitSup from 'markdown-it-sup'; +import extensionSvc from '../services/extensionSvc'; + +const coreBaseRules = [ + 'normalize', + 'block', + 'inline', + 'linkify', + 'replacements', + 'smartquotes', +]; +const blockBaseRules = [ + 'code', + 'fence', + 'blockquote', + 'hr', + 'list', + 'reference', + 'heading', + 'lheading', + 'html_block', + 'table', + 'paragraph', +]; +const inlineBaseRules = [ + 'text', + 'newline', + 'escape', + 'backticks', + 'strikethrough', + 'emphasis', + 'link', + 'image', + 'autolink', + 'html_inline', + 'entity', +]; +const inlineBaseRules2 = [ + 'balance_pairs', + 'strikethrough', + 'emphasis', + 'text_collapse', +]; + +extensionSvc.onGetOptions((options, properties) => { + options.abbr = properties['ext:markdown:abbr'] !== 'false'; + options.breaks = properties['ext:markdown:breaks'] === 'true'; + options.deflist = properties['ext:markdown:deflist'] !== 'false'; + options.del = properties['ext:markdown:del'] !== 'false'; + options.fence = properties['ext:markdown:fence'] !== 'false'; + options.footnote = properties['ext:markdown:footnote'] !== 'false'; + options.linkify = properties['ext:markdown:linkify'] !== 'false'; + options.sub = properties['ext:markdown:sub'] !== 'false'; + options.sup = properties['ext:markdown:sup'] !== 'false'; + options.table = properties['ext:markdown:table'] !== 'false'; + options.typographer = properties['ext:markdown:typographer'] !== 'false'; +}); + +extensionSvc.onInitConverter(0, (markdown, options) => { + markdown.set({ + html: true, + breaks: !!options.breaks, + linkify: !!options.linkify, + typographer: !!options.typographer, + langPrefix: 'prism language-', + }); + + markdown.core.ruler.enable(coreBaseRules); + + const blockRules = blockBaseRules.slice(); + if (!options.fence) { + blockRules.splice(blockRules.indexOf('fence'), 1); + } + if (!options.table) { + blockRules.splice(blockRules.indexOf('table'), 1); + } + markdown.block.ruler.enable(blockRules); + + const inlineRules = inlineBaseRules.slice(); + const inlineRules2 = inlineBaseRules2.slice(); + if (!options.del) { + inlineRules.splice(blockRules.indexOf('strikethrough'), 1); + inlineRules2.splice(blockRules.indexOf('strikethrough'), 1); + } + markdown.inline.ruler.enable(inlineRules); + markdown.inline.ruler2.enable(inlineRules2); + + if (options.abbr) { + markdown.use(markdownitAbbr); + } + if (options.deflist) { + markdown.use(markdownitDeflist); + } + if (options.footnote) { + markdown.use(markdownitFootnote); + } + if (options.sub) { + markdown.use(markdownitSub); + } + if (options.sup) { + markdown.use(markdownitSup); + } + + markdown.core.ruler.before('replacements', 'anchors', (state) => { + const anchorHash = {}; + let headingOpenToken; + let headingContent; + state.tokens.cl_each((token) => { + if (token.type === 'heading_open') { + headingContent = ''; + headingOpenToken = token; + } else if (token.type === 'heading_close') { + headingOpenToken.headingContent = headingContent; + + // Slugify according to http://pandoc.org/README.html#extension-auto_identifiers + let slug = headingContent + .replace(/\s/g, '-') // Replace all spaces and newlines with hyphens + .replace(/[\0-,/:-@[-^`{-~]/g, '') // Remove all punctuation, except underscores, hyphens, and periods + .toLowerCase(); // Convert all alphabetic characters to lowercase + + // Remove everything up to the first letter + let i; + for (i = 0; i < slug.length; i += 1) { + const charCode = slug.charCodeAt(i); + if ((charCode >= 0x61 && charCode <= 0x7A) || charCode > 0x7E) { + break; + } + } + + // If nothing is left after this, use the identifier `section` + slug = slug.slice(i) || 'section'; + + let anchor = slug; + let index = 1; + while (Object.prototype.hasOwnProperty.call(anchorHash, anchor)) { + anchor = `${slug}-${index}`; + index += 1; + } + anchorHash[anchor] = true; + headingOpenToken.headingAnchor = anchor; + headingOpenToken.attrs = [ + ['id', anchor], + ]; + headingOpenToken = undefined; + } else if (headingOpenToken) { + headingContent += token.children.cl_reduce((result, child) => { + if (child.type !== 'footnote_ref') { + return result + child.content; + } + return result; + }, ''); + } + }); + }); + + // Wrap tables into a div for scrolling + markdown.renderer.rules.table_open = (tokens, idx, opts) => + `
      ${markdown.renderer.renderToken(tokens, idx, opts)}`; + markdown.renderer.rules.table_close = (tokens, idx, opts) => + `${markdown.renderer.renderToken(tokens, idx, opts)}
      `; + + // Transform style into align attribute to pass the HTML sanitizer + const textAlignLength = 'text-align:'.length; + markdown.renderer.rules.td_open = (tokens, idx, opts) => { + const token = tokens[idx]; + if (token.attrs && token.attrs.length && token.attrs[0][0] === 'style') { + token.attrs = [ + ['align', token.attrs[0][1].slice(textAlignLength)], + ]; + } + return markdown.renderer.renderToken(tokens, idx, opts); + }; + markdown.renderer.rules.th_open = markdown.renderer.rules.td_open; + + markdown.renderer.rules.footnote_ref = (tokens, idx) => { + const n = Number(tokens[idx].meta.id + 1).toString(); + let id = `fnref${n}`; + if (tokens[idx].meta.subId > 0) { + id += `:${tokens[idx].meta.subId}`; + } + return `${n}`; + }; +}); + +extensionSvc.onSectionPreview((elt) => { + elt.querySelectorAll('.prism').cl_each((prismElt) => { + if (!prismElt.highlighted) { + Prism.highlightElement(prismElt); + } + prismElt.highlighted = true; + }); +}); diff --git a/src/icons/CodeBraces.vue b/src/icons/CodeBraces.vue new file mode 100644 index 00000000..90423321 --- /dev/null +++ b/src/icons/CodeBraces.vue @@ -0,0 +1,5 @@ + diff --git a/src/icons/Eye.vue b/src/icons/Eye.vue new file mode 100644 index 00000000..2c543fef --- /dev/null +++ b/src/icons/Eye.vue @@ -0,0 +1,5 @@ + diff --git a/src/icons/FileImage.vue b/src/icons/FileImage.vue new file mode 100644 index 00000000..dd3fa0a0 --- /dev/null +++ b/src/icons/FileImage.vue @@ -0,0 +1,5 @@ + diff --git a/src/icons/FormatBold.vue b/src/icons/FormatBold.vue new file mode 100644 index 00000000..8cd78707 --- /dev/null +++ b/src/icons/FormatBold.vue @@ -0,0 +1,5 @@ + diff --git a/src/icons/FormatHorizontalRule.vue b/src/icons/FormatHorizontalRule.vue new file mode 100644 index 00000000..a0437d6e --- /dev/null +++ b/src/icons/FormatHorizontalRule.vue @@ -0,0 +1,5 @@ + diff --git a/src/icons/FormatItalic.vue b/src/icons/FormatItalic.vue new file mode 100644 index 00000000..de698f89 --- /dev/null +++ b/src/icons/FormatItalic.vue @@ -0,0 +1,5 @@ + diff --git a/src/icons/FormatListBulleted.vue b/src/icons/FormatListBulleted.vue new file mode 100644 index 00000000..dbdb0a01 --- /dev/null +++ b/src/icons/FormatListBulleted.vue @@ -0,0 +1,5 @@ + diff --git a/src/icons/FormatListNumbers.vue b/src/icons/FormatListNumbers.vue new file mode 100644 index 00000000..6bd088ba --- /dev/null +++ b/src/icons/FormatListNumbers.vue @@ -0,0 +1,5 @@ + diff --git a/src/icons/FormatQuoteClose.vue b/src/icons/FormatQuoteClose.vue new file mode 100644 index 00000000..3001e74f --- /dev/null +++ b/src/icons/FormatQuoteClose.vue @@ -0,0 +1,5 @@ + diff --git a/src/icons/FormatSize.vue b/src/icons/FormatSize.vue new file mode 100644 index 00000000..77e03dd8 --- /dev/null +++ b/src/icons/FormatSize.vue @@ -0,0 +1,5 @@ + diff --git a/src/icons/FormatStrikethrough.vue b/src/icons/FormatStrikethrough.vue new file mode 100644 index 00000000..50d794a3 --- /dev/null +++ b/src/icons/FormatStrikethrough.vue @@ -0,0 +1,5 @@ + diff --git a/src/icons/LinkVariant.vue b/src/icons/LinkVariant.vue new file mode 100644 index 00000000..090cff99 --- /dev/null +++ b/src/icons/LinkVariant.vue @@ -0,0 +1,5 @@ + diff --git a/src/icons/NavigationBar.vue b/src/icons/NavigationBar.vue new file mode 100644 index 00000000..d4b83ddc --- /dev/null +++ b/src/icons/NavigationBar.vue @@ -0,0 +1,6 @@ + diff --git a/src/icons/SidePreview.vue b/src/icons/SidePreview.vue new file mode 100644 index 00000000..4ad35827 --- /dev/null +++ b/src/icons/SidePreview.vue @@ -0,0 +1,5 @@ + diff --git a/src/icons/StatusBar.vue b/src/icons/StatusBar.vue new file mode 100644 index 00000000..68299652 --- /dev/null +++ b/src/icons/StatusBar.vue @@ -0,0 +1,6 @@ + diff --git a/src/icons/Table.vue b/src/icons/Table.vue new file mode 100644 index 00000000..ed408a9b --- /dev/null +++ b/src/icons/Table.vue @@ -0,0 +1,5 @@ + diff --git a/src/icons/index.js b/src/icons/index.js new file mode 100644 index 00000000..f25701f7 --- /dev/null +++ b/src/icons/index.js @@ -0,0 +1,34 @@ +import Vue from 'vue'; +import FormatBold from './FormatBold'; +import FormatItalic from './FormatItalic'; +import FormatQuoteClose from './FormatQuoteClose'; +import CodeBraces from './CodeBraces'; +import LinkVariant from './LinkVariant'; +import FileImage from './FileImage'; +import Table from './Table'; +import FormatListNumbers from './FormatListNumbers'; +import FormatListBulleted from './FormatListBulleted'; +import FormatSize from './FormatSize'; +import FormatHorizontalRule from './FormatHorizontalRule'; +import FormatStrikethrough from './FormatStrikethrough'; +import StatusBar from './StatusBar'; +import NavigationBar from './NavigationBar'; +import SidePreview from './SidePreview'; +import Eye from './Eye'; + +Vue.component('iconFormatBold', FormatBold); +Vue.component('iconFormatItalic', FormatItalic); +Vue.component('iconFormatQuoteClose', FormatQuoteClose); +Vue.component('iconCodeBraces', CodeBraces); +Vue.component('iconLinkVariant', LinkVariant); +Vue.component('iconFileImage', FileImage); +Vue.component('iconTable', Table); +Vue.component('iconFormatListNumbers', FormatListNumbers); +Vue.component('iconFormatListBulleted', FormatListBulleted); +Vue.component('iconFormatSize', FormatSize); +Vue.component('iconFormatHorizontalRule', FormatHorizontalRule); +Vue.component('iconFormatStrikethrough', FormatStrikethrough); +Vue.component('iconStatusBar', StatusBar); +Vue.component('iconNavigationBar', NavigationBar); +Vue.component('iconSidePreview', SidePreview); +Vue.component('iconEye', Eye); diff --git a/src/index.js b/src/index.js new file mode 100644 index 00000000..e8a832e7 --- /dev/null +++ b/src/index.js @@ -0,0 +1,15 @@ +import Vue from 'vue'; +import App from './components/App'; +import store from './store'; +import './extensions/'; +import './services/optional'; +import './icons/'; + +Vue.config.productionTip = false; + +/* eslint-disable no-new */ +new Vue({ + el: '#app', + store, + render: h => h(App), +}); diff --git a/src/markdown/sample.md b/src/markdown/sample.md new file mode 100644 index 00000000..78dcc5aa --- /dev/null +++ b/src/markdown/sample.md @@ -0,0 +1,117 @@ +# Basic writing + +## Styling text + +Make text **bold** or *italic* by using either `*` or `_` around the text. + +_This text will be italic_ +__This text will be bold__ + +Create strikethrough text by using `~~`. + +~~Mistaken text.~~ + +## Blockquotes + +Indicate blockquotes with a `>`. + +> Blockquote + +## Headings + +Create a heading by adding one or more `#` symbols before your heading text. + +##### Heading level 5 +###### Heading level 6 + +## Horizontal rules + +Insert a horizontal rule by putting three or more `-`, `*`, or `_` on a line by themselves. + +---------- + +## Table of contents + +Insert a table of contents using the marker `[TOC]`. + +[TOC] + + +# Lists + +## Unordered lists + +Make an unordered list by preceding list items with either a `*` or a `-`. + +- Item +- Item +* Item + +## Ordered lists + +Make an ordered list by preceding list items with a number. + +1. Item 1 +2. Item 2 +3. Item 3 + + +# Code formatting + +## Inline formats + +Use single backticks to format text in a special `monospace format`. + +## Multiple lines + +Indent four spaces or a tab to format text as its own distinct block. + + var foo = 'bar'; // baz + +## Code highlighting + +Use triple backticks including the language identifier to have syntax highlighting. + +```js +var foo = 'bar'; // baz +``` + + +# Links and images + +## Links + +Create a link by wrapping link text in brackets, and then wrapping the link in parentheses. + +[Visit Classeur](http://classeur.io) + +## Images + +Images are like links, but have an exclamation point in front of them. + +![Classeur Logo](http://classeur.io/images/logo.png) + +## Footnotes + +To create footnotes, add a label starting with a `^` between a set of square brackets like this[^footnote], and then, declare the linked content. + + [^footnote]: Here is the content of the footnote. + + +# Tables + +Create tables by assembling a list of words and dividing them with hyphens (for the first row), and then separating each column with a pipe. + +First Header | Second Header +------------- | ------------- +Content Cell | Content Cell +Content Cell | Content Cell + +By including colons within the header row, you can define text to be left-aligned, right-aligned, or center-aligned. + +| Left-Aligned | Center Aligned | Right Aligned | +| :------------ |:---------------:| -----:| +| col 3 is | some wordy text | $1600 | +| col 2 is | centered | $12 | +| zebra stripes | are neat | $1 | + diff --git a/src/services/animationSvc.js b/src/services/animationSvc.js new file mode 100644 index 00000000..3ec7fe0c --- /dev/null +++ b/src/services/animationSvc.js @@ -0,0 +1,228 @@ +import bezierEasing from 'bezier-easing'; + +const easings = { + materialIn: bezierEasing(0.75, 0, 0.8, 0.25), + materialOut: bezierEasing(0.25, 0.8, 0.25, 1.0), +}; + +const vendors = ['moz', 'webkit']; +for (let x = 0; x < vendors.length && !window.requestAnimationFrame; x += 1) { + window.requestAnimationFrame = window[`${vendors[x]}RequestAnimationFrame`]; + window.cancelAnimationFrame = window[`${vendors[x]}CancelAnimationFrame`] || + window[`${vendors[x]}CancelRequestAnimationFrame`]; +} + +const transformStyles = [ + 'WebkitTransform', + 'MozTransform', + 'msTransform', + 'OTransform', + 'transform', +]; + +const transitionEndEvents = { + WebkitTransition: 'webkitTransitionEnd', + MozTransition: 'transitionend', + msTransition: 'MSTransitionEnd', + OTransition: 'oTransitionEnd', + transition: 'transitionend', +}; + +function getStyle(styles) { + const elt = document.createElement('div'); + return styles.reduce((result, style) => { + if (elt.style[style] === undefined) { + return undefined; + } + return style; + }, undefined); +} + +const transformStyle = getStyle(transformStyles); +const transitionStyle = getStyle(Object.keys(transitionEndEvents)); +const transitionEndEvent = transitionEndEvents[transitionStyle]; + +function identity(x) { + return x; +} + +function ElementAttribute(name) { + this.name = name; + this.setStart = (animation) => { + const value = animation.elt[name]; + animation.$start[name] = value; + return value !== undefined && animation.$end[name] !== undefined; + }; + this.applyCurrent = (animation) => { + animation.elt[name] = animation.$current[name]; + }; +} + +function StyleAttribute(name, unit, defaultValue, wrap = identity) { + this.name = name; + this.setStart = (animation) => { + let value = parseFloat(animation.elt.style[name]); + if (isNaN(value)) { + value = animation.$current[name] || defaultValue; + } + animation.$start[name] = value; + return animation.$end[name] !== undefined; + }; + this.applyCurrent = (animation) => { + animation.elt.style[name] = wrap(animation.$current[name]) + unit; + }; +} + +function TransformAttribute(name, unit, defaultValue, wrap = identity) { + this.name = name; + this.setStart = (animation) => { + let value = animation.$current[name]; + if (value === undefined) { + value = defaultValue; + } + animation.$start[name] = value; + if (animation.$end[name] === undefined) { + animation.$end[name] = value; + } + return value !== undefined; + }; + this.applyCurrent = (animation) => { + const value = animation.$current[name]; + return value !== defaultValue && `${name}(${wrap(value)}${unit})`; + }; +} + +const attributes = [ + new ElementAttribute('scrollTop'), + new ElementAttribute('scrollLeft'), + new StyleAttribute('opacity', '', 1), + new StyleAttribute('zIndex', '', 0), + new TransformAttribute('translateX', 'px', 0, Math.round), + new TransformAttribute('translateY', 'px', 0, Math.round), + new TransformAttribute('scale', '', 1), + new TransformAttribute('rotate', 'deg', 0), +].concat([ + 'width', + 'height', + 'top', + 'right', + 'bottom', + 'left', +].map(name => new StyleAttribute(name, 'px', 0, Math.round))); + +class Animation { + constructor(elt) { + this.elt = elt; + this.$current = {}; + this.$pending = {}; + } + + start(param1, param2, param3) { + let endCb = param1; + let stepCb = param2; + let useTransition = false; + if (typeof param1 === 'boolean') { + useTransition = param1; + endCb = param2; + stepCb = param3; + } + + this.stop(); + this.$start = {}; + this.$end = this.$pending; + this.$pending = {}; + this.$attributes = attributes.filter(attribute => attribute.setStart(this)); + this.$end.duration = this.$end.duration || 0; + this.$end.delay = this.$end.delay || 0; + this.$end.easing = easings[this.$end.easing] || easings.materialOut; + this.$end.endCb = typeof endCb === 'function' && endCb; + this.$end.stepCb = typeof stepCb === 'function' && stepCb; + this.$startTime = Date.now() + this.$end.delay; + this.loop(this.$end.duration && useTransition); + return this.elt; + } + + stop() { + window.cancelAnimationFrame(this.$requestId); + } + + loop(useTransition) { + const onTransitionEnd = (evt) => { + if (evt.target === this.elt) { + this.elt.removeEventListener(transitionEndEvent, onTransitionEnd); + const endCb = this.$end.endCb; + this.$end.endCb = undefined; + if (endCb) { + endCb(); + } + } + }; + + let progress = (Date.now() - this.$startTime) / this.$end.duration; + let transition = ''; + if (useTransition) { + progress = 1; + const transitions = [ + 'all', + `${this.$end.duration}ms`, + this.$end.easing.toCSS(), + ]; + if (this.$end.delay) { + transitions.push(`${this.$end.duration}ms`); + } + transition = transitions.join(' '); + if (this.$end.endCb) { + this.elt.addEventListener(transitionEndEvent, onTransitionEnd); + } + } else if (progress < 1) { + this.$requestId = window.requestAnimationFrame(() => this.loop(false)); + if (progress < 0) { + return; + } + } else if (this.$end.endCb) { + this.$requestId = window.requestAnimationFrame(this.$end.endCb); + } + + const coeff = this.$end.easing.get(progress); + const transforms = this.$attributes.reduce((result, attribute) => { + if (progress < 1) { + const diff = this.$end[attribute.name] - this.$start[attribute.name]; + this.$current[attribute.name] = this.$start[attribute.name] + (diff * coeff); + } else { + this.$current[attribute.name] = this.$end[attribute.name]; + } + const transform = attribute.applyCurrent(this); + if (transform) { + result.push(transform); + } + return result; + }, []); + + if (transforms.length) { + transforms.push('translateZ(0)'); // activate GPU + } + const transform = transforms.join(' '); + this.elt.style[transformStyle] = transform; + this.elt.style[transitionStyle] = transition; + if (this.$end.stepCb) { + this.$end.stepCb(); + } + } +} + +attributes.map(attribute => attribute.name).concat('duration', 'easing', 'delay') + .forEach((name) => { + Animation.prototype[name] = function setter(val) { + this.$pending[name] = val; + return this; + }; + }); + +function animate(elt) { + if (!elt.$animation) { + elt.$animation = new Animation(elt); + } + return elt.$animation; +} + +export default { animate }; diff --git a/src/services/constants.js b/src/services/constants.js new file mode 100644 index 00000000..a769bf60 --- /dev/null +++ b/src/services/constants.js @@ -0,0 +1,3 @@ +export default { + scrollOffset: 20, +}; diff --git a/src/services/editorEngineSvc.js b/src/services/editorEngineSvc.js new file mode 100644 index 00000000..1b1fa233 --- /dev/null +++ b/src/services/editorEngineSvc.js @@ -0,0 +1,158 @@ +import DiffMatchPatch from 'diff-match-patch'; +import cledit from '../cledit/cledit'; +import clDiffUtils from '../cledit/cldiffutils'; +import store from '../store'; + +let clEditor; +const newDiscussionMarker0 = new cledit.Marker(0); +const newDiscussionMarker1 = new cledit.Marker(0, true); +let markerKeys; +let markerIdxMap; +let previousPatchableText; +let currentPatchableText; +let discussionMarkers; +let content; +let isChangePatch; + +function getDiscussionMarkers(discussion, discussionId, onMarker) { + function getMarker(offsetName) { + const markerOffset = discussion[offsetName]; + const markerKey = discussionId + offsetName; + let marker = discussionMarkers[markerKey]; + if (markerOffset !== undefined) { + if (!marker) { + marker = new cledit.Marker(markerOffset, offsetName === 'offset1'); + marker.discussionId = discussionId; + marker.offsetName = offsetName; + clEditor.addMarker(marker); + discussionMarkers[markerKey] = marker; + } + onMarker(marker); + } + } + getMarker('offset0'); + getMarker('offset1'); +} + +function syncDiscussionMarkers() { + Object.keys(discussionMarkers) + .forEach((markerKey) => { + const marker = discussionMarkers[markerKey]; + // Remove marker if discussion was removed + const discussion = content.discussions[marker.discussionId]; + if (!discussion || discussion[marker.offsetName] === undefined) { + clEditor.removeMarker(marker); + delete discussionMarkers[markerKey]; + } + }); + + Object.keys(content.discussions) + .forEach((discussionId) => { + const discussion = content.discussions[discussionId]; + getDiscussionMarkers(discussion, discussionId, (marker) => { + discussion[marker.offsetName] = marker.offset; + }); + }); +} + +const diffMatchPatch = new DiffMatchPatch(); + +function makePatches() { + const diffs = diffMatchPatch.diff_main(previousPatchableText, currentPatchableText); + return diffMatchPatch.patch_make(previousPatchableText, diffs); +} + +function applyPatches(patches) { + const newPatchableText = diffMatchPatch.patch_apply(patches, currentPatchableText)[0]; + let result = newPatchableText; + if (markerKeys.length) { + // Strip text markers + result = result.replace(new RegExp(`[\ue000-${String.fromCharCode((0xe000 + markerKeys.length) - 1)}]`, 'g'), ''); + } + // Expect a `contentChanged` event + if (result !== clEditor.getContent()) { + previousPatchableText = currentPatchableText; + currentPatchableText = newPatchableText; + isChangePatch = true; + } + return result; +} + +function reversePatches(patches) { + const result = diffMatchPatch.patch_deepCopy(patches).reverse(); + result.forEach((patch) => { + patch.diffs.forEach((diff) => { + diff[0] = -diff[0]; + }); + }); + return result; +} + +export default { + clEditor: null, + lastChange: 0, + lastExternalChange: 0, + createClEditor(editorElt) { + this.clEditor = cledit(editorElt, editorElt.parentNode); + clEditor = this.clEditor; + markerKeys = []; + markerIdxMap = Object.create(null); + discussionMarkers = {}; + clEditor.on('contentChanged', (text) => { + store.commit('files/setCurrentFileContentText', text); + syncDiscussionMarkers(); + if (!isChangePatch) { + previousPatchableText = currentPatchableText; + currentPatchableText = clDiffUtils.makePatchableText(content, markerKeys, markerIdxMap); + } else { + // Take a chance to restore discussion offsets on undo/redo + content.text = currentPatchableText; + clDiffUtils.restoreDiscussionOffsets(content, markerKeys); + content.discussions.cl_each((discussion, discussionId) => { + getDiscussionMarkers(discussion, discussionId, (marker) => { + marker.offset = discussion[marker.offsetName]; + }); + }); + } + isChangePatch = false; + this.lastChange = Date.now(); + }); + clEditor.addMarker(newDiscussionMarker0); + clEditor.addMarker(newDiscussionMarker1); + }, + initClEditor(opts, reinit) { + if (store.state.files.currentFile.content) { + const options = Object.assign({}, opts); + + if (content !== store.state.files.currentFile.content) { + content = store.state.files.currentFile.content; + currentPatchableText = clDiffUtils.makePatchableText(content, markerKeys, markerIdxMap); + previousPatchableText = currentPatchableText; + syncDiscussionMarkers(); + } + + if (reinit) { + options.content = content.text; + options.selectionStart = content.state.selectionStart; + options.selectionEnd = content.state.selectionEnd; + } + + options.patchHandler = { + makePatches, + applyPatches: patches => applyPatches(patches), + reversePatches, + }; + clEditor.init(options); + } + }, + applyContent(isExternal) { + if (!clEditor) { + return null; + } + if (isExternal) { + this.lastExternalChange = Date.now(); + } + syncDiscussionMarkers(); + return clEditor.setContent(content.text, isExternal); + }, +}; diff --git a/src/services/editorSvc.js b/src/services/editorSvc.js new file mode 100644 index 00000000..6b652a28 --- /dev/null +++ b/src/services/editorSvc.js @@ -0,0 +1,734 @@ +import Vue from 'vue'; +import DiffMatchPatch from 'diff-match-patch'; +import Prism from 'prismjs'; +import markdownItPandocRenderer from 'markdown-it-pandoc-renderer'; +import cledit from '../cledit/cledit'; +import pagedown from '../cledit/pagedown'; +import htmlSanitizer from '../cledit/htmlSanitizer'; +import markdownConversionSvc from './markdownConversionSvc'; +import markdownGrammarSvc from './markdownGrammarSvc'; +import sectionUtils from './sectionUtils'; +import extensionSvc from './extensionSvc'; +import constants from './constants'; +import animationSvc from './animationSvc'; +import editorEngineSvc from './editorEngineSvc'; +import store from '../store'; + +const debounce = cledit.Utils.debounce; + +const allowDebounce = (action, wait) => { + let timeoutId; + return (doDebounce = false) => { + clearTimeout(timeoutId); + if (doDebounce) { + timeoutId = setTimeout(() => action(), wait); + } else { + action(); + } + }; +}; + +const diffMatchPatch = new DiffMatchPatch(); +let reinitClEditor = true; +let isPreviewRefreshed = false; +let tokens; +const anchorHash = {}; + +const editorSvc = Object.assign(new Vue(), { // Use a vue instance as an event bus + // Elements + editorElt: null, + previewElt: null, + tocElt: null, + // Other objects + pagedownEditor: null, + options: {}, + prismGrammars: {}, + converter: null, + parsingCtx: null, + conversionCtx: null, + sectionList: null, + sectionDescList: [], + sectionDescMeasuredList: null, + sectionDescWithDiffsList: null, + selectionRange: null, + previewSelectionRange: null, + previewSelectionStartOffset: null, + previewHtml: null, + previewText: null, + + /** + * Get element and dimension that handles scrolling. + */ + getObjectToScroll() { + let elt = this.editorElt.parentNode; + let dimensionKey = 'editorDimension'; + if (!store.state.layout.showEditor) { + elt = this.previewElt.parentNode; + dimensionKey = 'previewDimension'; + } + return { + elt, + dimensionKey, + }; + }, + + /** + * Get an object describing the position of the scroll bar in the file. + */ + getScrollPosition() { + const objToScroll = this.getObjectToScroll(); + const scrollTop = objToScroll.elt.scrollTop; + let result; + if (this.sectionDescMeasuredList) { + this.sectionDescMeasuredList.some((sectionDesc, sectionIdx) => { + if (scrollTop >= sectionDesc[objToScroll.dimensionKey].endOffset) { + return false; + } + const posInSection = (scrollTop - sectionDesc[objToScroll.dimensionKey].startOffset) / + (sectionDesc[objToScroll.dimensionKey].height || 1); + result = { + sectionIdx, + posInSection, + }; + return true; + }); + } + return result; + }, + + /** + * Get the offset in the preview corresponding to the offset of the markdown in the editor + */ + getPreviewOffset(editorOffset) { + let previewOffset = 0; + let offset = editorOffset; + this.sectionDescList.some((sectionDesc) => { + if (!sectionDesc.textToPreviewDiffs) { + previewOffset = undefined; + return true; + } + if (sectionDesc.section.text.length >= offset) { + previewOffset += diffMatchPatch.diff_xIndex(sectionDesc.textToPreviewDiffs, offset); + return true; + } + offset -= sectionDesc.section.text.length; + previewOffset += sectionDesc.previewText.length; + return false; + }); + return previewOffset; + }, + + /** + * Get the offset of the markdown in the editor corresponding to the offset in the preview + */ + getEditorOffset(previewOffset) { + let offset = previewOffset; + let editorOffset = 0; + this.sectionDescList.some((sectionDesc) => { + if (!sectionDesc.textToPreviewDiffs) { + editorOffset = undefined; + return true; + } + if (sectionDesc.previewText.length >= offset) { + const previewToTextDiffs = sectionDesc.textToPreviewDiffs + .map(diff => [-diff[0], diff[1]]); + editorOffset += diffMatchPatch.diff_xIndex(previewToTextDiffs, offset); + return true; + } + offset -= sectionDesc.previewText.length; + editorOffset += sectionDesc.section.text.length; + return false; + }); + return editorOffset; + }, + + /** + * Returns the pandoc AST generated from the file tokens and the converter options + */ + getPandocAst() { + return tokens && markdownItPandocRenderer(tokens, this.converter.options); + }, + + /** + * Initialize the Prism grammar with the options + */ + initPrism() { + const options = { + insideFences: markdownConversionSvc.defaultOptions.insideFences, + ...this.options, + }; + this.prismGrammars = markdownGrammarSvc.makeGrammars(options); + }, + + /** + * Initialize the markdown-it converter with the options + */ + initConverter() { + this.converter = markdownConversionSvc.createConverter(this.options, true); + }, + + /** + * Initialize the cledit editor with markdown-it section parser and Prism highlighter + */ + initClEditor() { + if (!store.state.files.currentFile.isLoaded) { + reinitClEditor = true; + isPreviewRefreshed = false; + editorEngineSvc.clEditor.toggleEditable(false); + return; + } + const options = { + sectionHighlighter: section => Prism.highlight( + section.text, this.prismGrammars[section.data]), + sectionParser: (text) => { + this.parsingCtx = markdownConversionSvc.parseSections(this.converter, text); + return this.parsingCtx.sections; + }, + }; + editorEngineSvc.initClEditor(options, reinitClEditor); + editorEngineSvc.clEditor.toggleEditable(true); + reinitClEditor = false; + this.restoreScrollPosition(); + }, + + /** + * Finish the conversion initiated by the section parser + */ + convert() { + this.conversionCtx = markdownConversionSvc.convert(this.parsingCtx, this.conversionCtx); + this.$emit('conversionCtx', this.conversionCtx); + tokens = this.parsingCtx.markdownState.tokens; + }, + + /** + * Refresh the preview with the result of `convert()` + */ + refreshPreview() { + const newSectionDescList = []; + let sectionPreviewElt; + let sectionTocElt; + let sectionIdx = 0; + let sectionDescIdx = 0; + let insertBeforePreviewElt = this.previewElt.firstChild; + let insertBeforeTocElt = this.tocElt.firstChild; + let previewHtml = ''; + let heading; + this.conversionCtx.htmlSectionDiff.forEach((item) => { + for (let i = 0; i < item[1].length; i += 1) { + const section = this.conversionCtx.sectionList[sectionIdx]; + if (item[0] === 0) { + const sectionDesc = this.sectionDescList[sectionDescIdx]; + sectionDescIdx += 1; + sectionDesc.editorElt = section.elt; + newSectionDescList.push(sectionDesc); + previewHtml += sectionDesc.html; + sectionIdx += 1; + insertBeforePreviewElt.classList.remove('modified'); + insertBeforePreviewElt = insertBeforePreviewElt.nextSibling; + insertBeforeTocElt.classList.remove('modified'); + insertBeforeTocElt = insertBeforeTocElt.nextSibling; + } else if (item[0] === -1) { + sectionDescIdx += 1; + sectionPreviewElt = insertBeforePreviewElt; + insertBeforePreviewElt = insertBeforePreviewElt.nextSibling; + this.previewElt.removeChild(sectionPreviewElt); + sectionTocElt = insertBeforeTocElt; + insertBeforeTocElt = insertBeforeTocElt.nextSibling; + this.tocElt.removeChild(sectionTocElt); + } else if (item[0] === 1) { + const html = this.conversionCtx.htmlSectionList[sectionIdx]; + sectionIdx += 1; + + // Create preview section element + sectionPreviewElt = document.createElement('div'); + sectionPreviewElt.className = 'cl-preview-section modified'; + sectionPreviewElt.innerHTML = htmlSanitizer.sanitizeHtml(html); + if (insertBeforePreviewElt) { + this.previewElt.insertBefore(sectionPreviewElt, insertBeforePreviewElt); + } else { + this.previewElt.appendChild(sectionPreviewElt); + } + extensionSvc.sectionPreview(sectionPreviewElt, this.options); + + // Create TOC section element + sectionTocElt = document.createElement('div'); + sectionTocElt.className = 'cl-toc-section modified'; + let headingElt = sectionPreviewElt.querySelector('h1, h2, h3, h4, h5, h6'); + heading = undefined; + if (headingElt) { + heading = { + title: headingElt.textContent, + anchor: headingElt.id, + level: parseInt(headingElt.tagName.slice(1), 10), + }; + headingElt = headingElt.cloneNode(true); + headingElt.removeAttribute('id'); + sectionTocElt.appendChild(headingElt); + } + if (insertBeforeTocElt) { + this.tocElt.insertBefore(sectionTocElt, insertBeforeTocElt); + } else { + this.tocElt.appendChild(sectionTocElt); + } + + const clonedElt = sectionPreviewElt.cloneNode(true); + // Unwrap tables + clonedElt.querySelectorAll('.table-wrapper').cl_each((elt) => { + while (elt.firstChild) { + elt.parentNode.appendChild(elt.firstChild); + } + elt.parentNode.removeChild(elt); + }); + + previewHtml += clonedElt.innerHTML; + newSectionDescList.push({ + section, + editorElt: section.elt, + previewElt: sectionPreviewElt, + tocElt: sectionTocElt, + html: clonedElt.innerHTML, + heading, + }); + } + } + }); + this.sectionDescList = newSectionDescList; + this.previewHtml = previewHtml.replace(/^\s+|\s+$/g, ''); + this.tocElt.classList[ + this.tocElt.querySelector('.cl-toc-section *') ? 'remove' : 'add' + ]('toc-tab--empty'); + + // Run preview async operations (image loading, mathjax...) + const loadingImages = this.previewElt.querySelectorAll('.cl-preview-section.modified img'); + const loadedPromises = loadingImages.cl_map(imgElt => new Promise((resolve) => { + if (!imgElt.src) { + resolve(); + return; + } + const img = new window.Image(); + img.onload = resolve; + img.onerror = resolve; + img.src = imgElt.src; + })); + + Promise.all(loadedPromises.concat(extensionSvc.asyncPreview(this.options))) + .then(() => { + this.previewText = this.previewElt.textContent; + this.$emit('previewText', this.previewText); + // Debounce if sections have already been mesured + this.measureSectionDimensions(!!this.sectionDescMeasuredList); + this.makeTextToPreviewDiffs(true); + }); + }, + + /** + * Measure the height of each section in editor, preview and toc. + */ + measureSectionDimensions: allowDebounce(() => { + if (editorSvc.sectionDescList && this.sectionDescList !== editorSvc.sectionDescMeasuredList) { + sectionUtils.measureSectionDimensions(editorSvc); + editorSvc.sectionDescMeasuredList = editorSvc.sectionDescList; + editorSvc.$emit('sectionDescMeasuredList', editorSvc.sectionDescMeasuredList); + } + }, 500), + + /** + * Make the diff between editor's markdown and preview's html. + */ + makeTextToPreviewDiffs: allowDebounce(() => { + if (editorSvc.sectionDescList + && editorSvc.sectionDescList !== editorSvc.sectionDescMeasuredList) { + editorSvc.sectionDescList + .forEach((sectionDesc) => { + if (!sectionDesc.textToPreviewDiffs) { + sectionDesc.previewText = sectionDesc.previewElt.textContent; + sectionDesc.textToPreviewDiffs = diffMatchPatch.diff_main( + sectionDesc.section.text, sectionDesc.previewText); + } + }); + editorSvc.sectionDescWithDiffsList = editorSvc.sectionDescList; + } + }, 50), + + /** + * Save editor selection/scroll state into the current file content. + */ + saveContentState: allowDebounce(() => { + const scrollPosition = editorSvc.getScrollPosition() || + store.state.files.currentFile.content.state.scrollPosition; + store.commit('files/setCurrentFileContentState', { + selectionStart: editorEngineSvc.clEditor.selectionMgr.selectionStart, + selectionEnd: editorEngineSvc.clEditor.selectionMgr.selectionEnd, + scrollPosition, + }, { root: true }); + }, 100), + + /** + * Restore the scroll position from the current file content state. + */ + restoreScrollPosition() { + const scrollPosition = store.state.files.currentFile.content.state.scrollPosition; + if (scrollPosition && this.sectionDescMeasuredList) { + const objectToScroll = this.getObjectToScroll(); + const sectionDesc = this.sectionDescMeasuredList[scrollPosition.sectionIdx]; + if (sectionDesc) { + const scrollTop = sectionDesc[objectToScroll.dimensionKey].startOffset + + (sectionDesc[objectToScroll.dimensionKey].height * scrollPosition.posInSection); + objectToScroll.elt.scrollTop = scrollTop; + } + } + }, + + /** + * Report selection from the preview to the editor. + */ + saveSelection: allowDebounce(() => { + const selection = window.getSelection(); + let range = selection.rangeCount && selection.getRangeAt(0); + if (range) { + if ( + /* eslint-disable no-bitwise */ + !(editorSvc.previewElt.compareDocumentPosition(range.startContainer) + & window.Node.DOCUMENT_POSITION_CONTAINED_BY) || + !(editorSvc.previewElt.compareDocumentPosition(range.endContainer) + & window.Node.DOCUMENT_POSITION_CONTAINED_BY) + /* eslint-enable no-bitwise */ + ) { + range = null; + } + } + if (editorSvc.previewSelectionRange !== range) { + let previewSelectionStartOffset; + let previewSelectionEndOffset; + if (range) { + const startRange = document.createRange(); + startRange.setStart(editorSvc.previewElt, 0); + startRange.setEnd(range.startContainer, range.startOffset); + previewSelectionStartOffset = `${startRange}`.length; + previewSelectionEndOffset = previewSelectionStartOffset + `${range}`.length; + const editorStartOffset = editorSvc.getEditorOffset(previewSelectionStartOffset); + const editorEndOffset = editorSvc.getEditorOffset(previewSelectionEndOffset); + if (editorStartOffset !== undefined && editorEndOffset !== undefined) { + editorEngineSvc.clEditor.selectionMgr.setSelectionStartEnd( + editorStartOffset, editorEndOffset, false); + } + } + editorSvc.previewSelectionRange = range; + } + }, 50), + + /** + * Scroll the preview (or the editor if preview is hidden) to the specified anchor + */ + scrollToAnchor(anchor) { + let scrollTop = 0; + let scrollerElt = this.previewElt.parentNode; + const sectionDesc = anchorHash[anchor]; + if (sectionDesc) { + if (store.state.layout.showSidePreview || !store.state.layout.showEditor) { + scrollTop = sectionDesc.previewDimension.startOffset; + } else { + scrollTop = sectionDesc.editorDimension.startOffset - constants.scrollOffset; + scrollerElt = this.editorElt.parentNode; + } + } else { + const elt = document.getElementById(anchor); + if (elt) { + scrollTop = elt.offsetTop; + } + } + const maxScrollTop = scrollerElt.scrollHeight - scrollerElt.offsetHeight; + if (scrollTop < 0) { + scrollTop = 0; + } else if (scrollTop > maxScrollTop) { + scrollTop = maxScrollTop; + } + animationSvc.animate(scrollerElt) + .scrollTop(scrollTop) + .duration(360) + .start(); + }, + + /** + * Apply the template to the file content + */ + // applyTemplate({ state, commit, dispatch, rootState }, template) { + // function groupToc(array, level = 1) { + // const result = []; + // let currentItem; + + // function pushCurrentItem() { + // if (currentItem) { + // if (currentItem.children.length > 0) { + // currentItem.children = groupToc(currentItem.children, level + 1); + // } + // result.push(currentItem); + // } + // } + // array.forEach((item) => { + // if (item.level !== level) { + // currentItem = currentItem || { + // children: [], + // }; + // currentItem.children.push(item); + // } else { + // pushCurrentItem(); + // currentItem = item; + // } + // }); + // pushCurrentItem(); + // return result; + // } + + // let toc = []; + // state.sectionDescList.cl_each((sectionDesc) => { + // if (sectionDesc.heading) { + // toc.push({ + // title: sectionDesc.heading.title, + // level: sectionDesc.heading.level, + // anchor: sectionDesc.heading.anchor, + // children: [], + // }); + // } + // }); + // toc = groupToc(toc); + + // const view = { + // file: { + // name: rootState.files.currentFile.name, + // content: { + // properties: rootState.files.currentFile.content.properties, + // text: rootState.files.currentFile.content.text, + // html: state.previewHtml, + // toc, + // }, + // }, + // }; + // const worker = new window.Worker(clVersion.getAssetPath('templateWorker-min.js')); + // worker.postMessage([template, view, clSettingSvc.values.handlebarsHelpers]); + // return new Promise((resolve, reject) => { + // worker.addEventListener('message', (e) => { + // resolve(e.data.toString()); + // }); + // setTimeout(() => { + // worker.terminate(); + // reject('Template generation timeout.'); + // }, 10000); + // }); + // }, + + /** + * Pass the elements to the store and initialize the editor. + */ + init(editorElt, previewElt, tocElt) { + this.editorElt = editorElt; + this.previewElt = previewElt; + this.tocElt = tocElt; + + editorEngineSvc.createClEditor(editorElt); + editorEngineSvc.clEditor.toggleEditable(false); + editorEngineSvc.clEditor.on('contentChanged', (content, diffs, sectionList) => { + const parsingCtx = { + ...this.parsingCtx, + sectionList, + }; + this.parsingCtx = parsingCtx; + }); + this.pagedownEditor = pagedown({ + input: Object.create(editorEngineSvc.clEditor), + }); + this.pagedownEditor.run(); + this.editorElt.addEventListener('focus', () => { + // if (clEditorLayoutSvc.currentControl === 'menu') { + // clEditorLayoutSvc.currentControl = undefined + // } + }); + // state.pagedownEditor.hooks.set('insertLinkDialog', (callback) => { + // clEditorSvc.linkDialogCallback = callback + // clEditorLayoutSvc.currentControl = 'linkDialog' + // scope.$evalAsync() + // return true + // }) + // state.pagedownEditor.hooks.set('insertImageDialog', (callback) => { + // clEditorSvc.imageDialogCallback = callback + // clEditorLayoutSvc.currentControl = 'imageDialog' + // scope.$evalAsync() + // return true + // }) + + this.editorElt.addEventListener('scroll', () => this.saveContentState(true)); + + const refreshPreview = () => { + this.convert(); + if (!isPreviewRefreshed) { + this.refreshPreview(); + this.measureSectionDimensions(); + this.restoreScrollPosition(); + } else { + setTimeout(() => this.refreshPreview(), 10); + } + isPreviewRefreshed = true; + }; + + const debouncedRefreshPreview = debounce(refreshPreview, 20); + + let newSectionList; + let newSelectionRange; + const debouncedEditorChanged = debounce(() => { + if (this.sectionList !== newSectionList) { + this.sectionList = newSectionList; + this.$emit('sectionList', this.sectionList); + if (isPreviewRefreshed) { + debouncedRefreshPreview(); + } else { + refreshPreview(); + } + } + if (this.selectionRange !== newSelectionRange) { + this.selectionRange = newSelectionRange; + this.$emit('selectionRange', this.selectionRange); + } + this.saveContentState(); + }, 10); + + editorEngineSvc.clEditor.selectionMgr.on('selectionChanged', (start, end, selectionRange) => { + newSelectionRange = selectionRange; + debouncedEditorChanged(); + }); + + /* ----------------------------- + * Inline images + */ + + const imgCache = Object.create(null); + + const addToImgCache = (imgElt) => { + let entries = imgCache[imgElt.src]; + if (!entries) { + entries = []; + imgCache[imgElt.src] = entries; + } + entries.push(imgElt); + }; + + const getFromImgCache = (src) => { + const entries = imgCache[src]; + if (!entries) { + return null; + } + let imgElt; + return entries + .some((entry) => { + if (this.editorElt.contains(entry)) { + return false; + } + imgElt = entry; + return true; + }) && imgElt; + }; + + const triggerImgCacheGc = debounce(() => { + Object.keys(imgCache).forEach((src) => { + const entries = imgCache[src] + .filter(imgElt => this.editorElt.contains(imgElt)); + if (entries.length) { + imgCache[src] = entries; + } else { + delete imgCache[src]; + } + }); + }, 100); + + let imgEltsToCache = []; + if (store.state.editor.inlineImages) { + editorEngineSvc.clEditor.highlighter.on('sectionHighlighted', (section) => { + section.elt.getElementsByClassName('token img').cl_each((imgTokenElt) => { + const srcElt = imgTokenElt.querySelector('.token.cl-src'); + if (srcElt) { + // Create an img element before the .img.token and wrap both elements + // into a .token.img-wrapper + const imgElt = document.createElement('img'); + imgElt.style.display = 'none'; + const uri = srcElt.textContent; + if (!/^unsafe/.test(htmlSanitizer.sanitizeUri(uri, true))) { + imgElt.onload = () => { + imgElt.style.display = ''; + }; + imgElt.src = uri; + imgEltsToCache.push(imgElt); + } + const imgTokenWrapper = document.createElement('span'); + imgTokenWrapper.className = 'token img-wrapper'; + imgTokenElt.parentNode.insertBefore(imgTokenWrapper, imgTokenElt); + imgTokenWrapper.appendChild(imgElt); + imgTokenWrapper.appendChild(imgTokenElt); + } + }); + }); + } + + editorEngineSvc.clEditor.highlighter.on('highlighted', () => { + imgEltsToCache.forEach((imgElt) => { + const cachedImgElt = getFromImgCache(imgElt.src); + if (cachedImgElt) { + // Found a previously loaded image that has just been released + imgElt.parentNode.replaceChild(cachedImgElt, imgElt); + } else { + addToImgCache(imgElt); + } + }); + imgEltsToCache = []; + // Eject released images from cache + triggerImgCacheGc(); + }); + + editorEngineSvc.clEditor.on('contentChanged', (content, diffs, sectionList) => { + newSectionList = sectionList; + debouncedEditorChanged(); + }); + + // scope.$watch('editorLayoutSvc.isEditorOpen', function (isOpen) { + // clEditorSvc.cledit.toggleEditable(isOpen) + // }) + + // scope.$watch('editorLayoutSvc.currentControl', function (currentControl) { + // !currentControl && setTimeout(function () { + // !scope.isDialogOpen && clEditorSvc.cledit && clEditorSvc.cledit.focus() + // }, 1) + // }) + + // clEditorSvc.setPreviewElt(element[0].querySelector('.preview__inner')) + // var previewElt = element[0].querySelector('.preview') + // clEditorSvc.isPreviewTop = previewElt.scrollTop < 10 + // previewElt.addEventListener('scroll', function () { + // var isPreviewTop = previewElt.scrollTop < 10 + // if (isPreviewTop !== clEditorSvc.isPreviewTop) { + // clEditorSvc.isPreviewTop = isPreviewTop + // scope.$apply() + // } + // }) + + store.watch( + state => state.files.currentFile.content.properties, + (properties) => { + const options = properties && extensionSvc.getOptions(properties, true); + if (JSON.stringify(options) !== JSON.stringify(editorSvc.options)) { + editorSvc.options = options; + editorSvc.initPrism(); + editorSvc.initConverter(); + editorSvc.initClEditor(); + } + }, { + immediate: true, + }); + + store.watch(state => `${state.layout.editorWidth},${state.layout.previewWidth}`, + () => editorSvc.measureSectionDimensions(true)); + store.watch(state => state.layout.showSidePreview, + showSidePreview => showSidePreview && editorSvc.measureSectionDimensions()); + + this.$emit('inited'); + }, +}); + +export default editorSvc; diff --git a/src/services/extensionSvc.js b/src/services/extensionSvc.js new file mode 100644 index 00000000..5fad6d2b --- /dev/null +++ b/src/services/extensionSvc.js @@ -0,0 +1,46 @@ +const getOptionsListeners = []; +const initConverterListeners = []; +const sectionPreviewListeners = []; +const asyncPreviewListeners = []; + +export default { + onGetOptions(listener) { + getOptionsListeners.push(listener); + }, + + onInitConverter(priority, listener) { + initConverterListeners[priority] = listener; + }, + + onSectionPreview(listener) { + sectionPreviewListeners.push(listener); + }, + + onAsyncPreview(listener) { + asyncPreviewListeners.push(listener); + }, + + getOptions(properties, isCurrentFile) { + return getOptionsListeners.reduce((options, listener) => { + listener(options, properties, isCurrentFile); + return options; + }, {}); + }, + + initConverter(markdown, options, isCurrentFile) { + // Use forEach as it's a sparsed array + initConverterListeners.forEach((listener) => { + listener(markdown, options, isCurrentFile); + }); + }, + + sectionPreview(elt, options) { + sectionPreviewListeners.forEach((listener) => { + listener(elt, options); + }); + }, + + asyncPreview(options) { + return Promise.all(asyncPreviewListeners.map(listener => listener(options))); + }, +}; diff --git a/src/services/markdownConversionSvc.js b/src/services/markdownConversionSvc.js new file mode 100644 index 00000000..c26a7da5 --- /dev/null +++ b/src/services/markdownConversionSvc.js @@ -0,0 +1,262 @@ +import DiffMatchPatch from 'diff-match-patch'; +import Prism from 'prismjs'; +import MarkdownIt from 'markdown-it'; +import markdownGrammarSvc from './markdownGrammarSvc'; +import extensionSvc from './extensionSvc'; + +const htmlSectionMarker = '\uF111\uF222\uF333\uF444'; +const diffMatchPatch = new DiffMatchPatch(); + +// Create aliases for syntax highlighting +const languageAliases = ({ + js: 'javascript', + json: 'javascript', + html: 'markup', + svg: 'markup', + xml: 'markup', + py: 'python', + rb: 'ruby', + ps1: 'powershell', + psm1: 'powershell', +}); +Object.keys(languageAliases).forEach((alias) => { + const language = languageAliases[alias]; + Prism.languages[alias] = Prism.languages[language]; +}); + +// Add language parsing capability to markdown fences +const insideFences = {}; +Object.keys(Prism.languages).forEach((name) => { + const language = Prism.languages[name]; + if (Prism.util.type(language) === 'Object') { + insideFences[`language-${name}`] = { + pattern: new RegExp(`(\`\`\`|~~~)${name}\\W[\\s\\S]*`), + inside: { + 'cl cl-pre': /(```|~~~).*/, + rest: language, + }, + }; + } +}); + +// Disable spell checking in specific tokens +const noSpellcheckTokens = Object.create(null); +[ + 'code', + 'pre', + 'pre gfm', + 'math block', + 'math inline', + 'math expr block', + 'math expr inline', + 'latex block', +] + .forEach((key) => { + noSpellcheckTokens[key] = true; + }); +Prism.hooks.add('wrap', (env) => { + if (noSpellcheckTokens[env.type]) { + env.attributes.spellcheck = 'false'; + } +}); + +function createFlagMap(arr) { + return arr.reduce((map, type) => ({ ...map, [type]: true }), {}); +} +const startSectionBlockTypeMap = createFlagMap([ + 'paragraph_open', + 'blockquote_open', + 'heading_open', + 'code', + 'fence', + 'table_open', + 'html_block', + 'bullet_list_open', + 'ordered_list_open', + 'hr', + 'dl_open', +]); +const listBlockTypeMap = createFlagMap([ + 'bullet_list_open', + 'ordered_list_open', +]); +const blockquoteBlockTypeMap = createFlagMap([ + 'blockquote_open', +]); +const tableBlockTypeMap = createFlagMap([ + 'table_open', +]); +const deflistBlockTypeMap = createFlagMap([ + 'dl_open', +]); + +function hashArray(arr, valueHash, valueArray) { + const hash = []; + arr.cl_each((str) => { + let strHash = valueHash[str]; + if (strHash === undefined) { + strHash = valueArray.length; + valueArray.push(str); + valueHash[str] = strHash; + } + hash.push(strHash); + }); + return String.fromCharCode.apply(null, hash); +} + +// Default options for the markdown converter and the grammar +const defaultOptions = { + abbr: true, + breaks: true, + deflist: true, + del: true, + fence: true, + footnote: true, + linkify: true, + math: true, + sub: true, + sup: true, + table: true, + typographer: true, + insideFences, +}; + +const markdownConversionSvc = { + defaultOptions, + + /** + * Creates a converter and init it with extensions. + * @returns {Object} A converter. + */ + createConverter(options, isCurrentFile) { + // Let the listeners add the rules + const converter = new MarkdownIt('zero'); + converter.core.ruler.enable([], true); + converter.block.ruler.enable([], true); + converter.inline.ruler.enable([], true); + extensionSvc.initConverter(converter, options, isCurrentFile); + Object.keys(startSectionBlockTypeMap).forEach((type) => { + const rule = converter.renderer.rules[type] === true || converter.renderer.renderToken; + converter.renderer.rules[type] = (tokens, idx, opts) => { + if (tokens[idx].sectionDelimiter) { + // Add section delimiter + return htmlSectionMarker + rule.call(converter.renderer, tokens, idx, opts); + } + return rule.call(converter.renderer, tokens, idx, opts); + }; + }); + return converter; + }, + + /** + * Parse markdown sections by passing the 2 first block rules of the markdown-it converter. + * @param {Object} converter The markdown-it converter. + * @param {String} text The text to be parsed. + * @returns {Object} A parsing context to be passed to `convert`. + */ + parseSections(converter, text) { + const markdownState = new converter.core.State(text, converter, {}); + const markdownCoreRules = converter.core.ruler.getRules(''); + markdownCoreRules[0](markdownState); // Pass the normalize rule + markdownCoreRules[1](markdownState); // Pass the block rule + const lines = text.split('\n'); + if (!lines[lines.length - 1]) { + // In cledit, last char is always '\n'. + // Remove it as one will be added by addSection + lines.pop(); + } + const parsingCtx = { + sections: [], + converter, + markdownState, + markdownCoreRules, + }; + let data = 'main'; + let i = 0; + + function addSection(maxLine) { + const section = { + text: '', + data, + }; + for (; i < maxLine; i += 1) { + section.text += `${lines[i]}\n`; + } + if (section) { + parsingCtx.sections.push(section); + } + } + markdownState.tokens.forEach((token, index) => { + // index === 0 means there are empty lines at the begining of the file + if (token.level === 0 && startSectionBlockTypeMap[token.type] === true) { + if (index > 0) { + token.sectionDelimiter = true; + addSection(token.map[0]); + } + if (listBlockTypeMap[token.type] === true) { + data = 'list'; + } else if (blockquoteBlockTypeMap[token.type] === true) { + data = 'blockquote'; + } else if (tableBlockTypeMap[token.type] === true) { + data = 'table'; + } else if (deflistBlockTypeMap[token.type] === true) { + data = 'deflist'; + } else { + data = 'main'; + } + } + }); + addSection(lines.length); + return parsingCtx; + }, + + /** + * Convert markdown sections previously parsed with `parseSections`. + * @param {Object} parsingCtx The parsing context returned by `parseSections`. + * @param {Object} previousConversionCtx The conversion context returned by a previous call + * to `convert`, in order to calculate the `htmlSectionDiff` of the returned conversion context. + * @returns {Object} A conversion context. + */ + convert(parsingCtx, previousConversionCtx) { + // This function can be called twice without editor modification + // so prevent from converting it again. + if (!parsingCtx.markdownState.isConverted) { + // Skip 2 first rules previously passed in parseSections + parsingCtx.markdownCoreRules.slice(2).forEach(rule => rule(parsingCtx.markdownState)); + parsingCtx.markdownState.isConverted = true; + } + const tokens = parsingCtx.markdownState.tokens; + const html = parsingCtx.converter.renderer.render( + tokens, + parsingCtx.converter.options, + parsingCtx.markdownState.env, + ); + const htmlSectionList = html.split(htmlSectionMarker); + if (htmlSectionList[0] === '') { + htmlSectionList.shift(); + } + const valueHash = Object.create(null); + const valueArray = []; + const newSectionHash = hashArray(htmlSectionList, valueHash, valueArray); + let htmlSectionDiff; + if (previousConversionCtx) { + const oldSectionHash = hashArray( + previousConversionCtx.htmlSectionList, valueHash, valueArray); + htmlSectionDiff = diffMatchPatch.diff_main(oldSectionHash, newSectionHash, false); + } else { + htmlSectionDiff = [ + [1, newSectionHash], + ]; + } + return { + sectionList: parsingCtx.sectionList, + htmlSectionList, + htmlSectionDiff, + }; + }, +}; + +markdownConversionSvc.defaultConverter = markdownConversionSvc.createConverter(defaultOptions); +markdownConversionSvc.defaultPrismGrammars = markdownGrammarSvc.makeGrammars(defaultOptions); + +export default markdownConversionSvc; diff --git a/src/services/markdownGrammarSvc.js b/src/services/markdownGrammarSvc.js new file mode 100644 index 00000000..9d89ddab --- /dev/null +++ b/src/services/markdownGrammarSvc.js @@ -0,0 +1,414 @@ +const charInsideUrl = '(&|[-A-Z0-9+@#/%?=~_|[\\]()!:,.;])'; +const charEndingUrl = '(&|[-A-Z0-9+@#/%=~_|[\\])])'; +const urlPattern = new RegExp(`(https?|ftp)(://${charInsideUrl}*${charEndingUrl})(?=$|\\W)`, 'gi'); +const emailPattern = /(?:mailto:)?([-.\w]+@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)/gi; + +const markup = { + comment: //g, + tag: { + pattern: /<\/?[\w:-]+\s*(?:\s+[\w:-]+(?:=(?:("|')(\\?[\w\W])*?\1|[^\s'">=]+))?\s*)*\/?>/gi, + inside: { + tag: { + pattern: /^<\/?[\w:-]+/i, + inside: { + punctuation: /^<\/?/, + namespace: /^[\w-]+?:/, + }, + }, + 'attr-value': { + pattern: /=(?:('|")[\w\W]*?(\1)|[^\s>]+)/gi, + inside: { + punctuation: /=|>|"/g, + }, + }, + punctuation: /\/?>/g, + 'attr-name': { + pattern: /[\w:-]+/g, + inside: { + namespace: /^[\w-]+?:/, + }, + }, + }, + }, + entity: /&#?[\da-z]{1,8};/gi, +}; + +const latex = { + // A tex command e.g. \foo + keyword: /\\(?:[^a-zA-Z]|[a-zA-Z]+)/g, + // Curly and square braces + lparen: /[[({]/g, + // Curly and square braces + rparen: /[\])}]/g, + // A comment. Tex comments start with % and go to + // the end of the line + comment: /%.*/g, +}; + +export default { + makeGrammars(options) { + const grammars = { + main: {}, + list: {}, + blockquote: {}, + table: {}, + deflist: {}, + }; + + grammars.deflist.deflist = { + pattern: new RegExp( + [ + '^ {0,3}\\S.*\\n', // Description line + '(?:[ \\t]*\\n)?', // Optional empty line + '(?:', + '[ \\t]*:[ \\t].*\\n', // Colon line + '(?:', + '(?:', + '.*\\S.*\\n', // Non-empty line + '|', + '[ \\t]*\\n(?! ?\\S)', // Or empty line not followed by unindented line + ')', + ')*', + '(?:[ \\t]*\\n)*', // Empty lines + ')+', + ].join(''), + 'm', + ), + inside: { + term: /^.+/, + cl: /^[ \t]*:[ \t]/gm, + }, + }; + + const insideFences = options.insideFences || {}; + insideFences['cl cl-pre'] = /```|~~~/; + if (options.fence) { + grammars.main['pre gfm'] = { + pattern: /^(```|~~~)[\s\S]*?\n\1 *$/gm, + inside: insideFences, + }; + grammars.list['pre gfm'] = { + pattern: /^(?: {4}|\t)(```|~~~)[\s\S]*?\n(?: {4}|\t)\1\s*$/gm, + inside: insideFences, + }; + grammars.deflist.deflist.inside['pre gfm'] = grammars.list['pre gfm']; + } + + grammars.main['h1 alt'] = { + pattern: /^.+\n=+[ \t]*$/gm, + inside: { + 'cl cl-hash': /=+[ \t]*$/, + }, + }; + grammars.main['h2 alt'] = { + pattern: /^.+\n-+[ \t]*$/gm, + inside: { + 'cl cl-hash': /-+[ \t]*$/, + }, + }; + for (let i = 6; i >= 1; i -= 1) { + grammars.main[`h${i}`] = { + pattern: new RegExp(`^#{${i}}[ \t].+$`, 'gm'), + inside: { + 'cl cl-hash': new RegExp(`^#{${i}}`), + }, + }; + } + + const list = /^[ \t]*([*+-]|\d+\.)[ \t]/gm; + const blockquote = { + pattern: /^\s*>.*(?:\n[ \t]*\S.*)*/gm, + inside: { + 'cl cl-gt': /^\s*>/gm, + 'cl cl-li': list, + }, + }; + grammars.list.blockquote = blockquote; + grammars.blockquote.blockquote = blockquote; + grammars.deflist.deflist.inside.blockquote = blockquote; + grammars.list['cl cl-li'] = list; + grammars.blockquote['cl cl-li'] = list; + grammars.deflist.deflist.inside['cl cl-li'] = list; + + grammars.table.table = { + pattern: new RegExp( + [ + '^\\s*\\S.*[|].*\\n', // Header Row + '[-| :]+\\n', // Separator + '(?:.*[|].*\\n?)*', // Table rows + '$', + ].join(''), + 'gm', + ), + inside: { + 'cl cl-title-separator': /^[-| :]+$/gm, + 'cl cl-pipe': /[|]/gm, + }, + }; + + grammars.main.hr = { + pattern: /^ {0,3}([*\-_] *){3,}$/gm, + }; + + const defs = {}; + if (options.footnote) { + defs.fndef = { + pattern: /^ {0,3}\[\^.*?\]:.*$/gm, + inside: { + 'ref-id': { + pattern: /^ {0,3}\[\^.*?\]/, + inside: { + cl: /(\[\^|\])/, + }, + }, + }, + }; + } + if (options.abbr) { + defs.abbrdef = { + pattern: /^ {0,3}\*\[.*?\]:.*$/gm, + inside: { + 'abbr-id': { + pattern: /^ {0,3}\*\[.*?\]/, + inside: { + cl: /(\*\[|\])/, + }, + }, + }, + }; + } + defs.linkdef = { + pattern: /^ {0,3}\[.*?\]:.*$/gm, + inside: { + 'link-id': { + pattern: /^ {0,3}\[.*?\]/, + inside: { + cl: /[[\]]/, + }, + }, + url: urlPattern, + }, + }; + + Object.keys(defs).forEach((name) => { + const def = defs[name]; + grammars.main[name] = def; + grammars.list[name] = def; + grammars.blockquote[name] = def; + grammars.table[name] = def; + grammars.deflist[name] = def; + }); + + grammars.main.pre = { + pattern: /^\s*\n(?: {4}|\t).*\S.*\n((?: {4}|\t).*\n)*/gm, + }; + + const rest = {}; + rest.code = { + pattern: /(`+)[\s\S]*?\1/g, + inside: { + 'cl cl-code': /`/, + }, + }; + if (options.math) { + rest['math block'] = { + pattern: /\\\\\[[\s\S]*?\\\\\]/g, + inside: { + 'cl cl-bracket-start': /^\\\\\[/, + 'cl cl-bracket-end': /\\\\\]$/, + rest: latex, + }, + }; + rest['math inline'] = { + pattern: /\\\\\([\s\S]*?\\\\\)/g, + inside: { + 'cl cl-bracket-start': /^\\\\\(/, + 'cl cl-bracket-end': /\\\\\)$/, + rest: latex, + }, + }; + rest['math expr block'] = { + pattern: /(\$\$)[\s\S]*?\1/g, + inside: { + 'cl cl-bracket-start': /^\$\$/, + 'cl cl-bracket-end': /\$\$$/, + rest: latex, + }, + }; + rest['math expr inline'] = { + pattern: /\$(?!\s)[\s\S]*?\S\$(?!\d)/g, + inside: { + 'cl cl-bracket-start': /^\$/, + 'cl cl-bracket-end': /\$$/, + rest: latex, + }, + }; + rest['latex block'] = { + pattern: /\\begin\{([a-z]*\*?)\}[\s\S]*?\\?\\end\{\1\}/g, + inside: { + keyword: /\\(begin|end)/, + rest: latex, + }, + }; + } + if (options.footnote) { + rest.inlinefn = { + pattern: /\^\[.+?\]/g, + inside: { + cl: /(\^\[|\])/, + }, + }; + rest.fn = { + pattern: /\[\^.+?\]/g, + inside: { + cl: /(\[\^|\])/, + }, + }; + } + rest.img = { + pattern: /!\[.*?\]\(.+?\)/g, + inside: { + 'cl cl-title': /['‘][^'’]*['’]|["“][^"”]*["”](?=\)$)/, + 'cl cl-src': { + pattern: /(\]\()[^('" \t]+(?=[)'" \t])/, + lookbehind: true, + }, + }, + }; + rest.link = { + pattern: /\[.*?\]\(.+?\)/gm, + inside: { + 'cl cl-underlined-text': { + pattern: /(\[)[^\]]*/, + lookbehind: true, + }, + 'cl cl-title': /['‘][^'’]*['’]|["“][^"”]*["”](?=\)$)/, + }, + }; + rest.imgref = { + pattern: /!\[.*?\][ \t]*\[.*?\]/g, + }; + rest.linkref = { + pattern: /\[.*?\][ \t]*\[.*?\]/g, + inside: { + 'cl cl-underlined-text': { + pattern: /^(\[)[^\]]*(?=\][ \t]*\[)/, + lookbehind: true, + }, + }, + }; + rest.comment = markup.comment; + rest.tag = markup.tag; + rest.url = urlPattern; + rest.email = emailPattern; + rest.strong = { + pattern: /(^|[^\w*])(__|\*\*)(?![_*])[\s\S]*?\2(?=([^\w*]|$))/gm, + lookbehind: true, + inside: { + 'cl cl-strong cl-start': /^(__|\*\*)/, + 'cl cl-strong cl-close': /(__|\*\*)$/, + }, + }; + rest.em = { + pattern: /(^|[^\w*])(_|\*)(?![_*])[\s\S]*?\2(?=([^\w*]|$))/gm, + lookbehind: true, + inside: { + 'cl cl-em cl-start': /^(_|\*)/, + 'cl cl-em cl-close': /(_|\*)$/, + }, + }; + rest['strong em'] = { + pattern: /(^|[^\w*])(__|\*\*)(_|\*)(?![_*])[\s\S]*?\3\2(?=([^\w*]|$))/gm, + lookbehind: true, + inside: { + 'cl cl-strong cl-start': /^(__|\*\*)(_|\*)/, + 'cl cl-strong cl-close': /(_|\*)(__|\*\*)$/, + }, + }; + rest['strong em inv'] = { + pattern: /(^|[^\w*])(_|\*)(__|\*\*)(?![_*])[\s\S]*?\3\2(?=([^\w*]|$))/gm, + lookbehind: true, + inside: { + 'cl cl-strong cl-start': /^(_|\*)(__|\*\*)/, + 'cl cl-strong cl-close': /(__|\*\*)(_|\*)$/, + }, + }; + if (options.del) { + rest.del = { + pattern: /(^|[^\w*])(~~)[\s\S]*?\2(?=([^\w*]|$))/gm, + lookbehind: true, + inside: { + cl: /~~/, + 'cl-del-text': /[^~]+/, + }, + }; + } + if (options.sub) { + rest.sub = { + pattern: /(~)(?=\S)(.*?\S)\1/gm, + inside: { + cl: /~/, + }, + }; + } + if (options.sup) { + rest.sup = { + pattern: /(\^)(?=\S)(.*?\S)\1/gm, + inside: { + cl: /\^/, + }, + }; + } + rest.entity = markup.entity; + + for (let c = 6; c >= 1; c -= 1) { + grammars.main[`h${c}`].inside.rest = rest; + } + grammars.main['h1 alt'].inside.rest = rest; + grammars.main['h2 alt'].inside.rest = rest; + grammars.table.table.inside.rest = rest; + grammars.main.rest = rest; + grammars.list.rest = rest; + grammars.blockquote.blockquote.inside.rest = rest; + grammars.deflist.deflist.inside.rest = rest; + if (options.footnote) { + grammars.main.fndef.inside.rest = rest; + } + + const restLight = { + code: rest.code, + inlinefn: rest.inlinefn, + fn: rest.fn, + link: rest.link, + linkref: rest.linkref, + }; + rest.strong.inside.rest = restLight; + rest.em.inside.rest = restLight; + if (options.del) { + rest.del.inside.rest = restLight; + } + + const inside = { + code: rest.code, + comment: rest.comment, + tag: rest.tag, + strong: rest.strong, + em: rest.em, + del: rest.del, + sub: rest.sub, + sup: rest.sup, + entity: markup.entity, + }; + rest.link.inside['cl cl-underlined-text'].inside = inside; + rest.linkref.inside['cl cl-underlined-text'].inside = inside; + + // Wrap any other characters to allow paragraph folding + Object.keys(grammars).forEach((key) => { + const grammar = grammars[key]; + grammar.rest = grammar.rest || {}; + grammar.rest.p = /.+/; + }); + + return grammars; + }, +}; diff --git a/src/services/optional/index.js b/src/services/optional/index.js new file mode 100644 index 00000000..e1e5094c --- /dev/null +++ b/src/services/optional/index.js @@ -0,0 +1 @@ +import './scrollSync'; diff --git a/src/services/optional/scrollSync.js b/src/services/optional/scrollSync.js new file mode 100644 index 00000000..e82c6f7c --- /dev/null +++ b/src/services/optional/scrollSync.js @@ -0,0 +1,185 @@ +import store from '../../store'; +import constants from '../constants'; +import animationSvc from '../animationSvc'; +import editorSvc from '../editorSvc'; + +let editorScrollerElt; +let previewScrollerElt; +let previewElt; +let editorFinishTimeoutId; +let previewFinishTimeoutId; +let skipAnimation; +let isScrollEditor; +let isScrollPreview; +let isEditorMoving; +let isPreviewMoving; +let sectionDescList; + +let throttleTimeoutId; +let throttleLastTime = 0; + +function throttle(func, wait) { + clearTimeout(throttleTimeoutId); + const currentTime = Date.now(); + const localWait = (wait + throttleLastTime) - currentTime; + if (localWait < 1) { + throttleLastTime = currentTime; + func(); + } else { + throttleTimeoutId = setTimeout(() => { + throttleLastTime = Date.now(); + func(); + }, localWait); + } +} + +const doScrollSync = () => { + const localSkipAnimation = skipAnimation + || !store.state.layout.showSidePreview + || !store.state.layout.showEditor; + skipAnimation = false; + if (!store.state.editor.scrollSync || !sectionDescList || sectionDescList.length === 0) { + return; + } + let editorScrollTop = editorScrollerElt.scrollTop; + if (editorScrollTop < 0) { + editorScrollTop = 0; + } + let previewScrollTop = previewScrollerElt.scrollTop; + let scrollTo; + if (isScrollEditor) { + // Scroll the preview + isScrollEditor = false; + editorScrollTop += constants.scrollOffset; + sectionDescList.some((sectionDesc) => { + if (editorScrollTop > sectionDesc.editorDimension.endOffset) { + return false; + } + const posInSection = (editorScrollTop - sectionDesc.editorDimension.startOffset) + / (sectionDesc.editorDimension.height || 1); + scrollTo = (sectionDesc.previewDimension.startOffset + + (sectionDesc.previewDimension.height * posInSection)) - constants.scrollOffset; + return true; + }); + scrollTo = Math.min( + scrollTo, + previewScrollerElt.scrollHeight - previewScrollerElt.offsetHeight, + ); + + throttle(() => { + clearTimeout(previewFinishTimeoutId); + animationSvc.animate(previewScrollerElt) + .scrollTop(scrollTo) + .duration(!localSkipAnimation && 100) + .start(() => { + previewFinishTimeoutId = setTimeout(() => { + isPreviewMoving = false; + }, 100); + }, () => { + isPreviewMoving = true; + }); + }, localSkipAnimation ? 500 : 10); + } else if (!store.state.layout.showEditor || isScrollPreview) { + // Scroll the editor + isScrollPreview = false; + previewScrollTop += constants.scrollOffset; + sectionDescList.some((sectionDesc) => { + if (previewScrollTop > sectionDesc.previewDimension.endOffset) { + return false; + } + const posInSection = (previewScrollTop - sectionDesc.previewDimension.startOffset) + / (sectionDesc.previewDimension.height || 1); + scrollTo = (sectionDesc.editorDimension.startOffset + + (sectionDesc.editorDimension.height * posInSection)) - constants.scrollOffset; + return true; + }); + scrollTo = Math.min( + scrollTo, + editorScrollerElt.scrollHeight - editorScrollerElt.offsetHeight, + ); + + throttle(() => { + clearTimeout(editorFinishTimeoutId); + animationSvc.animate(editorScrollerElt) + .scrollTop(scrollTo) + .duration(!localSkipAnimation && 100) + .start(() => { + editorFinishTimeoutId = setTimeout(() => { + isEditorMoving = false; + }, 100); + }, () => { + isEditorMoving = true; + }); + }, localSkipAnimation ? 500 : 10); + } +}; + +let isPreviewRefreshing; +let timeoutId; + +const forceScrollSync = () => { + if (!isPreviewRefreshing) { + doScrollSync(!store.state.layout.showSidePreview); + } +}; +store.watch(state => state.editor.scrollSync, forceScrollSync); + +editorSvc.$on('inited', () => { + editorScrollerElt = editorSvc.editorElt.parentNode; + previewScrollerElt = editorSvc.previewElt.parentNode; + previewElt = editorSvc.previewElt; + + editorScrollerElt.addEventListener('scroll', () => { + if (isEditorMoving) { + return; + } + isScrollEditor = true; + isScrollPreview = false; + doScrollSync(!store.state.layout.showSidePreview); + }); + + previewScrollerElt.addEventListener('scroll', () => { + if (isPreviewMoving || isPreviewRefreshing) { + return; + } + isScrollPreview = true; + isScrollEditor = false; + doScrollSync(!store.state.layout.showSidePreview); + }); +}); + +editorSvc.$on('sectionList', () => { + clearTimeout(timeoutId); + isPreviewRefreshing = true; + sectionDescList = undefined; +}); + +editorSvc.$on('conversionCtx', () => { + // Set the preview height to prevent scrollbar from jumping + previewElt.style.height = `${previewElt.offsetHeight}px`; +}); + +editorSvc.$on('previewText', () => { + // Remove height property once the preview as been refreshed + previewElt.style.removeProperty('height'); + // Assume the user is writing in the editor + isScrollEditor = store.state.layout.showEditor; + // A preview scrolling event can occur if height is smaller + timeoutId = setTimeout(() => { + isPreviewRefreshing = false; + }, 100); +}); + +store.watch(state => state.layout.showSidePreview, + (showSidePreview) => { + if (showSidePreview) { + isScrollEditor = true; + isScrollPreview = false; + skipAnimation = true; + } + }); + +editorSvc.$on('sectionDescMeasuredList', (sectionDescMeasuredList) => { + sectionDescList = sectionDescMeasuredList; + forceScrollSync(); +}); diff --git a/src/services/sectionUtils.js b/src/services/sectionUtils.js new file mode 100644 index 00000000..aa3253d2 --- /dev/null +++ b/src/services/sectionUtils.js @@ -0,0 +1,104 @@ +function SectionDimension(startOffset, endOffset) { + this.startOffset = startOffset; + this.endOffset = endOffset; + this.height = endOffset - startOffset; +} + +function dimensionNormalizer(dimensionName) { + return (editorSvc) => { + const dimensionList = editorSvc.sectionDescList.map(sectionDesc => sectionDesc[dimensionName]); + let dimension; + let i; + let j; + for (i = 0; i < dimensionList.length; i += 1) { + dimension = dimensionList[i]; + if (dimension.height) { + for (j = i + 1; j < dimensionList.length && dimensionList[j].height === 0; j += 1) { + // Loop + } + const normalizeFactor = j - i; + if (normalizeFactor !== 1) { + const normalizedHeight = dimension.height / normalizeFactor; + dimension.height = normalizedHeight; + dimension.endOffset = dimension.startOffset + dimension.height; + for (j = i + 1; j < i + normalizeFactor; j += 1) { + const startOffset = dimension.endOffset; + dimension = dimensionList[j]; + dimension.startOffset = startOffset; + dimension.height = normalizedHeight; + dimension.endOffset = dimension.startOffset + dimension.height; + } + i = j - 1; + } + } + } + }; +} + +const normalizeEditorDimensions = dimensionNormalizer('editorDimension'); +const normalizePreviewDimensions = dimensionNormalizer('previewDimension'); +const normalizeTocDimensions = dimensionNormalizer('tocDimension'); + +function measureSectionDimensions(editorSvc) { + let editorSectionOffset = 0; + let previewSectionOffset = 0; + let tocSectionOffset = 0; + let sectionDesc = editorSvc.sectionDescList[0]; + let nextSectionDesc; + let i = 1; + for (; i < editorSvc.sectionDescList.length; i += 1) { + nextSectionDesc = editorSvc.sectionDescList[i]; + + // Measure editor section + let newEditorSectionOffset = nextSectionDesc.editorElt + ? nextSectionDesc.editorElt.offsetTop + : editorSectionOffset; + newEditorSectionOffset = newEditorSectionOffset > editorSectionOffset + ? newEditorSectionOffset + : editorSectionOffset; + sectionDesc.editorDimension = new SectionDimension(editorSectionOffset, newEditorSectionOffset); + editorSectionOffset = newEditorSectionOffset; + + // Measure preview section + let newPreviewSectionOffset = nextSectionDesc.previewElt + ? nextSectionDesc.previewElt.offsetTop + : previewSectionOffset; + newPreviewSectionOffset = newPreviewSectionOffset > previewSectionOffset + ? newPreviewSectionOffset + : previewSectionOffset; + sectionDesc.previewDimension = new SectionDimension( + previewSectionOffset, newPreviewSectionOffset); + previewSectionOffset = newPreviewSectionOffset; + + // Measure TOC section + let newTocSectionOffset = nextSectionDesc.tocElt + ? nextSectionDesc.tocElt.offsetTop + (nextSectionDesc.tocElt.offsetHeight / 2) + : tocSectionOffset; + newTocSectionOffset = newTocSectionOffset > tocSectionOffset + ? newTocSectionOffset + : tocSectionOffset; + sectionDesc.tocDimension = new SectionDimension(tocSectionOffset, newTocSectionOffset); + tocSectionOffset = newTocSectionOffset; + + sectionDesc = nextSectionDesc; + } + + // Last section + sectionDesc = editorSvc.sectionDescList[i - 1]; + if (sectionDesc) { + sectionDesc.editorDimension = new SectionDimension( + editorSectionOffset, editorSvc.editorElt.scrollHeight); + sectionDesc.previewDimension = new SectionDimension( + previewSectionOffset, editorSvc.previewElt.scrollHeight); + sectionDesc.tocDimension = new SectionDimension( + tocSectionOffset, editorSvc.tocElt.scrollHeight); + } + + normalizeEditorDimensions(editorSvc); + normalizePreviewDimensions(editorSvc); + normalizeTocDimensions(editorSvc); +} + +export default { + measureSectionDimensions, +}; diff --git a/src/services/utils.js b/src/services/utils.js new file mode 100644 index 00000000..4b1dd55b --- /dev/null +++ b/src/services/utils.js @@ -0,0 +1,11 @@ +const crypto = window.crypto || window.msCrypto; +const alphabet = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'.split(''); +const radix = alphabet.length; +const array = new Uint32Array(20); + +export default { + uid() { + crypto.getRandomValues(array); + return array.map(value => alphabet[value % radix]).join(''); + }, +}; diff --git a/src/store/index.js b/src/store/index.js new file mode 100644 index 00000000..93497307 --- /dev/null +++ b/src/store/index.js @@ -0,0 +1,22 @@ +import createLogger from 'vuex/dist/logger'; +import Vue from 'vue'; +import Vuex from 'vuex'; +import files from './modules/files'; +import layout from './modules/layout'; +import editor from './modules/editor'; + +Vue.use(Vuex); + +const debug = process.env.NODE_ENV !== 'production'; + +const store = new Vuex.Store({ + modules: { + files, + layout, + editor, + }, + strict: debug, + plugins: debug ? [createLogger()] : [], +}); + +export default store; diff --git a/src/store/modules/editor.js b/src/store/modules/editor.js new file mode 100644 index 00000000..43bfe24b --- /dev/null +++ b/src/store/modules/editor.js @@ -0,0 +1,16 @@ +const setter = propertyName => (state, value) => { + state[propertyName] = value; +}; + +export default { + namespaced: true, + state: { + // Configuration + inlineImages: true, + scrollSync: true, + }, + mutations: { + setInlineImages: setter('inlineImages'), + setScrollSync: setter('scrollSync'), + }, +}; diff --git a/src/store/modules/files.js b/src/store/modules/files.js new file mode 100644 index 00000000..9a259853 --- /dev/null +++ b/src/store/modules/files.js @@ -0,0 +1,31 @@ +import mdSample from '../../markdown/sample.md'; + +export default { + namespaced: true, + state: { + files: [], + currentFile: { + name: null, + folderId: null, + isLoaded: true, + content: { + state: {}, + text: mdSample, + properties: {}, + discussions: {}, + comments: {}, + }, + }, + }, + mutations: { + setCurrentFile: (state, value) => { + state.currentFile = value; + }, + setCurrentFileContentText: (state, value) => { + state.currentFile.content.text = value; + }, + setCurrentFileContentState: (state, value) => { + state.currentFile.content.state = value; + }, + }, +}; diff --git a/src/store/modules/layout.js b/src/store/modules/layout.js new file mode 100644 index 00000000..9587396f --- /dev/null +++ b/src/store/modules/layout.js @@ -0,0 +1,167 @@ +const navigationBarHeight = 44; +const sideBarWidth = 280; +const editorMinWidth = 280; +const buttonBarWidth = 30; +const statusBarHeight = 20; +const outOfScreenMargin = 50; +const minPadding = 20; + +const setter = propertyName => (state, value) => { + state[propertyName] = value; +}; + +const toggler = (propertyName, setterName) => ({ state, commit, dispatch }, show) => { + commit(setterName, show === undefined ? !state[propertyName] : show); + dispatch('updateStyle'); +}; + +export default { + namespaced: true, + state: { + // Configuration + showNavigationBar: true, + showEditor: true, + showSidePreview: true, + showSideBar: false, + showStatusBar: false, + editorWidthFactor: 1, + fontSizeFactor: 1, + // Style + fontSize: 0, + inner1Y: 0, + inner1Height: 0, + inner2Height: 0, + inner3X: 0, + inner3Width: 0, + navigationBarY: 0, + sideBarX: 0, + statusBarY: 0, + editorWidth: 0, + editorPadding: 0, + previewWidth: 0, + previewPadding: 0, + }, + mutations: { + setShowNavigationBar: setter('showNavigationBar'), + setShowEditor: setter('showEditor'), + setShowSidePreview: setter('showSidePreview'), + setShowSideBar: setter('showSideBar'), + setShowStatusBar: setter('showStatusBar'), + setEditorWidthFactor: setter('editorWidthFactor'), + setFontSizeFactor: setter('fontSizeFactor'), + setFontSize: setter('fontSize'), + setInner1Y: setter('inner1Y'), + setInner1Height: setter('inner1Height'), + setInner2Height: setter('inner2Height'), + setInner3X: setter('inner3X'), + setInner3Width: setter('inner3Width'), + setNavigationBarY: setter('navigationBarY'), + setSideBarX: setter('sideBarX'), + setStatusBarY: setter('statusBarY'), + setEditorWidth: setter('editorWidth'), + setEditorPadding: setter('editorPadding'), + setPreviewWidth: setter('previewWidth'), + setPreviewPadding: setter('previewPadding'), + }, + actions: { + toggleNavigationBar: toggler('showNavigationBar', 'setShowNavigationBar'), + toggleEditor: toggler('showEditor', 'setShowEditor'), + toggleSidePreview: toggler('showSidePreview', 'setShowSidePreview'), + toggleSideBar: toggler('showSideBar', 'setShowSideBar'), + toggleStatusBar: toggler('showStatusBar', 'setShowStatusBar'), + updateStyle({ state, commit, dispatch }) { + const bodyWidth = document.body.clientWidth; + const bodyHeight = document.body.clientHeight; + + const showNavigationBar = state.showEditor && state.showNavigationBar; + const inner1Y = showNavigationBar + ? navigationBarHeight + : 0; + const inner1Height = bodyHeight - inner1Y; + const inner2Height = state.showStatusBar + ? inner1Height - statusBarHeight + : inner1Height; + const navigationBarY = showNavigationBar + ? 0 + : -navigationBarHeight - outOfScreenMargin; + const sideBarX = state.showSideBar + ? bodyWidth - sideBarWidth + : bodyWidth + outOfScreenMargin; + const statusBarY = state.showStatusBar + ? inner2Height + : inner2Height + outOfScreenMargin; + + let doublePanelWidth = bodyWidth - buttonBarWidth; + if (state.showSideBar) { + doublePanelWidth -= sideBarWidth; + } + if (doublePanelWidth < editorMinWidth) { + doublePanelWidth = editorMinWidth; + } + const splitPanel = state.showEditor && state.showSidePreview; + if (splitPanel && doublePanelWidth / 2 < editorMinWidth) { + dispatch('toggleSidePreview', false); + return; + } + if (state.showSideBar && bodyWidth < editorMinWidth + sideBarWidth) { + dispatch('toggleSideBar', false); + return; + } + + let fontSize = 18; + let textWidth = 990; + if (doublePanelWidth < 1120) { + fontSize -= 1; + textWidth = 910; + } + if (doublePanelWidth < 1040) { + textWidth = 830; + } + if (textWidth < 640) { + fontSize -= 1; + } + textWidth *= state.editorWidthFactor; + fontSize *= state.fontSizeFactor; + + const panelWidth = doublePanelWidth / 2; + let inner3X = panelWidth; + if (!splitPanel) { + inner3X = state.showEditor + ? doublePanelWidth + : -buttonBarWidth; + } + const inner3Width = splitPanel + ? panelWidth + buttonBarWidth + : doublePanelWidth + buttonBarWidth; + + const previewWidth = splitPanel + ? panelWidth + : bodyWidth; + let previewPadding = (previewWidth - textWidth) / 2; + if (previewPadding < minPadding) { + previewPadding = minPadding; + } + const editorWidth = splitPanel + ? panelWidth + : doublePanelWidth; + let editorPadding = (editorWidth - textWidth) / 2; + if (editorPadding < minPadding) { + editorPadding = minPadding; + } + + commit('setFontSize', fontSize); + commit('setInner1Y', inner1Y); + commit('setInner1Height', inner1Height); + commit('setInner2Height', inner2Height); + commit('setInner3X', inner3X); + commit('setInner3Width', inner3Width); + commit('setNavigationBarY', navigationBarY); + commit('setSideBarX', sideBarX); + commit('setStatusBarY', statusBarY); + commit('setPreviewWidth', previewWidth); + commit('setPreviewPadding', previewPadding); + commit('setEditorWidth', editorWidth); + commit('setEditorPadding', editorPadding); + }, + }, +}; diff --git a/static/.gitkeep b/static/.gitkeep new file mode 100644 index 00000000..e69de29b diff --git a/yarn.lock b/yarn.lock new file mode 100644 index 00000000..f94a90fa --- /dev/null +++ b/yarn.lock @@ -0,0 +1,5622 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +JSONStream@^0.8.4: + version "0.8.4" + resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-0.8.4.tgz#91657dfe6ff857483066132b4618b62e8f4887bd" + dependencies: + jsonparse "0.0.5" + through ">=2.2.7 <3" + +abbrev@1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.0.tgz#d0554c2256636e2f56e7c2e5ad183f859428d81f" + +accepts@~1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.3.tgz#c3ca7434938648c3e0d9c1e328dd68b622c284ca" + dependencies: + mime-types "~2.1.11" + negotiator "0.6.1" + +acorn-dynamic-import@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/acorn-dynamic-import/-/acorn-dynamic-import-2.0.2.tgz#c752bd210bef679501b6c6cb7fc84f8f47158cc4" + dependencies: + acorn "^4.0.3" + +acorn-jsx@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b" + dependencies: + acorn "^3.0.4" + +acorn@^3.0.4: + version "3.3.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a" + +acorn@^4.0.3: + version "4.0.13" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.13.tgz#105495ae5361d697bd195c825192e1ad7f253787" + +acorn@^5.0.0, acorn@^5.0.1, acorn@^5.0.3: + version "5.0.3" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.0.3.tgz#c460df08491463f028ccb82eab3730bf01087b3d" + +ajv-keywords@^1.0.0, ajv-keywords@^1.1.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c" + +ajv@^4.11.2, ajv@^4.7.0, ajv@^4.9.1: + version "4.11.8" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-4.11.8.tgz#82ffb02b29e662ae53bdc20af15947706739c536" + dependencies: + co "^4.6.0" + json-stable-stringify "^1.0.1" + +align-text@^0.1.1, align-text@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117" + dependencies: + kind-of "^3.0.2" + longest "^1.0.1" + repeat-string "^1.5.2" + +alphanum-sort@^1.0.1, alphanum-sort@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3" + +amdefine@>=0.0.4: + version "1.0.1" + resolved "https://registry.yarnpkg.com/amdefine/-/amdefine-1.0.1.tgz#4a5282ac164729e93619bcfd3ad151f817ce91f5" + +ansi-escapes@^1.1.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-1.4.0.tgz#d3a8a83b319aa67793662b13e761c7911422306e" + +ansi-html@0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/ansi-html/-/ansi-html-0.0.7.tgz#813584021962a9e9e6fd039f940d12f56ca7859e" + +ansi-regex@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + +ansi-styles@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-2.2.1.tgz#b432dd3358b634cf75e1e4664368240533c1ddbe" + +anymatch@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-1.3.0.tgz#a3e52fa39168c825ff57b0248126ce5a8ff95507" + dependencies: + arrify "^1.0.0" + micromatch "^2.1.5" + +aproba@^1.0.3: + version "1.1.1" + resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.1.1.tgz#95d3600f07710aa0e9298c726ad5ecf2eacbabab" + +are-we-there-yet@~1.1.2: + version "1.1.4" + resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.4.tgz#bb5dca382bb94f05e15194373d16fd3ba1ca110d" + dependencies: + delegates "^1.0.0" + readable-stream "^2.0.6" + +argparse@^1.0.7: + version "1.0.9" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.9.tgz#73d83bc263f86e97f8cc4f6bae1b0e90a7d22c86" + dependencies: + sprintf-js "~1.0.2" + +arr-diff@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-2.0.0.tgz#8f3b827f955a8bd669697e4a4256ac3ceae356cf" + dependencies: + arr-flatten "^1.0.1" + +arr-flatten@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.0.3.tgz#a274ed85ac08849b6bd7847c4580745dc51adfb1" + +array-differ@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-1.0.0.tgz#eff52e3758249d33be402b8bb8e564bb2b5d4031" + +array-find-index@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" + +array-find@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/array-find/-/array-find-1.0.0.tgz#6c8e286d11ed768327f8e62ecee87353ca3e78b8" + +array-flatten@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" + +array-union@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" + dependencies: + array-uniq "^1.0.1" + +array-uniq@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" + +array-unique@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.2.1.tgz#a1d97ccafcbc2625cc70fadceb36a50c58b01a53" + +arrify@^1.0.0, arrify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" + +asn1.js@^4.0.0: + version "4.9.1" + resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.9.1.tgz#48ba240b45a9280e94748990ba597d216617fd40" + dependencies: + bn.js "^4.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +asn1@~0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.3.tgz#dac8787713c9966849fc8180777ebe9c1ddf3b86" + +assert-plus@1.0.0, assert-plus@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + +assert-plus@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-0.2.0.tgz#d74e1b87e7affc0db8aadb7021f3fe48101ab234" + +assert@^1.1.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/assert/-/assert-1.4.1.tgz#99912d591836b5a6f5b345c0f07eefc08fc65d91" + dependencies: + util "0.10.3" + +async-each@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.1.tgz#19d386a1d9edc6e7c1c85d388aedbcc56d33602d" + +async-foreach@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/async-foreach/-/async-foreach-0.1.3.tgz#36121f845c0578172de419a97dbeb1d16ec34542" + +async@^2.1.2, async@^2.1.5: + version "2.4.1" + resolved "https://registry.yarnpkg.com/async/-/async-2.4.1.tgz#62a56b279c98a11d0987096a01cc3eeb8eb7bbd7" + dependencies: + lodash "^4.14.0" + +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + +autoprefixer@^6.0.0, autoprefixer@^6.3.1, autoprefixer@^6.7.2: + version "6.7.7" + resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-6.7.7.tgz#1dbd1c835658e35ce3f9984099db00585c782014" + dependencies: + browserslist "^1.7.6" + caniuse-db "^1.0.30000634" + normalize-range "^0.1.2" + num2fraction "^1.2.2" + postcss "^5.2.16" + postcss-value-parser "^3.2.3" + +aws-sign2@~0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.6.0.tgz#14342dd38dbcc94d0e5b87d763cd63612c0e794f" + +aws4@^1.2.1: + version "1.6.0" + resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.6.0.tgz#83ef5ca860b2b32e4a0deedee8c771b9db57471e" + +babel-code-frame@^6.11.0, babel-code-frame@^6.16.0, babel-code-frame@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-code-frame/-/babel-code-frame-6.22.0.tgz#027620bee567a88c32561574e7fd0801d33118e4" + dependencies: + chalk "^1.1.0" + esutils "^2.0.2" + js-tokens "^3.0.0" + +babel-core@^6.22.1, babel-core@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-core/-/babel-core-6.24.1.tgz#8c428564dce1e1f41fb337ec34f4c3b022b5ad83" + dependencies: + babel-code-frame "^6.22.0" + babel-generator "^6.24.1" + babel-helpers "^6.24.1" + babel-messages "^6.23.0" + babel-register "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + babylon "^6.11.0" + convert-source-map "^1.1.0" + debug "^2.1.1" + json5 "^0.5.0" + lodash "^4.2.0" + minimatch "^3.0.2" + path-is-absolute "^1.0.0" + private "^0.1.6" + slash "^1.0.0" + source-map "^0.5.0" + +babel-eslint@^7.1.1: + version "7.2.3" + resolved "https://registry.yarnpkg.com/babel-eslint/-/babel-eslint-7.2.3.tgz#b2fe2d80126470f5c19442dc757253a897710827" + dependencies: + babel-code-frame "^6.22.0" + babel-traverse "^6.23.1" + babel-types "^6.23.0" + babylon "^6.17.0" + +babel-generator@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-generator/-/babel-generator-6.24.1.tgz#e715f486c58ded25649d888944d52aa07c5d9497" + dependencies: + babel-messages "^6.23.0" + babel-runtime "^6.22.0" + babel-types "^6.24.1" + detect-indent "^4.0.0" + jsesc "^1.3.0" + lodash "^4.2.0" + source-map "^0.5.0" + trim-right "^1.0.1" + +babel-helper-bindify-decorators@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-bindify-decorators/-/babel-helper-bindify-decorators-6.24.1.tgz#14c19e5f142d7b47f19a52431e52b1ccbc40a330" + dependencies: + babel-runtime "^6.22.0" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-builder-binary-assignment-operator-visitor@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-builder-binary-assignment-operator-visitor/-/babel-helper-builder-binary-assignment-operator-visitor-6.24.1.tgz#cce4517ada356f4220bcae8a02c2b346f9a56664" + dependencies: + babel-helper-explode-assignable-expression "^6.24.1" + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-call-delegate@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-call-delegate/-/babel-helper-call-delegate-6.24.1.tgz#ece6aacddc76e41c3461f88bfc575bd0daa2df8d" + dependencies: + babel-helper-hoist-variables "^6.24.1" + babel-runtime "^6.22.0" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-define-map@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-define-map/-/babel-helper-define-map-6.24.1.tgz#7a9747f258d8947d32d515f6aa1c7bd02204a080" + dependencies: + babel-helper-function-name "^6.24.1" + babel-runtime "^6.22.0" + babel-types "^6.24.1" + lodash "^4.2.0" + +babel-helper-explode-assignable-expression@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-explode-assignable-expression/-/babel-helper-explode-assignable-expression-6.24.1.tgz#f25b82cf7dc10433c55f70592d5746400ac22caa" + dependencies: + babel-runtime "^6.22.0" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-explode-class@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-explode-class/-/babel-helper-explode-class-6.24.1.tgz#7dc2a3910dee007056e1e31d640ced3d54eaa9eb" + dependencies: + babel-helper-bindify-decorators "^6.24.1" + babel-runtime "^6.22.0" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-function-name@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-function-name/-/babel-helper-function-name-6.24.1.tgz#d3475b8c03ed98242a25b48351ab18399d3580a9" + dependencies: + babel-helper-get-function-arity "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-get-function-arity@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-get-function-arity/-/babel-helper-get-function-arity-6.24.1.tgz#8f7782aa93407c41d3aa50908f89b031b1b6853d" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-hoist-variables@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-hoist-variables/-/babel-helper-hoist-variables-6.24.1.tgz#1ecb27689c9d25513eadbc9914a73f5408be7a76" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-optimise-call-expression@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-optimise-call-expression/-/babel-helper-optimise-call-expression-6.24.1.tgz#f7a13427ba9f73f8f4fa993c54a97882d1244257" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-helper-regex@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-regex/-/babel-helper-regex-6.24.1.tgz#d36e22fab1008d79d88648e32116868128456ce8" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + lodash "^4.2.0" + +babel-helper-remap-async-to-generator@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-remap-async-to-generator/-/babel-helper-remap-async-to-generator-6.24.1.tgz#5ec581827ad723fecdd381f1c928390676e4551b" + dependencies: + babel-helper-function-name "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helper-replace-supers@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helper-replace-supers/-/babel-helper-replace-supers-6.24.1.tgz#bf6dbfe43938d17369a213ca8a8bf74b6a90ab1a" + dependencies: + babel-helper-optimise-call-expression "^6.24.1" + babel-messages "^6.23.0" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-helpers@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-helpers/-/babel-helpers-6.24.1.tgz#3471de9caec388e5c850e597e58a26ddf37602b2" + dependencies: + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-loader@^6.2.10: + version "6.4.1" + resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-6.4.1.tgz#0b34112d5b0748a8dcdbf51acf6f9bd42d50b8ca" + dependencies: + find-cache-dir "^0.1.1" + loader-utils "^0.2.16" + mkdirp "^0.5.1" + object-assign "^4.0.1" + +babel-messages@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-messages/-/babel-messages-6.23.0.tgz#f3cdf4703858035b2a2951c6ec5edf6c62f2630e" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-check-es2015-constants@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-check-es2015-constants/-/babel-plugin-check-es2015-constants-6.22.0.tgz#35157b101426fd2ffd3da3f75c7d1e91835bbf8a" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-syntax-async-functions@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-functions/-/babel-plugin-syntax-async-functions-6.13.0.tgz#cad9cad1191b5ad634bf30ae0872391e0647be95" + +babel-plugin-syntax-async-generators@^6.5.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-async-generators/-/babel-plugin-syntax-async-generators-6.13.0.tgz#6bc963ebb16eccbae6b92b596eb7f35c342a8b9a" + +babel-plugin-syntax-class-properties@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-class-properties/-/babel-plugin-syntax-class-properties-6.13.0.tgz#d7eb23b79a317f8543962c505b827c7d6cac27de" + +babel-plugin-syntax-decorators@^6.13.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-decorators/-/babel-plugin-syntax-decorators-6.13.0.tgz#312563b4dbde3cc806cee3e416cceeaddd11ac0b" + +babel-plugin-syntax-dynamic-import@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz#8d6a26229c83745a9982a441051572caa179b1da" + +babel-plugin-syntax-exponentiation-operator@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-exponentiation-operator/-/babel-plugin-syntax-exponentiation-operator-6.13.0.tgz#9ee7e8337290da95288201a6a57f4170317830de" + +babel-plugin-syntax-object-rest-spread@^6.8.0: + version "6.13.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5" + +babel-plugin-syntax-trailing-function-commas@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-trailing-function-commas/-/babel-plugin-syntax-trailing-function-commas-6.22.0.tgz#ba0360937f8d06e40180a43fe0d5616fff532cf3" + +babel-plugin-transform-async-generator-functions@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-generator-functions/-/babel-plugin-transform-async-generator-functions-6.24.1.tgz#f058900145fd3e9907a6ddf28da59f215258a5db" + dependencies: + babel-helper-remap-async-to-generator "^6.24.1" + babel-plugin-syntax-async-generators "^6.5.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-async-to-generator@^6.22.0, babel-plugin-transform-async-to-generator@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-async-to-generator/-/babel-plugin-transform-async-to-generator-6.24.1.tgz#6536e378aff6cb1d5517ac0e40eb3e9fc8d08761" + dependencies: + babel-helper-remap-async-to-generator "^6.24.1" + babel-plugin-syntax-async-functions "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-class-properties@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-class-properties/-/babel-plugin-transform-class-properties-6.24.1.tgz#6a79763ea61d33d36f37b611aa9def81a81b46ac" + dependencies: + babel-helper-function-name "^6.24.1" + babel-plugin-syntax-class-properties "^6.8.0" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-decorators@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-decorators/-/babel-plugin-transform-decorators-6.24.1.tgz#788013d8f8c6b5222bdf7b344390dfd77569e24d" + dependencies: + babel-helper-explode-class "^6.24.1" + babel-plugin-syntax-decorators "^6.13.0" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-arrow-functions@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-arrow-functions/-/babel-plugin-transform-es2015-arrow-functions-6.22.0.tgz#452692cb711d5f79dc7f85e440ce41b9f244d221" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-block-scoped-functions@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoped-functions/-/babel-plugin-transform-es2015-block-scoped-functions-6.22.0.tgz#bbc51b49f964d70cb8d8e0b94e820246ce3a6141" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-block-scoping@^6.23.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-block-scoping/-/babel-plugin-transform-es2015-block-scoping-6.24.1.tgz#76c295dc3a4741b1665adfd3167215dcff32a576" + dependencies: + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + lodash "^4.2.0" + +babel-plugin-transform-es2015-classes@^6.23.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-classes/-/babel-plugin-transform-es2015-classes-6.24.1.tgz#5a4c58a50c9c9461e564b4b2a3bfabc97a2584db" + dependencies: + babel-helper-define-map "^6.24.1" + babel-helper-function-name "^6.24.1" + babel-helper-optimise-call-expression "^6.24.1" + babel-helper-replace-supers "^6.24.1" + babel-messages "^6.23.0" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-computed-properties@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-computed-properties/-/babel-plugin-transform-es2015-computed-properties-6.24.1.tgz#6fe2a8d16895d5634f4cd999b6d3480a308159b3" + dependencies: + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-destructuring@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-destructuring/-/babel-plugin-transform-es2015-destructuring-6.23.0.tgz#997bb1f1ab967f682d2b0876fe358d60e765c56d" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-duplicate-keys@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-duplicate-keys/-/babel-plugin-transform-es2015-duplicate-keys-6.24.1.tgz#73eb3d310ca969e3ef9ec91c53741a6f1576423e" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-for-of@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-for-of/-/babel-plugin-transform-es2015-for-of-6.23.0.tgz#f47c95b2b613df1d3ecc2fdb7573623c75248691" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-function-name@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-function-name/-/babel-plugin-transform-es2015-function-name-6.24.1.tgz#834c89853bc36b1af0f3a4c5dbaa94fd8eacaa8b" + dependencies: + babel-helper-function-name "^6.24.1" + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-literals@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-literals/-/babel-plugin-transform-es2015-literals-6.22.0.tgz#4f54a02d6cd66cf915280019a31d31925377ca2e" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-modules-amd@^6.22.0, babel-plugin-transform-es2015-modules-amd@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-amd/-/babel-plugin-transform-es2015-modules-amd-6.24.1.tgz#3b3e54017239842d6d19c3011c4bd2f00a00d154" + dependencies: + babel-plugin-transform-es2015-modules-commonjs "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-modules-commonjs@^6.23.0, babel-plugin-transform-es2015-modules-commonjs@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-commonjs/-/babel-plugin-transform-es2015-modules-commonjs-6.24.1.tgz#d3e310b40ef664a36622200097c6d440298f2bfe" + dependencies: + babel-plugin-transform-strict-mode "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-modules-systemjs@^6.23.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-systemjs/-/babel-plugin-transform-es2015-modules-systemjs-6.24.1.tgz#ff89a142b9119a906195f5f106ecf305d9407d23" + dependencies: + babel-helper-hoist-variables "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-modules-umd@^6.23.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-modules-umd/-/babel-plugin-transform-es2015-modules-umd-6.24.1.tgz#ac997e6285cd18ed6176adb607d602344ad38468" + dependencies: + babel-plugin-transform-es2015-modules-amd "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + +babel-plugin-transform-es2015-object-super@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-object-super/-/babel-plugin-transform-es2015-object-super-6.24.1.tgz#24cef69ae21cb83a7f8603dad021f572eb278f8d" + dependencies: + babel-helper-replace-supers "^6.24.1" + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-parameters@^6.23.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-parameters/-/babel-plugin-transform-es2015-parameters-6.24.1.tgz#57ac351ab49caf14a97cd13b09f66fdf0a625f2b" + dependencies: + babel-helper-call-delegate "^6.24.1" + babel-helper-get-function-arity "^6.24.1" + babel-runtime "^6.22.0" + babel-template "^6.24.1" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-shorthand-properties@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-shorthand-properties/-/babel-plugin-transform-es2015-shorthand-properties-6.24.1.tgz#24f875d6721c87661bbd99a4622e51f14de38aa0" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-spread@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-spread/-/babel-plugin-transform-es2015-spread-6.22.0.tgz#d6d68a99f89aedc4536c81a542e8dd9f1746f8d1" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-sticky-regex@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-sticky-regex/-/babel-plugin-transform-es2015-sticky-regex-6.24.1.tgz#00c1cdb1aca71112cdf0cf6126c2ed6b457ccdbc" + dependencies: + babel-helper-regex "^6.24.1" + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-plugin-transform-es2015-template-literals@^6.22.0: + version "6.22.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-template-literals/-/babel-plugin-transform-es2015-template-literals-6.22.0.tgz#a84b3450f7e9f8f1f6839d6d687da84bb1236d8d" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-typeof-symbol@^6.23.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-typeof-symbol/-/babel-plugin-transform-es2015-typeof-symbol-6.23.0.tgz#dec09f1cddff94b52ac73d505c84df59dcceb372" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-es2015-unicode-regex@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-es2015-unicode-regex/-/babel-plugin-transform-es2015-unicode-regex-6.24.1.tgz#d38b12f42ea7323f729387f18a7c5ae1faeb35e9" + dependencies: + babel-helper-regex "^6.24.1" + babel-runtime "^6.22.0" + regexpu-core "^2.0.0" + +babel-plugin-transform-exponentiation-operator@^6.22.0, babel-plugin-transform-exponentiation-operator@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-exponentiation-operator/-/babel-plugin-transform-exponentiation-operator-6.24.1.tgz#2ab0c9c7f3098fa48907772bb813fe41e8de3a0e" + dependencies: + babel-helper-builder-binary-assignment-operator-visitor "^6.24.1" + babel-plugin-syntax-exponentiation-operator "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-object-rest-spread@^6.22.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-object-rest-spread/-/babel-plugin-transform-object-rest-spread-6.23.0.tgz#875d6bc9be761c58a2ae3feee5dc4895d8c7f921" + dependencies: + babel-plugin-syntax-object-rest-spread "^6.8.0" + babel-runtime "^6.22.0" + +babel-plugin-transform-regenerator@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-regenerator/-/babel-plugin-transform-regenerator-6.24.1.tgz#b8da305ad43c3c99b4848e4fe4037b770d23c418" + dependencies: + regenerator-transform "0.9.11" + +babel-plugin-transform-runtime@^6.22.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-runtime/-/babel-plugin-transform-runtime-6.23.0.tgz#88490d446502ea9b8e7efb0fe09ec4d99479b1ee" + dependencies: + babel-runtime "^6.22.0" + +babel-plugin-transform-strict-mode@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-plugin-transform-strict-mode/-/babel-plugin-transform-strict-mode-6.24.1.tgz#d5faf7aa578a65bbe591cf5edae04a0c67020758" + dependencies: + babel-runtime "^6.22.0" + babel-types "^6.24.1" + +babel-preset-env@^1.3.2: + version "1.5.1" + resolved "https://registry.yarnpkg.com/babel-preset-env/-/babel-preset-env-1.5.1.tgz#d2eca6af179edf27cdc305a84820f601b456dd0b" + dependencies: + babel-plugin-check-es2015-constants "^6.22.0" + babel-plugin-syntax-trailing-function-commas "^6.22.0" + babel-plugin-transform-async-to-generator "^6.22.0" + babel-plugin-transform-es2015-arrow-functions "^6.22.0" + babel-plugin-transform-es2015-block-scoped-functions "^6.22.0" + babel-plugin-transform-es2015-block-scoping "^6.23.0" + babel-plugin-transform-es2015-classes "^6.23.0" + babel-plugin-transform-es2015-computed-properties "^6.22.0" + babel-plugin-transform-es2015-destructuring "^6.23.0" + babel-plugin-transform-es2015-duplicate-keys "^6.22.0" + babel-plugin-transform-es2015-for-of "^6.23.0" + babel-plugin-transform-es2015-function-name "^6.22.0" + babel-plugin-transform-es2015-literals "^6.22.0" + babel-plugin-transform-es2015-modules-amd "^6.22.0" + babel-plugin-transform-es2015-modules-commonjs "^6.23.0" + babel-plugin-transform-es2015-modules-systemjs "^6.23.0" + babel-plugin-transform-es2015-modules-umd "^6.23.0" + babel-plugin-transform-es2015-object-super "^6.22.0" + babel-plugin-transform-es2015-parameters "^6.23.0" + babel-plugin-transform-es2015-shorthand-properties "^6.22.0" + babel-plugin-transform-es2015-spread "^6.22.0" + babel-plugin-transform-es2015-sticky-regex "^6.22.0" + babel-plugin-transform-es2015-template-literals "^6.22.0" + babel-plugin-transform-es2015-typeof-symbol "^6.23.0" + babel-plugin-transform-es2015-unicode-regex "^6.22.0" + babel-plugin-transform-exponentiation-operator "^6.22.0" + babel-plugin-transform-regenerator "^6.22.0" + browserslist "^2.1.2" + invariant "^2.2.2" + semver "^5.3.0" + +babel-preset-stage-2@^6.22.0: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-preset-stage-2/-/babel-preset-stage-2-6.24.1.tgz#d9e2960fb3d71187f0e64eec62bc07767219bdc1" + dependencies: + babel-plugin-syntax-dynamic-import "^6.18.0" + babel-plugin-transform-class-properties "^6.24.1" + babel-plugin-transform-decorators "^6.24.1" + babel-preset-stage-3 "^6.24.1" + +babel-preset-stage-3@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-preset-stage-3/-/babel-preset-stage-3-6.24.1.tgz#836ada0a9e7a7fa37cb138fb9326f87934a48395" + dependencies: + babel-plugin-syntax-trailing-function-commas "^6.22.0" + babel-plugin-transform-async-generator-functions "^6.24.1" + babel-plugin-transform-async-to-generator "^6.24.1" + babel-plugin-transform-exponentiation-operator "^6.24.1" + babel-plugin-transform-object-rest-spread "^6.22.0" + +babel-register@^6.22.0, babel-register@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-register/-/babel-register-6.24.1.tgz#7e10e13a2f71065bdfad5a1787ba45bca6ded75f" + dependencies: + babel-core "^6.24.1" + babel-runtime "^6.22.0" + core-js "^2.4.0" + home-or-tmp "^2.0.0" + lodash "^4.2.0" + mkdirp "^0.5.1" + source-map-support "^0.4.2" + +babel-runtime@^6.18.0, babel-runtime@^6.22.0: + version "6.23.0" + resolved "https://registry.yarnpkg.com/babel-runtime/-/babel-runtime-6.23.0.tgz#0a9489f144de70efb3ce4300accdb329e2fc543b" + dependencies: + core-js "^2.4.0" + regenerator-runtime "^0.10.0" + +babel-template@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-template/-/babel-template-6.24.1.tgz#04ae514f1f93b3a2537f2a0f60a5a45fb8308333" + dependencies: + babel-runtime "^6.22.0" + babel-traverse "^6.24.1" + babel-types "^6.24.1" + babylon "^6.11.0" + lodash "^4.2.0" + +babel-traverse@^6.23.1, babel-traverse@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-traverse/-/babel-traverse-6.24.1.tgz#ab36673fd356f9a0948659e7b338d5feadb31695" + dependencies: + babel-code-frame "^6.22.0" + babel-messages "^6.23.0" + babel-runtime "^6.22.0" + babel-types "^6.24.1" + babylon "^6.15.0" + debug "^2.2.0" + globals "^9.0.0" + invariant "^2.2.0" + lodash "^4.2.0" + +babel-types@^6.19.0, babel-types@^6.23.0, babel-types@^6.24.1: + version "6.24.1" + resolved "https://registry.yarnpkg.com/babel-types/-/babel-types-6.24.1.tgz#a136879dc15b3606bda0d90c1fc74304c2ff0975" + dependencies: + babel-runtime "^6.22.0" + esutils "^2.0.2" + lodash "^4.2.0" + to-fast-properties "^1.0.1" + +babylon@^6.11.0, babylon@^6.15.0, babylon@^6.17.0: + version "6.17.2" + resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.17.2.tgz#201d25ef5f892c41bae49488b08db0dd476e9f5c" + +balanced-match@^0.4.0, balanced-match@^0.4.1, balanced-match@^0.4.2: + version "0.4.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838" + +base64-js@^1.0.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.0.tgz#a39992d723584811982be5e290bb6a53d86700f1" + +bcrypt-pbkdf@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz#63bc5dcb61331b92bc05fd528953c33462a06f8d" + dependencies: + tweetnacl "^0.14.3" + +bezier-easing@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/bezier-easing/-/bezier-easing-1.1.1.tgz#9e2f0e270b1ab204ff243d216d1fab52172da26c" + +big.js@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/big.js/-/big.js-3.1.3.tgz#4cada2193652eb3ca9ec8e55c9015669c9806978" + +binary-extensions@^1.0.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.8.0.tgz#48ec8d16df4377eae5fa5884682480af4d95c774" + +block-stream@*: + version "0.0.9" + resolved "https://registry.yarnpkg.com/block-stream/-/block-stream-0.0.9.tgz#13ebfe778a03205cfe03751481ebb4b3300c126a" + dependencies: + inherits "~2.0.0" + +bluebird@^2.10.2: + version "2.11.0" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-2.11.0.tgz#534b9033c022c9579c56ba3b3e5a5caafbb650e1" + +bluebird@^3.0.5, bluebird@^3.1.1, bluebird@^3.4.7: + version "3.5.0" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.0.tgz#791420d7f551eea2897453a8a77653f96606d67c" + +bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: + version "4.11.6" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.6.tgz#53344adb14617a13f6e8dd2ce28905d1c0ba3215" + +boolbase@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" + +boom@2.x.x: + version "2.10.1" + resolved "https://registry.yarnpkg.com/boom/-/boom-2.10.1.tgz#39c8918ceff5799f83f9492a848f625add0c766f" + dependencies: + hoek "2.x.x" + +brace-expansion@^1.1.7: + version "1.1.7" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.7.tgz#3effc3c50e000531fb720eaff80f0ae8ef23cf59" + dependencies: + balanced-match "^0.4.1" + concat-map "0.0.1" + +braces@^1.8.2: + version "1.8.5" + resolved "https://registry.yarnpkg.com/braces/-/braces-1.8.5.tgz#ba77962e12dff969d6b76711e914b737857bf6a7" + dependencies: + expand-range "^1.8.1" + preserve "^0.2.0" + repeat-element "^1.1.2" + +brorand@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" + +browserify-aes@^1.0.0, browserify-aes@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.0.6.tgz#5e7725dbdef1fd5930d4ebab48567ce451c48a0a" + dependencies: + buffer-xor "^1.0.2" + cipher-base "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.0" + inherits "^2.0.1" + +browserify-cipher@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.0.tgz#9988244874bf5ed4e28da95666dcd66ac8fc363a" + dependencies: + browserify-aes "^1.0.4" + browserify-des "^1.0.0" + evp_bytestokey "^1.0.0" + +browserify-des@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.0.tgz#daa277717470922ed2fe18594118a175439721dd" + dependencies: + cipher-base "^1.0.1" + des.js "^1.0.0" + inherits "^2.0.1" + +browserify-rsa@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524" + dependencies: + bn.js "^4.1.0" + randombytes "^2.0.1" + +browserify-sign@^4.0.0: + version "4.0.4" + resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.0.4.tgz#aa4eb68e5d7b658baa6bf6a57e630cbd7a93d298" + dependencies: + bn.js "^4.1.1" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.2" + elliptic "^6.0.0" + inherits "^2.0.1" + parse-asn1 "^5.0.0" + +browserify-zlib@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.1.4.tgz#bb35f8a519f600e0fa6b8485241c979d0141fb2d" + dependencies: + pako "~0.2.0" + +browserslist@^1.1.1, browserslist@^1.1.3, browserslist@^1.3.6, browserslist@^1.5.2, browserslist@^1.7.6: + version "1.7.7" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-1.7.7.tgz#0bd76704258be829b2398bb50e4b62d1a166b0b9" + dependencies: + caniuse-db "^1.0.30000639" + electron-to-chromium "^1.2.7" + +browserslist@^2.1.2: + version "2.1.4" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-2.1.4.tgz#cc526af4a1312b7d2e05653e56d0c8ab70c0e053" + dependencies: + caniuse-lite "^1.0.30000670" + electron-to-chromium "^1.3.11" + +buffer-shims@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/buffer-shims/-/buffer-shims-1.0.0.tgz#9978ce317388c649ad8793028c3477ef044a8b51" + +buffer-xor@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" + +buffer@^4.3.0: + version "4.9.1" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" + dependencies: + base64-js "^1.0.2" + ieee754 "^1.1.4" + isarray "^1.0.0" + +builtin-modules@^1.0.0, builtin-modules@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" + +builtin-status-codes@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" + +caller-path@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-0.1.0.tgz#94085ef63581ecd3daa92444a8fe94e82577751f" + dependencies: + callsites "^0.2.0" + +callsites@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/callsites/-/callsites-0.2.0.tgz#afab96262910a7f33c19a5775825c69f34e350ca" + +camel-case@3.0.x: + version "3.0.0" + resolved "https://registry.yarnpkg.com/camel-case/-/camel-case-3.0.0.tgz#ca3c3688a4e9cf3a4cda777dc4dcbc713249cf73" + dependencies: + no-case "^2.2.0" + upper-case "^1.1.1" + +camelcase-keys@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7" + dependencies: + camelcase "^2.0.0" + map-obj "^1.0.0" + +camelcase@^1.0.2: + version "1.2.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-1.2.1.tgz#9bb5304d2e0b56698b2c758b08a3eaa9daa58a39" + +camelcase@^2.0.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" + +camelcase@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-3.0.0.tgz#32fc4b9fcdaf845fcdf7e73bb97cac2261f0ab0a" + +caniuse-api@^1.5.2: + version "1.6.1" + resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-1.6.1.tgz#b534e7c734c4f81ec5fbe8aca2ad24354b962c6c" + dependencies: + browserslist "^1.3.6" + caniuse-db "^1.0.30000529" + lodash.memoize "^4.1.2" + lodash.uniq "^4.5.0" + +caniuse-db@^1.0.30000187, caniuse-db@^1.0.30000529, caniuse-db@^1.0.30000634, caniuse-db@^1.0.30000639: + version "1.0.30000676" + resolved "https://registry.yarnpkg.com/caniuse-db/-/caniuse-db-1.0.30000676.tgz#82ea578237637c8ff34a28acaade373b624c4ea8" + +caniuse-lite@^1.0.30000670: + version "1.0.30000676" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000676.tgz#1e962123f48073f0c51c4ea0651dd64d25786498" + +caseless@~0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" + +center-align@^0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/center-align/-/center-align-0.1.3.tgz#aa0d32629b6ee972200411cbd4461c907bc2b7ad" + dependencies: + align-text "^0.1.3" + lazy-cache "^1.0.3" + +chalk@^1.0.0, chalk@^1.1.0, chalk@^1.1.1, chalk@^1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" + dependencies: + ansi-styles "^2.2.1" + escape-string-regexp "^1.0.2" + has-ansi "^2.0.0" + strip-ansi "^3.0.0" + supports-color "^2.0.0" + +chokidar@^1.4.3: + version "1.7.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468" + dependencies: + anymatch "^1.3.0" + async-each "^1.0.0" + glob-parent "^2.0.0" + inherits "^2.0.1" + is-binary-path "^1.0.0" + is-glob "^2.0.0" + path-is-absolute "^1.0.0" + readdirp "^2.0.0" + optionalDependencies: + fsevents "^1.0.0" + +cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.3.tgz#eeabf194419ce900da3018c207d212f2a6df0a07" + dependencies: + inherits "^2.0.1" + +circular-json@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.1.tgz#be8b36aefccde8b3ca7aa2d6afc07a37242c0d2d" + +clap@^1.0.9: + version "1.1.3" + resolved "https://registry.yarnpkg.com/clap/-/clap-1.1.3.tgz#b3bd36e93dd4cbfb395a3c26896352445265c05b" + dependencies: + chalk "^1.1.3" + +clean-css@4.1.x: + version "4.1.3" + resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-4.1.3.tgz#07cfe8980edb20d455ddc23aadcf1e04c6e509ce" + dependencies: + source-map "0.5.x" + +cli-cursor@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-1.0.2.tgz#64da3f7d56a54412e59794bd62dc35295e8f2987" + dependencies: + restore-cursor "^1.0.1" + +cli-cursor@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" + dependencies: + restore-cursor "^2.0.0" + +cli-spinners@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-1.0.0.tgz#ef987ed3d48391ac3dab9180b406a742180d6e6a" + +cli-width@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.1.0.tgz#b234ca209b29ef66fc518d9b98d5847b00edf00a" + +clipboard@^1.5.5: + version "1.7.1" + resolved "https://registry.yarnpkg.com/clipboard/-/clipboard-1.7.1.tgz#360d6d6946e99a7a1fef395e42ba92b5e9b5a16b" + dependencies: + good-listener "^1.2.2" + select "^1.1.2" + tiny-emitter "^2.0.0" + +cliui@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-2.1.0.tgz#4b475760ff80264c762c3a1719032e91c7fea0d1" + dependencies: + center-align "^0.1.1" + right-align "^0.1.1" + wordwrap "0.0.2" + +cliui@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-3.2.0.tgz#120601537a916d29940f934da3b48d585a39213d" + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + wrap-ansi "^2.0.0" + +clone-deep@^0.2.4: + version "0.2.4" + resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-0.2.4.tgz#4e73dd09e9fb971cc38670c5dced9c1896481cc6" + dependencies: + for-own "^0.1.3" + is-plain-object "^2.0.1" + kind-of "^3.0.2" + lazy-cache "^1.0.3" + shallow-clone "^0.1.2" + +clone-regexp@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/clone-regexp/-/clone-regexp-1.0.0.tgz#eae0a2413f55c0942f818c229fefce845d7f3b1c" + dependencies: + is-regexp "^1.0.0" + is-supported-regexp-flag "^1.0.0" + +clone@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.2.tgz#260b7a99ebb1edfe247538175f783243cb19d149" + +clunderscore@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/clunderscore/-/clunderscore-1.0.3.tgz#a9f99088702d919404d82781f067872ff209d92c" + +co@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + +coa@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/coa/-/coa-1.0.2.tgz#2ba9fec3b4aa43d7a49d7e6c3561e92061b6bcec" + dependencies: + q "^1.1.2" + +code-point-at@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + +color-convert@^1.3.0: + version "1.9.0" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.0.tgz#1accf97dd739b983bf994d56fec8f95853641b7a" + dependencies: + color-name "^1.1.1" + +color-diff@^0.1.3: + version "0.1.7" + resolved "https://registry.yarnpkg.com/color-diff/-/color-diff-0.1.7.tgz#6db78cd9482a8e459d40821eaf4b503283dcb8e2" + +color-name@^1.0.0, color-name@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.2.tgz#5c8ab72b64bd2215d617ae9559ebb148475cf98d" + +color-string@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/color-string/-/color-string-0.3.0.tgz#27d46fb67025c5c2fa25993bfbf579e47841b991" + dependencies: + color-name "^1.0.0" + +color@^0.11.0: + version "0.11.4" + resolved "https://registry.yarnpkg.com/color/-/color-0.11.4.tgz#6d7b5c74fb65e841cd48792ad1ed5e07b904d764" + dependencies: + clone "^1.0.2" + color-convert "^1.3.0" + color-string "^0.3.0" + +colorguard@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/colorguard/-/colorguard-1.2.0.tgz#f3facaf5caaeba4ef54653d9fb25bb73177c0d84" + dependencies: + chalk "^1.1.1" + color-diff "^0.1.3" + log-symbols "^1.0.2" + object-assign "^4.0.1" + pipetteur "^2.0.0" + plur "^2.0.0" + postcss "^5.0.4" + postcss-reporter "^1.2.1" + text-table "^0.2.0" + yargs "^1.2.6" + +colormin@^1.0.5: + version "1.1.2" + resolved "https://registry.yarnpkg.com/colormin/-/colormin-1.1.2.tgz#ea2f7420a72b96881a38aae59ec124a6f7298133" + dependencies: + color "^0.11.0" + css-color-names "0.0.4" + has "^1.0.1" + +colors@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63" + +combined-stream@^1.0.5, combined-stream@~1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.5.tgz#938370a57b4a51dea2c77c15d5c5fdf895164009" + dependencies: + delayed-stream "~1.0.0" + +commander@2.9.x, commander@^2.9.0, commander@~2.9.0: + version "2.9.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.9.0.tgz#9c99094176e12240cb22d6c5146098400fe0f7d4" + dependencies: + graceful-readlink ">= 1.0.0" + +commondir@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + +concat-stream@^1.5.2: + version "1.6.0" + resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.0.tgz#0aac662fd52be78964d5532f694784e70110acf7" + dependencies: + inherits "^2.0.3" + readable-stream "^2.2.2" + typedarray "^0.0.6" + +config-chain@~1.1.5: + version "1.1.11" + resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.11.tgz#aba09747dfbe4c3e70e766a6e41586e1859fc6f2" + dependencies: + ini "^1.3.4" + proto-list "~1.2.1" + +connect-history-api-fallback@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/connect-history-api-fallback/-/connect-history-api-fallback-1.3.0.tgz#e51d17f8f0ef0db90a64fdb47de3051556e9f169" + +console-browserify@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10" + dependencies: + date-now "^0.1.4" + +console-control-strings@^1.0.0, console-control-strings@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + +consolidate@^0.14.0: + version "0.14.5" + resolved "https://registry.yarnpkg.com/consolidate/-/consolidate-0.14.5.tgz#5a25047bc76f73072667c8cb52c989888f494c63" + dependencies: + bluebird "^3.1.1" + +constants-browserify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" + +contains-path@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/contains-path/-/contains-path-0.1.0.tgz#fe8cf184ff6670b6baef01a9d4861a5cbec4120a" + +content-disposition@0.5.2: + version "0.5.2" + resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4" + +content-type@~1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.2.tgz#b7d113aee7a8dd27bd21133c4dc2529df1721eed" + +convert-source-map@^1.1.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.5.0.tgz#9acd70851c6d5dfdd93d9282e5edf94a03ff46b5" + +cookie-signature@1.0.6: + version "1.0.6" + resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" + +cookie@0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb" + +copy-webpack-plugin@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-4.0.1.tgz#9728e383b94316050d0c7463958f2b85c0aa8200" + dependencies: + bluebird "^2.10.2" + fs-extra "^0.26.4" + glob "^6.0.4" + is-glob "^3.1.0" + loader-utils "^0.2.15" + lodash "^4.3.0" + minimatch "^3.0.0" + node-dir "^0.1.10" + +core-js@^2.4.0: + version "2.4.1" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.4.1.tgz#4de911e667b0eae9124e34254b53aea6fc618d3e" + +core-util-is@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + +cosmiconfig@^2.1.0, cosmiconfig@^2.1.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-2.1.3.tgz#952771eb0dddc1cb3fa2f6fbe51a522e93b3ee0a" + dependencies: + is-directory "^0.3.1" + js-yaml "^3.4.3" + minimist "^1.2.0" + object-assign "^4.1.0" + os-homedir "^1.0.1" + parse-json "^2.2.0" + require-from-string "^1.1.0" + +create-ecdh@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.0.tgz#888c723596cdf7612f6498233eebd7a35301737d" + dependencies: + bn.js "^4.1.0" + elliptic "^6.0.0" + +create-hash@^1.1.0, create-hash@^1.1.1, create-hash@^1.1.2: + version "1.1.3" + resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.1.3.tgz#606042ac8b9262750f483caddab0f5819172d8fd" + dependencies: + cipher-base "^1.0.1" + inherits "^2.0.1" + ripemd160 "^2.0.0" + sha.js "^2.4.0" + +create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4: + version "1.1.6" + resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.6.tgz#acb9e221a4e17bdb076e90657c42b93e3726cf06" + dependencies: + cipher-base "^1.0.3" + create-hash "^1.1.0" + inherits "^2.0.1" + ripemd160 "^2.0.0" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +cross-spawn@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-3.0.1.tgz#1256037ecb9f0c5f79e3d6ef135e30770184b982" + dependencies: + lru-cache "^4.0.1" + which "^1.2.9" + +cryptiles@2.x.x: + version "2.0.5" + resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8" + dependencies: + boom "2.x.x" + +crypto-browserify@^3.11.0: + version "3.11.0" + resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.11.0.tgz#3652a0906ab9b2a7e0c3ce66a408e957a2485522" + dependencies: + browserify-cipher "^1.0.0" + browserify-sign "^4.0.0" + create-ecdh "^4.0.0" + create-hash "^1.1.0" + create-hmac "^1.1.0" + diffie-hellman "^5.0.0" + inherits "^2.0.1" + pbkdf2 "^3.0.3" + public-encrypt "^4.0.0" + randombytes "^2.0.0" + +css-color-names@0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.3.tgz#de0cef16f4d8aa8222a320d5b6d7e9bbada7b9f6" + +css-color-names@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-0.0.4.tgz#808adc2e79cf84738069b646cb20ec27beb629e0" + +css-loader@^0.28.4: + version "0.28.4" + resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-0.28.4.tgz#6cf3579192ce355e8b38d5f42dd7a1f2ec898d0f" + dependencies: + babel-code-frame "^6.11.0" + css-selector-tokenizer "^0.7.0" + cssnano ">=2.6.1 <4" + icss-utils "^2.1.0" + loader-utils "^1.0.2" + lodash.camelcase "^4.3.0" + object-assign "^4.0.1" + postcss "^5.0.6" + postcss-modules-extract-imports "^1.0.0" + postcss-modules-local-by-default "^1.0.1" + postcss-modules-scope "^1.0.0" + postcss-modules-values "^1.1.0" + postcss-value-parser "^3.3.0" + source-list-map "^0.1.7" + +css-rule-stream@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/css-rule-stream/-/css-rule-stream-1.1.0.tgz#3786e7198983d965a26e31957e09078cbb7705a2" + dependencies: + css-tokenize "^1.0.1" + duplexer2 "0.0.2" + ldjson-stream "^1.2.1" + through2 "^0.6.3" + +css-select@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/css-select/-/css-select-1.2.0.tgz#2b3a110539c5355f1cd8d314623e870b121ec858" + dependencies: + boolbase "~1.0.0" + css-what "2.1" + domutils "1.5.1" + nth-check "~1.0.1" + +css-selector-tokenizer@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/css-selector-tokenizer/-/css-selector-tokenizer-0.7.0.tgz#e6988474ae8c953477bf5e7efecfceccd9cf4c86" + dependencies: + cssesc "^0.1.0" + fastparse "^1.1.1" + regexpu-core "^1.0.0" + +css-tokenize@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/css-tokenize/-/css-tokenize-1.0.1.tgz#4625cb1eda21c143858b7f81d6803c1d26fc14be" + dependencies: + inherits "^2.0.1" + readable-stream "^1.0.33" + +css-what@2.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/css-what/-/css-what-2.1.0.tgz#9467d032c38cfaefb9f2d79501253062f87fa1bd" + +cssesc@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-0.1.0.tgz#c814903e45623371a0477b40109aaafbeeaddbb4" + +"cssnano@>=2.6.1 <4", cssnano@^3.4.0: + version "3.10.0" + resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-3.10.0.tgz#4f38f6cea2b9b17fa01490f23f1dc68ea65c1c38" + dependencies: + autoprefixer "^6.3.1" + decamelize "^1.1.2" + defined "^1.0.0" + has "^1.0.1" + object-assign "^4.0.1" + postcss "^5.0.14" + postcss-calc "^5.2.0" + postcss-colormin "^2.1.8" + postcss-convert-values "^2.3.4" + postcss-discard-comments "^2.0.4" + postcss-discard-duplicates "^2.0.1" + postcss-discard-empty "^2.0.1" + postcss-discard-overridden "^0.1.1" + postcss-discard-unused "^2.2.1" + postcss-filter-plugins "^2.0.0" + postcss-merge-idents "^2.1.5" + postcss-merge-longhand "^2.0.1" + postcss-merge-rules "^2.0.3" + postcss-minify-font-values "^1.0.2" + postcss-minify-gradients "^1.0.1" + postcss-minify-params "^1.0.4" + postcss-minify-selectors "^2.0.4" + postcss-normalize-charset "^1.1.0" + postcss-normalize-url "^3.0.7" + postcss-ordered-values "^2.1.0" + postcss-reduce-idents "^2.2.2" + postcss-reduce-initial "^1.0.0" + postcss-reduce-transforms "^1.0.3" + postcss-svgo "^2.1.1" + postcss-unique-selectors "^2.0.2" + postcss-value-parser "^3.2.3" + postcss-zindex "^2.0.1" + +csso@~2.3.1: + version "2.3.2" + resolved "https://registry.yarnpkg.com/csso/-/csso-2.3.2.tgz#ddd52c587033f49e94b71fc55569f252e8ff5f85" + dependencies: + clap "^1.0.9" + source-map "^0.5.3" + +currently-unhandled@^0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" + dependencies: + array-find-index "^1.0.1" + +d@1: + version "1.0.0" + resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f" + dependencies: + es5-ext "^0.10.9" + +dashdash@^1.12.0: + version "1.14.1" + resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + dependencies: + assert-plus "^1.0.0" + +date-now@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" + +de-indent@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/de-indent/-/de-indent-1.0.2.tgz#b2038e846dc33baa5796128d0804b455b8c1e21d" + +debug@2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.2.0.tgz#f87057e995b1a1f6ae6a4960664137bc56f039da" + dependencies: + ms "0.7.1" + +debug@2.6.7: + version "2.6.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.7.tgz#92bad1f6d05bbb6bba22cca88bcd0ec894c2861e" + dependencies: + ms "2.0.0" + +debug@^2.1.1, debug@^2.2.0, debug@^2.6.0: + version "2.6.8" + resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.8.tgz#e731531ca2ede27d188222427da17821d68ff4fc" + dependencies: + ms "2.0.0" + +decamelize@^1.0.0, decamelize@^1.1.1, decamelize@^1.1.2: + version "1.2.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + +deep-extend@~0.4.0: + version "0.4.2" + resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.4.2.tgz#48b699c27e334bf89f10892be432f6e4c7d34a7f" + +deep-is@~0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" + +defined@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/defined/-/defined-1.0.0.tgz#c98d9bcef75674188e110969151199e39b1fa693" + +del@^2.0.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/del/-/del-2.2.2.tgz#c12c981d067846c84bcaf862cff930d907ffd1a8" + dependencies: + globby "^5.0.0" + is-path-cwd "^1.0.0" + is-path-in-cwd "^1.0.0" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + rimraf "^2.2.8" + +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + +delegate@^3.1.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/delegate/-/delegate-3.1.3.tgz#9a8251a777d7025faa55737bc3b071742127a9fd" + +delegates@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + +depd@1.1.0, depd@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.0.tgz#e1bd82c6aab6ced965b97b88b17ed3e528ca18c3" + +des.js@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.0.tgz#c074d2e2aa6a8a9a07dbd61f9a15c2cd83ec8ecc" + dependencies: + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + +destroy@~1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" + +detect-indent@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-4.0.0.tgz#f76d064352cdf43a1cb6ce619c4ee3a9475de208" + dependencies: + repeating "^2.0.0" + +diff-match-patch@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/diff-match-patch/-/diff-match-patch-1.0.0.tgz#1cc3c83a490d67f95d91e39f6ad1f2e086b63048" + +diffie-hellman@^5.0.0: + version "5.0.2" + resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.2.tgz#b5835739270cfe26acf632099fded2a07f209e5e" + dependencies: + bn.js "^4.1.0" + miller-rabin "^4.0.0" + randombytes "^2.0.0" + +doctrine@1.5.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" + dependencies: + esutils "^2.0.2" + isarray "^1.0.0" + +doctrine@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.0.0.tgz#c73d8d2909d22291e1a007a395804da8b665fe63" + dependencies: + esutils "^2.0.2" + isarray "^1.0.0" + +doiuse@^2.4.1: + version "2.6.0" + resolved "https://registry.yarnpkg.com/doiuse/-/doiuse-2.6.0.tgz#1892d10b61a9a356addbf2b614933e81f8bb3834" + dependencies: + browserslist "^1.1.1" + caniuse-db "^1.0.30000187" + css-rule-stream "^1.1.0" + duplexer2 "0.0.2" + jsonfilter "^1.1.2" + ldjson-stream "^1.2.1" + lodash "^4.0.0" + multimatch "^2.0.0" + postcss "^5.0.8" + source-map "^0.4.2" + through2 "^0.6.3" + yargs "^3.5.4" + +dom-converter@~0.1: + version "0.1.4" + resolved "https://registry.yarnpkg.com/dom-converter/-/dom-converter-0.1.4.tgz#a45ef5727b890c9bffe6d7c876e7b19cb0e17f3b" + dependencies: + utila "~0.3" + +dom-serializer@0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.0.tgz#073c697546ce0780ce23be4a28e293e40bc30c82" + dependencies: + domelementtype "~1.1.1" + entities "~1.1.1" + +domain-browser@^1.1.1: + version "1.1.7" + resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.1.7.tgz#867aa4b093faa05f1de08c06f4d7b21fdf8698bc" + +domelementtype@1, domelementtype@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.3.0.tgz#b17aed82e8ab59e52dd9c19b1756e0fc187204c2" + +domelementtype@~1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-1.1.3.tgz#bd28773e2642881aec51544924299c5cd822185b" + +domhandler@2.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.1.0.tgz#d2646f5e57f6c3bab11cf6cb05d3c0acf7412594" + dependencies: + domelementtype "1" + +domhandler@^2.3.0: + version "2.4.1" + resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.4.1.tgz#892e47000a99be55bbf3774ffea0561d8879c259" + dependencies: + domelementtype "1" + +domutils@1.1: + version "1.1.6" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.1.6.tgz#bddc3de099b9a2efacc51c623f28f416ecc57485" + dependencies: + domelementtype "1" + +domutils@1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.5.1.tgz#dcd8488a26f563d61079e48c9f7b7e32373682cf" + dependencies: + dom-serializer "0" + domelementtype "1" + +domutils@^1.5.1: + version "1.6.2" + resolved "https://registry.yarnpkg.com/domutils/-/domutils-1.6.2.tgz#1958cc0b4c9426e9ed367fb1c8e854891b0fa3ff" + dependencies: + dom-serializer "0" + domelementtype "1" + +duplexer2@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/duplexer2/-/duplexer2-0.0.2.tgz#c614dcf67e2fb14995a91711e5a617e8a60a31db" + dependencies: + readable-stream "~1.1.9" + +duplexer@^0.1.1, duplexer@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1" + +ecc-jsbn@~0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz#0fc73a9ed5f0d53c38193398523ef7e543777505" + dependencies: + jsbn "~0.1.0" + +editorconfig@^0.13.2: + version "0.13.2" + resolved "https://registry.yarnpkg.com/editorconfig/-/editorconfig-0.13.2.tgz#8e57926d9ee69ab6cb999f027c2171467acceb35" + dependencies: + bluebird "^3.0.5" + commander "^2.9.0" + lru-cache "^3.2.0" + sigmund "^1.0.1" + +ee-first@1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" + +ejs@^2.5.6: + version "2.5.6" + resolved "https://registry.yarnpkg.com/ejs/-/ejs-2.5.6.tgz#479636bfa3fe3b1debd52087f0acb204b4f19c88" + +electron-to-chromium@^1.2.7, electron-to-chromium@^1.3.11: + version "1.3.13" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.13.tgz#1b3a5eace6e087bb5e257a100b0cbfe81b2891fc" + +elliptic@^6.0.0: + version "6.4.0" + resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.4.0.tgz#cac9af8762c85836187003c8dfe193e5e2eae5df" + dependencies: + bn.js "^4.4.0" + brorand "^1.0.1" + hash.js "^1.0.0" + hmac-drbg "^1.0.0" + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.0" + +emojis-list@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" + +encodeurl@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.1.tgz#79e3d58655346909fe6f0f45a5de68103b294d20" + +enhanced-resolve@^3.0.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-3.1.0.tgz#9f4b626f577245edcf4b2ad83d86e17f4f421dec" + dependencies: + graceful-fs "^4.1.2" + memory-fs "^0.4.0" + object-assign "^4.0.1" + tapable "^0.2.5" + +enhanced-resolve@~0.9.0: + version "0.9.1" + resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-0.9.1.tgz#4d6e689b3725f86090927ccc86cd9f1635b89e2e" + dependencies: + graceful-fs "^4.1.2" + memory-fs "^0.2.0" + tapable "^0.1.8" + +entities@^1.1.1, entities@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" + +errno@^0.1.3: + version "0.1.4" + resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.4.tgz#b896e23a9e5e8ba33871fc996abd3635fc9a1c7d" + dependencies: + prr "~0.0.0" + +error-ex@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.1.tgz#f855a86ce61adc4e8621c3cda21e7a7612c3a8dc" + dependencies: + is-arrayish "^0.2.1" + +error-stack-parser@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/error-stack-parser/-/error-stack-parser-2.0.1.tgz#a3202b8fb03114aa9b40a0e3669e48b2b65a010a" + dependencies: + stackframe "^1.0.3" + +es5-ext@^0.10.14, es5-ext@^0.10.9, es5-ext@~0.10.14: + version "0.10.22" + resolved "https://registry.yarnpkg.com/es5-ext/-/es5-ext-0.10.22.tgz#1876c51f990769c112c781ea3ebe89f84fd39071" + dependencies: + es6-iterator "2" + es6-symbol "~3.1" + +es6-iterator@2, es6-iterator@^2.0.1, es6-iterator@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/es6-iterator/-/es6-iterator-2.0.1.tgz#8e319c9f0453bf575d374940a655920e59ca5512" + dependencies: + d "1" + es5-ext "^0.10.14" + es6-symbol "^3.1" + +es6-map@^0.1.3: + version "0.1.5" + resolved "https://registry.yarnpkg.com/es6-map/-/es6-map-0.1.5.tgz#9136e0503dcc06a301690f0bb14ff4e364e949f0" + dependencies: + d "1" + es5-ext "~0.10.14" + es6-iterator "~2.0.1" + es6-set "~0.1.5" + es6-symbol "~3.1.1" + event-emitter "~0.3.5" + +es6-set@~0.1.5: + version "0.1.5" + resolved "https://registry.yarnpkg.com/es6-set/-/es6-set-0.1.5.tgz#d2b3ec5d4d800ced818db538d28974db0a73ccb1" + dependencies: + d "1" + es5-ext "~0.10.14" + es6-iterator "~2.0.1" + es6-symbol "3.1.1" + event-emitter "~0.3.5" + +es6-symbol@3.1.1, es6-symbol@^3.1, es6-symbol@^3.1.1, es6-symbol@~3.1, es6-symbol@~3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/es6-symbol/-/es6-symbol-3.1.1.tgz#bf00ef4fdab6ba1b46ecb7b629b4c7ed5715cc77" + dependencies: + d "1" + es5-ext "~0.10.14" + +es6-weak-map@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/es6-weak-map/-/es6-weak-map-2.0.2.tgz#5e3ab32251ffd1538a1f8e5ffa1357772f92d96f" + dependencies: + d "1" + es5-ext "^0.10.14" + es6-iterator "^2.0.1" + es6-symbol "^3.1.1" + +escape-html@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" + +escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + +escope@^3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/escope/-/escope-3.6.0.tgz#e01975e812781a163a6dadfdd80398dc64c889c3" + dependencies: + es6-map "^0.1.3" + es6-weak-map "^2.0.1" + esrecurse "^4.1.0" + estraverse "^4.1.1" + +eslint-config-airbnb-base@^11.1.3: + version "11.2.0" + resolved "https://registry.yarnpkg.com/eslint-config-airbnb-base/-/eslint-config-airbnb-base-11.2.0.tgz#19a9dc4481a26f70904545ec040116876018f853" + +eslint-friendly-formatter@^2.0.7: + version "2.0.7" + resolved "https://registry.yarnpkg.com/eslint-friendly-formatter/-/eslint-friendly-formatter-2.0.7.tgz#657f95a19af4989636afebb1cc9de6cebbd088ee" + dependencies: + chalk "^1.0.0" + extend "^3.0.0" + minimist "^1.2.0" + text-table "^0.2.0" + +eslint-import-resolver-node@^0.2.0: + version "0.2.3" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-node/-/eslint-import-resolver-node-0.2.3.tgz#5add8106e8c928db2cba232bcd9efa846e3da16c" + dependencies: + debug "^2.2.0" + object-assign "^4.0.1" + resolve "^1.1.6" + +eslint-import-resolver-webpack@^0.8.1: + version "0.8.1" + resolved "https://registry.yarnpkg.com/eslint-import-resolver-webpack/-/eslint-import-resolver-webpack-0.8.1.tgz#c7f8b4d5bd3c5b489457e5728c5db1c4ffbac9aa" + dependencies: + array-find "^1.0.0" + debug "^2.2.0" + enhanced-resolve "~0.9.0" + find-root "^0.1.1" + has "^1.0.1" + interpret "^1.0.0" + is-absolute "^0.2.3" + lodash.get "^3.7.0" + node-libs-browser "^1.0.0" + resolve "^1.2.0" + semver "^5.3.0" + +eslint-loader@^1.7.1: + version "1.7.1" + resolved "https://registry.yarnpkg.com/eslint-loader/-/eslint-loader-1.7.1.tgz#50b158dd6272dcefb97e984254837f81a5802ce0" + dependencies: + find-cache-dir "^0.1.1" + loader-fs-cache "^1.0.0" + loader-utils "^1.0.2" + object-assign "^4.0.1" + object-hash "^1.1.4" + rimraf "^2.6.1" + +eslint-module-utils@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/eslint-module-utils/-/eslint-module-utils-2.0.0.tgz#a6f8c21d901358759cdc35dbac1982ae1ee58bce" + dependencies: + debug "2.2.0" + pkg-dir "^1.0.0" + +eslint-plugin-html@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/eslint-plugin-html/-/eslint-plugin-html-2.0.3.tgz#7c89883ab0c85fa5d28b666a14a4e906aa90b897" + dependencies: + htmlparser2 "^3.8.2" + +eslint-plugin-import@^2.2.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/eslint-plugin-import/-/eslint-plugin-import-2.3.0.tgz#37c801e0ada0e296cbdf20c3f393acb5b52af36b" + dependencies: + builtin-modules "^1.1.1" + contains-path "^0.1.0" + debug "^2.2.0" + doctrine "1.5.0" + eslint-import-resolver-node "^0.2.0" + eslint-module-utils "^2.0.0" + has "^1.0.1" + lodash.cond "^4.3.0" + minimatch "^3.0.3" + read-pkg-up "^2.0.0" + +eslint@^3.19.0: + version "3.19.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-3.19.0.tgz#c8fc6201c7f40dd08941b87c085767386a679acc" + dependencies: + babel-code-frame "^6.16.0" + chalk "^1.1.3" + concat-stream "^1.5.2" + debug "^2.1.1" + doctrine "^2.0.0" + escope "^3.6.0" + espree "^3.4.0" + esquery "^1.0.0" + estraverse "^4.2.0" + esutils "^2.0.2" + file-entry-cache "^2.0.0" + glob "^7.0.3" + globals "^9.14.0" + ignore "^3.2.0" + imurmurhash "^0.1.4" + inquirer "^0.12.0" + is-my-json-valid "^2.10.0" + is-resolvable "^1.0.0" + js-yaml "^3.5.1" + json-stable-stringify "^1.0.0" + levn "^0.3.0" + lodash "^4.0.0" + mkdirp "^0.5.0" + natural-compare "^1.4.0" + optionator "^0.8.2" + path-is-inside "^1.0.1" + pluralize "^1.2.1" + progress "^1.1.8" + require-uncached "^1.0.2" + shelljs "^0.7.5" + strip-bom "^3.0.0" + strip-json-comments "~2.0.1" + table "^3.7.8" + text-table "~0.2.0" + user-home "^2.0.0" + +espree@^3.4.0: + version "3.4.3" + resolved "https://registry.yarnpkg.com/espree/-/espree-3.4.3.tgz#2910b5ccd49ce893c2ffffaab4fd8b3a31b82374" + dependencies: + acorn "^5.0.1" + acorn-jsx "^3.0.0" + +esprima@^2.6.0: + version "2.7.3" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-2.7.3.tgz#96e3b70d5779f6ad49cd032673d1c312767ba581" + +esprima@^3.1.1: + version "3.1.3" + resolved "https://registry.yarnpkg.com/esprima/-/esprima-3.1.3.tgz#fdca51cee6133895e3c88d535ce49dbff62a4633" + +esquery@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.0.0.tgz#cfba8b57d7fba93f17298a8a006a04cda13d80fa" + dependencies: + estraverse "^4.0.0" + +esrecurse@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.1.0.tgz#4713b6536adf7f2ac4f327d559e7756bff648220" + dependencies: + estraverse "~4.1.0" + object-assign "^4.0.1" + +estraverse@^4.0.0, estraverse@^4.1.1, estraverse@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13" + +estraverse@~4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.1.1.tgz#f6caca728933a850ef90661d0e17982ba47111a2" + +esutils@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b" + +etag@~1.8.0: + version "1.8.0" + resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.0.tgz#6f631aef336d6c46362b51764044ce216be3c051" + +event-emitter@~0.3.5: + version "0.3.5" + resolved "https://registry.yarnpkg.com/event-emitter/-/event-emitter-0.3.5.tgz#df8c69eef1647923c7157b9ce83840610b02cc39" + dependencies: + d "1" + es5-ext "~0.10.14" + +eventemitter3@1.x.x: + version "1.2.0" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-1.2.0.tgz#1c86991d816ad1e504750e73874224ecf3bec508" + +events@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/events/-/events-1.1.1.tgz#9ebdb7635ad099c70dcc4c2a1f5004288e8bd924" + +eventsource-polyfill@^0.9.6: + version "0.9.6" + resolved "https://registry.yarnpkg.com/eventsource-polyfill/-/eventsource-polyfill-0.9.6.tgz#10e0d187f111b167f28fdab918843ce7d818f13c" + +evp_bytestokey@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.0.tgz#497b66ad9fef65cd7c08a6180824ba1476b66e53" + dependencies: + create-hash "^1.1.1" + +execall@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/execall/-/execall-1.0.0.tgz#73d0904e395b3cab0658b08d09ec25307f29bb73" + dependencies: + clone-regexp "^1.0.0" + +exit-hook@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8" + +expand-brackets@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-0.1.5.tgz#df07284e342a807cd733ac5af72411e581d1177b" + dependencies: + is-posix-bracket "^0.1.0" + +expand-range@^1.8.1: + version "1.8.2" + resolved "https://registry.yarnpkg.com/expand-range/-/expand-range-1.8.2.tgz#a299effd335fe2721ebae8e257ec79644fc85337" + dependencies: + fill-range "^2.1.0" + +express@^4.14.1, express@^4.15.2: + version "4.15.3" + resolved "https://registry.yarnpkg.com/express/-/express-4.15.3.tgz#bab65d0f03aa80c358408972fc700f916944b662" + dependencies: + accepts "~1.3.3" + array-flatten "1.1.1" + content-disposition "0.5.2" + content-type "~1.0.2" + cookie "0.3.1" + cookie-signature "1.0.6" + debug "2.6.7" + depd "~1.1.0" + encodeurl "~1.0.1" + escape-html "~1.0.3" + etag "~1.8.0" + finalhandler "~1.0.3" + fresh "0.5.0" + merge-descriptors "1.0.1" + methods "~1.1.2" + on-finished "~2.3.0" + parseurl "~1.3.1" + path-to-regexp "0.1.7" + proxy-addr "~1.1.4" + qs "6.4.0" + range-parser "~1.2.0" + send "0.15.3" + serve-static "1.12.3" + setprototypeof "1.0.3" + statuses "~1.3.1" + type-is "~1.6.15" + utils-merge "1.0.0" + vary "~1.1.1" + +extend@^3.0.0, extend@~3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444" + +extglob@^0.3.1: + version "0.3.2" + resolved "https://registry.yarnpkg.com/extglob/-/extglob-0.3.2.tgz#2e18ff3d2f49ab2765cec9023f011daa8d8349a1" + dependencies: + is-extglob "^1.0.0" + +extract-text-webpack-plugin@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/extract-text-webpack-plugin/-/extract-text-webpack-plugin-2.1.0.tgz#69315b885f876dbf96d3819f6a9f1cca7aebf159" + dependencies: + ajv "^4.11.2" + async "^2.1.2" + loader-utils "^1.0.2" + webpack-sources "^0.1.0" + +extsprintf@1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.0.2.tgz#e1080e0658e300b06294990cc70e1502235fd550" + +fast-levenshtein@~2.0.4: + version "2.0.6" + resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + +fastparse@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.1.tgz#d1e2643b38a94d7583b479060e6c4affc94071f8" + +figures@^1.3.5: + version "1.7.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-1.7.0.tgz#cbe1e3affcf1cd44b80cadfed28dc793a9701d2e" + dependencies: + escape-string-regexp "^1.0.5" + object-assign "^4.1.0" + +file-entry-cache@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-2.0.0.tgz#c392990c3e684783d838b8c84a45d8a048458361" + dependencies: + flat-cache "^1.2.1" + object-assign "^4.0.1" + +file-loader@^0.11.1: + version "0.11.1" + resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-0.11.1.tgz#6b328ee1234a729e4e47d36375dd6d35c0e1db84" + dependencies: + loader-utils "^1.0.2" + +filename-regex@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26" + +filesize@^3.5.9: + version "3.5.10" + resolved "https://registry.yarnpkg.com/filesize/-/filesize-3.5.10.tgz#fc8fa23ddb4ef9e5e0ab6e1e64f679a24a56761f" + +fill-range@^2.1.0: + version "2.2.3" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-2.2.3.tgz#50b77dfd7e469bc7492470963699fe7a8485a723" + dependencies: + is-number "^2.1.0" + isobject "^2.0.0" + randomatic "^1.1.3" + repeat-element "^1.1.2" + repeat-string "^1.5.2" + +finalhandler@~1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.0.3.tgz#ef47e77950e999780e86022a560e3217e0d0cc89" + dependencies: + debug "2.6.7" + encodeurl "~1.0.1" + escape-html "~1.0.3" + on-finished "~2.3.0" + parseurl "~1.3.1" + statuses "~1.3.1" + unpipe "~1.0.0" + +find-cache-dir@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-0.1.1.tgz#c8defae57c8a52a8a784f9e31c57c742e993a0b9" + dependencies: + commondir "^1.0.1" + mkdirp "^0.5.1" + pkg-dir "^1.0.0" + +find-root@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/find-root/-/find-root-0.1.2.tgz#98d2267cff1916ccaf2743b3a0eea81d79d7dcd1" + +find-up@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" + dependencies: + path-exists "^2.0.0" + pinkie-promise "^2.0.0" + +find-up@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" + dependencies: + locate-path "^2.0.0" + +flat-cache@^1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/flat-cache/-/flat-cache-1.2.2.tgz#fa86714e72c21db88601761ecf2f555d1abc6b96" + dependencies: + circular-json "^0.3.1" + del "^2.0.2" + graceful-fs "^4.1.2" + write "^0.2.1" + +flatten@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782" + +for-in@^0.1.3: + version "0.1.8" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.8.tgz#d8773908e31256109952b1fdb9b3fa867d2775e1" + +for-in@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + +for-own@^0.1.3, for-own@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" + dependencies: + for-in "^1.0.1" + +forever-agent@~0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + +form-data@~2.1.1: + version "2.1.4" + resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.1.4.tgz#33c183acf193276ecaa98143a69e94bfee1750d1" + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.5" + mime-types "^2.1.12" + +forwarded@~0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.0.tgz#19ef9874c4ae1c297bcf078fde63a09b66a84363" + +fresh@0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.0.tgz#f474ca5e6a9246d6fd8e0953cfa9b9c805afa78e" + +friendly-errors-webpack-plugin@^1.1.3: + version "1.6.1" + resolved "https://registry.yarnpkg.com/friendly-errors-webpack-plugin/-/friendly-errors-webpack-plugin-1.6.1.tgz#e32781c4722f546a06a9b5d7a7cfa28520375d70" + dependencies: + chalk "^1.1.3" + error-stack-parser "^2.0.0" + string-length "^1.0.1" + +fs-extra@^0.26.4: + version "0.26.7" + resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.26.7.tgz#9ae1fdd94897798edab76d0918cf42d0c3184fa9" + dependencies: + graceful-fs "^4.1.2" + jsonfile "^2.1.0" + klaw "^1.0.0" + path-is-absolute "^1.0.0" + rimraf "^2.2.8" + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + +fsevents@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.1.1.tgz#f19fd28f43eeaf761680e519a203c4d0b3d31aff" + dependencies: + nan "^2.3.0" + node-pre-gyp "^0.6.29" + +fstream-ignore@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/fstream-ignore/-/fstream-ignore-1.0.5.tgz#9c31dae34767018fe1d249b24dada67d092da105" + dependencies: + fstream "^1.0.0" + inherits "2" + minimatch "^3.0.0" + +fstream@^1.0.0, fstream@^1.0.10, fstream@^1.0.2: + version "1.0.11" + resolved "https://registry.yarnpkg.com/fstream/-/fstream-1.0.11.tgz#5c1fb1f117477114f0632a0eb4b71b3cb0fd3171" + dependencies: + graceful-fs "^4.1.2" + inherits "~2.0.0" + mkdirp ">=0.5 0" + rimraf "2" + +function-bind@^1.0.2: + version "1.1.0" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.0.tgz#16176714c801798e4e8f2cf7f7529467bb4a5771" + +gather-stream@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/gather-stream/-/gather-stream-1.0.0.tgz#b33994af457a8115700d410f317733cbe7a0904b" + +gauge@~2.7.3: + version "2.7.4" + resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" + dependencies: + aproba "^1.0.3" + console-control-strings "^1.0.0" + has-unicode "^2.0.0" + object-assign "^4.1.0" + signal-exit "^3.0.0" + string-width "^1.0.1" + strip-ansi "^3.0.1" + wide-align "^1.1.0" + +gaze@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/gaze/-/gaze-1.1.2.tgz#847224677adb8870d679257ed3388fdb61e40105" + dependencies: + globule "^1.0.0" + +generate-function@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.0.0.tgz#6858fe7c0969b7d4e9093337647ac79f60dfbe74" + +generate-object-property@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/generate-object-property/-/generate-object-property-1.2.0.tgz#9c0e1c40308ce804f4783618b937fa88f99d50d0" + dependencies: + is-property "^1.0.0" + +get-caller-file@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.2.tgz#f702e63127e7e231c160a80c1554acb70d5047e5" + +get-stdin@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" + +get-stdin@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-5.0.1.tgz#122e161591e21ff4c52530305693f20e6393a398" + +getpass@^0.1.1: + version "0.1.7" + resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" + dependencies: + assert-plus "^1.0.0" + +glob-base@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/glob-base/-/glob-base-0.3.0.tgz#dbb164f6221b1c0b1ccf82aea328b497df0ea3c4" + dependencies: + glob-parent "^2.0.0" + is-glob "^2.0.0" + +glob-parent@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-2.0.0.tgz#81383d72db054fcccf5336daa902f182f6edbb28" + dependencies: + is-glob "^2.0.0" + +glob@^6.0.4: + version "6.0.4" + resolved "https://registry.yarnpkg.com/glob/-/glob-6.0.4.tgz#0f08860f6a155127b2fadd4f9ce24b1aab6e4d22" + dependencies: + inflight "^1.0.4" + inherits "2" + minimatch "2 || 3" + once "^1.3.0" + path-is-absolute "^1.0.0" + +glob@^7.0.0, glob@^7.0.3, glob@^7.0.5, glob@~7.1.1: + version "7.1.2" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.2.tgz#c19c9df9a028702d678612384a6552404c636d15" + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +globals@^9.0.0, globals@^9.14.0: + version "9.17.0" + resolved "https://registry.yarnpkg.com/globals/-/globals-9.17.0.tgz#0c0ca696d9b9bb694d2e5470bd37777caad50286" + +globby@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-5.0.0.tgz#ebd84667ca0dbb330b99bcfc68eac2bc54370e0d" + dependencies: + array-union "^1.0.1" + arrify "^1.0.0" + glob "^7.0.3" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + +globby@^6.0.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c" + dependencies: + array-union "^1.0.1" + glob "^7.0.3" + object-assign "^4.0.1" + pify "^2.0.0" + pinkie-promise "^2.0.0" + +globjoin@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/globjoin/-/globjoin-0.1.4.tgz#2f4494ac8919e3767c5cbb691e9f463324285d43" + +globule@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/globule/-/globule-1.1.0.tgz#c49352e4dc183d85893ee825385eb994bb6df45f" + dependencies: + glob "~7.1.1" + lodash "~4.16.4" + minimatch "~3.0.2" + +good-listener@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/good-listener/-/good-listener-1.2.2.tgz#d53b30cdf9313dffb7dc9a0d477096aa6d145c50" + dependencies: + delegate "^3.1.2" + +graceful-fs@^4.1.2, graceful-fs@^4.1.6, graceful-fs@^4.1.9: + version "4.1.11" + resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.1.11.tgz#0e8bdfe4d1ddb8854d64e04ea7c00e2a026e5658" + +"graceful-readlink@>= 1.0.0": + version "1.0.1" + resolved "https://registry.yarnpkg.com/graceful-readlink/-/graceful-readlink-1.0.1.tgz#4cafad76bc62f02fa039b2f94e9a3dd3a391a725" + +gzip-size@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-3.0.0.tgz#546188e9bdc337f673772f81660464b389dce520" + dependencies: + duplexer "^0.1.1" + +har-schema@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-1.0.5.tgz#d263135f43307c02c602afc8fe95970c0151369e" + +har-validator@~4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-4.2.1.tgz#33481d0f1bbff600dd203d75812a6a5fba002e2a" + dependencies: + ajv "^4.9.1" + har-schema "^1.0.5" + +has-ansi@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91" + dependencies: + ansi-regex "^2.0.0" + +has-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-1.0.0.tgz#9d9e793165ce017a00f00418c43f942a7b1d11fa" + +has-unicode@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + +has@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/has/-/has-1.0.1.tgz#8461733f538b0837c9361e39a9ab9e9704dc2f28" + dependencies: + function-bind "^1.0.2" + +hash-base@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-2.0.2.tgz#66ea1d856db4e8a5470cadf6fce23ae5244ef2e1" + dependencies: + inherits "^2.0.1" + +hash-sum@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/hash-sum/-/hash-sum-1.0.2.tgz#33b40777754c6432573c120cc3808bbd10d47f04" + +hash.js@^1.0.0, hash.js@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.0.3.tgz#1332ff00156c0a0ffdd8236013d07b77a0451573" + dependencies: + inherits "^2.0.1" + +hawk@~3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/hawk/-/hawk-3.1.3.tgz#078444bd7c1640b0fe540d2c9b73d59678e8e1c4" + dependencies: + boom "2.x.x" + cryptiles "2.x.x" + hoek "2.x.x" + sntp "1.x.x" + +he@1.1.x, he@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/he/-/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd" + +hmac-drbg@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" + +hoek@2.x.x: + version "2.16.3" + resolved "https://registry.yarnpkg.com/hoek/-/hoek-2.16.3.tgz#20bb7403d3cea398e91dc4710a8ff1b8274a25ed" + +home-or-tmp@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/home-or-tmp/-/home-or-tmp-2.0.0.tgz#e36c3f2d2cae7d746a857e38d18d5f32a7882db8" + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.1" + +hosted-git-info@^2.1.4: + version "2.4.2" + resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.4.2.tgz#0076b9f46a270506ddbaaea56496897460612a67" + +html-comment-regex@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/html-comment-regex/-/html-comment-regex-1.1.1.tgz#668b93776eaae55ebde8f3ad464b307a4963625e" + +html-entities@^1.2.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-1.2.1.tgz#0df29351f0721163515dfb9e5543e5f6eed5162f" + +html-minifier@^3.2.3: + version "3.5.2" + resolved "https://registry.yarnpkg.com/html-minifier/-/html-minifier-3.5.2.tgz#d73bc3ff448942408818ce609bf3fb0ea7ef4eb7" + dependencies: + camel-case "3.0.x" + clean-css "4.1.x" + commander "2.9.x" + he "1.1.x" + ncname "1.0.x" + param-case "2.1.x" + relateurl "0.2.x" + uglify-js "3.0.x" + +html-tags@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/html-tags/-/html-tags-1.1.1.tgz#869f43859f12d9bdc3892419e494a628aa1b204e" + +html-webpack-plugin@^2.28.0: + version "2.28.0" + resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-2.28.0.tgz#2e7863b57e5fd48fe263303e2ffc934c3064d009" + dependencies: + bluebird "^3.4.7" + html-minifier "^3.2.3" + loader-utils "^0.2.16" + lodash "^4.17.3" + pretty-error "^2.0.2" + toposort "^1.0.0" + +htmlparser2@^3.8.2, htmlparser2@^3.9.1: + version "3.9.2" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.9.2.tgz#1bdf87acca0f3f9e53fa4fcceb0f4b4cbb00b338" + dependencies: + domelementtype "^1.3.0" + domhandler "^2.3.0" + domutils "^1.5.1" + entities "^1.1.1" + inherits "^2.0.1" + readable-stream "^2.0.2" + +htmlparser2@~3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.3.0.tgz#cc70d05a59f6542e43f0e685c982e14c924a9efe" + dependencies: + domelementtype "1" + domhandler "2.1" + domutils "1.1" + readable-stream "1.0" + +http-errors@~1.6.1: + version "1.6.1" + resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.6.1.tgz#5f8b8ed98aca545656bf572997387f904a722257" + dependencies: + depd "1.1.0" + inherits "2.0.3" + setprototypeof "1.0.3" + statuses ">= 1.3.1 < 2" + +http-proxy-middleware@^0.17.3: + version "0.17.4" + resolved "https://registry.yarnpkg.com/http-proxy-middleware/-/http-proxy-middleware-0.17.4.tgz#642e8848851d66f09d4f124912846dbaeb41b833" + dependencies: + http-proxy "^1.16.2" + is-glob "^3.1.0" + lodash "^4.17.2" + micromatch "^2.3.11" + +http-proxy@^1.16.2: + version "1.16.2" + resolved "https://registry.yarnpkg.com/http-proxy/-/http-proxy-1.16.2.tgz#06dff292952bf64dbe8471fa9df73066d4f37742" + dependencies: + eventemitter3 "1.x.x" + requires-port "1.x.x" + +http-signature@~1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.1.1.tgz#df72e267066cd0ac67fb76adf8e134a8fbcf91bf" + dependencies: + assert-plus "^0.2.0" + jsprim "^1.2.2" + sshpk "^1.7.0" + +https-browserify@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-0.0.1.tgz#3f91365cabe60b77ed0ebba24b454e3e09d95a82" + +icss-replace-symbols@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/icss-replace-symbols/-/icss-replace-symbols-1.1.0.tgz#06ea6f83679a7749e386cfe1fe812ae5db223ded" + +icss-utils@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-2.1.0.tgz#83f0a0ec378bf3246178b6c2ad9136f135b1c962" + dependencies: + postcss "^6.0.1" + +ieee754@^1.1.4: + version "1.1.8" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.1.8.tgz#be33d40ac10ef1926701f6f08a2d86fbfd1ad3e4" + +ignore@^3.2.0: + version "3.3.3" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.3.tgz#432352e57accd87ab3110e82d3fea0e47812156d" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + +in-publish@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/in-publish/-/in-publish-2.0.0.tgz#e20ff5e3a2afc2690320b6dc552682a9c7fadf51" + +indent-string@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80" + dependencies: + repeating "^2.0.0" + +indexes-of@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607" + +indexof@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/indexof/-/indexof-0.0.1.tgz#82dc336d232b9062179d05ab3293a66059fd435d" + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2, inherits@2.0.3, inherits@^2.0.1, inherits@^2.0.3, inherits@~2.0.0, inherits@~2.0.1: + version "2.0.3" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + +inherits@2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" + +ini@^1.3.4, ini@~1.3.0: + version "1.3.4" + resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.4.tgz#0537cb79daf59b59a1a517dff706c86ec039162e" + +inquirer@^0.12.0: + version "0.12.0" + resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-0.12.0.tgz#1ef2bfd63504df0bc75785fff8c2c41df12f077e" + dependencies: + ansi-escapes "^1.1.0" + ansi-regex "^2.0.0" + chalk "^1.0.0" + cli-cursor "^1.0.1" + cli-width "^2.0.0" + figures "^1.3.5" + lodash "^4.3.0" + readline2 "^1.0.1" + run-async "^0.1.0" + rx-lite "^3.1.2" + string-width "^1.0.1" + strip-ansi "^3.0.0" + through "^2.3.6" + +interpret@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.0.3.tgz#cbc35c62eeee73f19ab7b10a801511401afc0f90" + +invariant@^2.2.0, invariant@^2.2.2: + version "2.2.2" + resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.2.tgz#9e1f56ac0acdb6bf303306f338be3b204ae60360" + dependencies: + loose-envify "^1.0.0" + +invert-kv@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-1.0.0.tgz#104a8e4aaca6d3d8cd157a8ef8bfab2d7a3ffdb6" + +ipaddr.js@1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.3.0.tgz#1e03a52fdad83a8bbb2b25cbf4998b4cffcd3dec" + +irregular-plurals@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/irregular-plurals/-/irregular-plurals-1.2.0.tgz#38f299834ba8c00c30be9c554e137269752ff3ac" + +is-absolute-url@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-2.1.0.tgz#50530dfb84fcc9aa7dbe7852e83a37b93b9f2aa6" + +is-absolute@^0.2.3: + version "0.2.6" + resolved "https://registry.yarnpkg.com/is-absolute/-/is-absolute-0.2.6.tgz#20de69f3db942ef2d87b9c2da36f172235b1b5eb" + dependencies: + is-relative "^0.2.1" + is-windows "^0.2.0" + +is-arrayish@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + +is-binary-path@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" + dependencies: + binary-extensions "^1.0.0" + +is-buffer@^1.0.2, is-buffer@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.5.tgz#1f3b26ef613b214b88cbca23cc6c01d87961eecc" + +is-builtin-module@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-builtin-module/-/is-builtin-module-1.0.0.tgz#540572d34f7ac3119f8f76c30cbc1b1e037affbe" + dependencies: + builtin-modules "^1.0.0" + +is-directory@^0.3.1: + version "0.3.1" + resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1" + +is-dotfile@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1" + +is-equal-shallow@^0.1.3: + version "0.1.3" + resolved "https://registry.yarnpkg.com/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz#2238098fc221de0bcfa5d9eac4c45d638aa1c534" + dependencies: + is-primitive "^2.0.0" + +is-extendable@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + +is-extglob@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-1.0.0.tgz#ac468177c4943405a092fc8f29760c6ffc6206c0" + +is-extglob@^2.1.0: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + +is-finite@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.0.2.tgz#cc6677695602be550ef11e8b4aa6305342b6d0aa" + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + dependencies: + number-is-nan "^1.0.0" + +is-fullwidth-code-point@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + +is-glob@^2.0.0, is-glob@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-2.0.1.tgz#d096f926a3ded5600f3fdfd91198cb0888c2d863" + dependencies: + is-extglob "^1.0.0" + +is-glob@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" + dependencies: + is-extglob "^2.1.0" + +is-my-json-valid@^2.10.0: + version "2.16.0" + resolved "https://registry.yarnpkg.com/is-my-json-valid/-/is-my-json-valid-2.16.0.tgz#f079dd9bfdae65ee2038aae8acbc86ab109e3693" + dependencies: + generate-function "^2.0.0" + generate-object-property "^1.1.0" + jsonpointer "^4.0.0" + xtend "^4.0.0" + +is-number@^2.0.2, is-number@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-2.1.0.tgz#01fcbbb393463a548f2f466cce16dece49db908f" + dependencies: + kind-of "^3.0.2" + +is-path-cwd@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-path-cwd/-/is-path-cwd-1.0.0.tgz#d225ec23132e89edd38fda767472e62e65f1106d" + +is-path-in-cwd@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-path-in-cwd/-/is-path-in-cwd-1.0.0.tgz#6477582b8214d602346094567003be8a9eac04dc" + dependencies: + is-path-inside "^1.0.0" + +is-path-inside@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-1.0.0.tgz#fc06e5a1683fbda13de667aff717bbc10a48f37f" + dependencies: + path-is-inside "^1.0.1" + +is-plain-obj@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" + +is-plain-object@^2.0.1: + version "2.0.3" + resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.3.tgz#c15bf3e4b66b62d72efaf2925848663ecbc619b6" + dependencies: + isobject "^3.0.0" + +is-posix-bracket@^0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4" + +is-primitive@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" + +is-property@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" + +is-regexp@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069" + +is-relative@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-relative/-/is-relative-0.2.1.tgz#d27f4c7d516d175fb610db84bbeef23c3bc97aa5" + dependencies: + is-unc-path "^0.1.1" + +is-resolvable@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.0.0.tgz#8df57c61ea2e3c501408d100fb013cf8d6e0cc62" + dependencies: + tryit "^1.0.1" + +is-supported-regexp-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-supported-regexp-flag/-/is-supported-regexp-flag-1.0.0.tgz#8b520c85fae7a253382d4b02652e045576e13bb8" + +is-svg@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-svg/-/is-svg-2.1.0.tgz#cf61090da0d9efbcab8722deba6f032208dbb0e9" + dependencies: + html-comment-regex "^1.1.0" + +is-typedarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + +is-unc-path@^0.1.1: + version "0.1.2" + resolved "https://registry.yarnpkg.com/is-unc-path/-/is-unc-path-0.1.2.tgz#6ab053a72573c10250ff416a3814c35178af39b9" + dependencies: + unc-path-regex "^0.1.0" + +is-utf8@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" + +is-windows@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-0.2.0.tgz#de1aa6d63ea29dd248737b69f1ff8b8002d2108c" + +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-0.0.1.tgz#8a18acfca9a8f4177e09abfc6038939b05d1eedf" + +isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + +isobject@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + dependencies: + isarray "1.0.0" + +isobject@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.0.tgz#39565217f3661789e8a0a0c080d5f7e6bc46e1a0" + +isstream@~0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + +jodid25519@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/jodid25519/-/jodid25519-1.0.2.tgz#06d4912255093419477d425633606e0e90782967" + dependencies: + jsbn "~0.1.0" + +js-base64@^2.1.8, js-base64@^2.1.9: + version "2.1.9" + resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.1.9.tgz#f0e80ae039a4bd654b5f281fc93f04a914a7fcce" + +js-beautify@^1.6.3: + version "1.6.14" + resolved "https://registry.yarnpkg.com/js-beautify/-/js-beautify-1.6.14.tgz#d3b8f7322d02b9277d58bd238264c327e58044cd" + dependencies: + config-chain "~1.1.5" + editorconfig "^0.13.2" + mkdirp "~0.5.0" + nopt "~3.0.1" + +js-tokens@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.1.tgz#08e9f132484a2c45a30907e9dc4d5567b7f114d7" + +js-yaml@^3.4.3, js-yaml@^3.5.1: + version "3.8.4" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.8.4.tgz#520b4564f86573ba96662af85a8cafa7b4b5a6f6" + dependencies: + argparse "^1.0.7" + esprima "^3.1.1" + +js-yaml@~3.7.0: + version "3.7.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.7.0.tgz#5c967ddd837a9bfdca5f2de84253abe8a1c03b80" + dependencies: + argparse "^1.0.7" + esprima "^2.6.0" + +jsbn@~0.1.0: + version "0.1.1" + resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + +jsesc@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-1.3.0.tgz#46c3fec8c1892b12b0833db9bc7622176dbab34b" + +jsesc@~0.5.0: + version "0.5.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-0.5.0.tgz#e7dee66e35d6fc16f710fe91d5cf69f70f08911d" + +json-loader@^0.5.4: + version "0.5.4" + resolved "https://registry.yarnpkg.com/json-loader/-/json-loader-0.5.4.tgz#8baa1365a632f58a3c46d20175fc6002c96e37de" + +json-schema@0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + +json-stable-stringify@^1.0.0, json-stable-stringify@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz#9a759d39c5f2ff503fd5300646ed445f88c4f9af" + dependencies: + jsonify "~0.0.0" + +json-stringify-safe@~5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + +json5@^0.5.0, json5@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/json5/-/json5-0.5.1.tgz#1eade7acc012034ad84e2396767ead9fa5495821" + +jsonfile@^2.1.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" + optionalDependencies: + graceful-fs "^4.1.6" + +jsonfilter@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/jsonfilter/-/jsonfilter-1.1.2.tgz#21ef7cedc75193813c75932e96a98be205ba5a11" + dependencies: + JSONStream "^0.8.4" + minimist "^1.1.0" + stream-combiner "^0.2.1" + through2 "^0.6.3" + +jsonify@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/jsonify/-/jsonify-0.0.0.tgz#2c74b6ee41d93ca51b7b5aaee8f503631d252a73" + +jsonparse@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-0.0.5.tgz#330542ad3f0a654665b778f3eb2d9a9fa507ac64" + +jsonpointer@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/jsonpointer/-/jsonpointer-4.0.1.tgz#4fd92cb34e0e9db3c89c8622ecf51f9b978c6cb9" + +jsprim@^1.2.2: + version "1.4.0" + resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.0.tgz#a3b87e40298d8c380552d8cc7628a0bb95a22918" + dependencies: + assert-plus "1.0.0" + extsprintf "1.0.2" + json-schema "0.2.3" + verror "1.3.6" + +kind-of@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-2.0.1.tgz#018ec7a4ce7e3a86cb9141be519d24c8faa981b5" + dependencies: + is-buffer "^1.0.2" + +kind-of@^3.0.2: + version "3.2.2" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" + dependencies: + is-buffer "^1.1.5" + +klaw@^1.0.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/klaw/-/klaw-1.3.1.tgz#4088433b46b3b1ba259d78785d8e96f73ba02439" + optionalDependencies: + graceful-fs "^4.1.9" + +known-css-properties@^0.0.7: + version "0.0.7" + resolved "https://registry.yarnpkg.com/known-css-properties/-/known-css-properties-0.0.7.tgz#9104343a2adfd8ef3b07bdee7a325e4d44ed9371" + +lazy-cache@^0.2.3: + version "0.2.7" + resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-0.2.7.tgz#7feddf2dcb6edb77d11ef1d117ab5ffdf0ab1b65" + +lazy-cache@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" + +lcid@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/lcid/-/lcid-1.0.0.tgz#308accafa0bc483a3867b4b6f2b9506251d1b835" + dependencies: + invert-kv "^1.0.0" + +ldjson-stream@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ldjson-stream/-/ldjson-stream-1.2.1.tgz#91beceda5ac4ed2b17e649fb777e7abfa0189c2b" + dependencies: + split2 "^0.2.1" + through2 "^0.6.1" + +levn@^0.3.0, levn@~0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + dependencies: + prelude-ls "~1.1.2" + type-check "~0.3.2" + +linkify-it@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/linkify-it/-/linkify-it-2.0.3.tgz#d94a4648f9b1c179d64fa97291268bdb6ce9434f" + dependencies: + uc.micro "^1.0.1" + +load-json-file@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" + dependencies: + graceful-fs "^4.1.2" + parse-json "^2.2.0" + pify "^2.0.0" + pinkie-promise "^2.0.0" + strip-bom "^2.0.0" + +load-json-file@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-2.0.0.tgz#7947e42149af80d696cbf797bcaabcfe1fe29ca8" + dependencies: + graceful-fs "^4.1.2" + parse-json "^2.2.0" + pify "^2.0.0" + strip-bom "^3.0.0" + +loader-fs-cache@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/loader-fs-cache/-/loader-fs-cache-1.0.1.tgz#56e0bf08bd9708b26a765b68509840c8dec9fdbc" + dependencies: + find-cache-dir "^0.1.1" + mkdirp "0.5.1" + +loader-runner@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.3.0.tgz#f482aea82d543e07921700d5a46ef26fdac6b8a2" + +loader-utils@^0.2.15, loader-utils@^0.2.16: + version "0.2.17" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-0.2.17.tgz#f86e6374d43205a6e6c60e9196f17c0299bfb348" + dependencies: + big.js "^3.1.3" + emojis-list "^2.0.0" + json5 "^0.5.0" + object-assign "^4.0.1" + +loader-utils@^1.0.1, loader-utils@^1.0.2, loader-utils@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.1.0.tgz#c98aef488bcceda2ffb5e2de646d6a754429f5cd" + dependencies: + big.js "^3.1.3" + emojis-list "^2.0.0" + json5 "^0.5.0" + +locate-path@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" + dependencies: + p-locate "^2.0.0" + path-exists "^3.0.0" + +lodash._baseget@^3.0.0: + version "3.7.2" + resolved "https://registry.yarnpkg.com/lodash._baseget/-/lodash._baseget-3.7.2.tgz#1b6ae1d5facf3c25532350a13c1197cb8bb674f4" + +lodash._topath@^3.0.0: + version "3.8.1" + resolved "https://registry.yarnpkg.com/lodash._topath/-/lodash._topath-3.8.1.tgz#3ec5e2606014f4cb97f755fe6914edd8bfc00eac" + dependencies: + lodash.isarray "^3.0.0" + +lodash.assign@^4.2.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7" + +lodash.camelcase@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" + +lodash.clonedeep@^4.3.2: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" + +lodash.cond@^4.3.0: + version "4.5.2" + resolved "https://registry.yarnpkg.com/lodash.cond/-/lodash.cond-4.5.2.tgz#f471a1da486be60f6ab955d17115523dd1d255d5" + +lodash.get@^3.7.0: + version "3.7.0" + resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-3.7.0.tgz#3ce68ae2c91683b281cc5394128303cbf75e691f" + dependencies: + lodash._baseget "^3.0.0" + lodash._topath "^3.0.0" + +lodash.isarray@^3.0.0: + version "3.0.4" + resolved "https://registry.yarnpkg.com/lodash.isarray/-/lodash.isarray-3.0.4.tgz#79e4eb88c36a8122af86f844aa9bcd851b5fbb55" + +lodash.memoize@^4.1.2: + version "4.1.2" + resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" + +lodash.mergewith@^4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.0.tgz#150cf0a16791f5903b8891eab154609274bdea55" + +lodash.tail@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/lodash.tail/-/lodash.tail-4.1.1.tgz#d2333a36d9e7717c8ad2f7cacafec7c32b444664" + +lodash.uniq@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" + +lodash@^4.0.0, lodash@^4.1.0, lodash@^4.14.0, lodash@^4.17.2, lodash@^4.17.3, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.3.0: + version "4.17.4" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.4.tgz#78203a4d1c328ae1d86dca6460e369b57f4055ae" + +lodash@~4.16.4: + version "4.16.6" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.16.6.tgz#d22c9ac660288f3843e16ba7d2b5d06cca27d777" + +log-symbols@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-1.0.2.tgz#376ff7b58ea3086a0f09facc74617eca501e1a18" + dependencies: + chalk "^1.0.0" + +longest@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/longest/-/longest-1.0.1.tgz#30a0b2da38f73770e8294a0d22e6625ed77d0097" + +loose-envify@^1.0.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.3.1.tgz#d1a8ad33fa9ce0e713d65fdd0ac8b748d478c848" + dependencies: + js-tokens "^3.0.0" + +loud-rejection@^1.0.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" + dependencies: + currently-unhandled "^0.4.1" + signal-exit "^3.0.0" + +lower-case@^1.1.1: + version "1.1.4" + resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-1.1.4.tgz#9a2cabd1b9e8e0ae993a4bf7d5875c39c42e8eac" + +lru-cache@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-3.2.0.tgz#71789b3b7f5399bec8565dda38aa30d2a097efee" + dependencies: + pseudomap "^1.0.1" + +lru-cache@^4.0.1: + version "4.0.2" + resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.0.2.tgz#1d17679c069cda5d040991a09dbc2c0db377e55e" + dependencies: + pseudomap "^1.0.1" + yallist "^2.0.0" + +macaddress@^0.2.8: + version "0.2.8" + resolved "https://registry.yarnpkg.com/macaddress/-/macaddress-0.2.8.tgz#5904dc537c39ec6dbefeae902327135fa8511f12" + +map-obj@^1.0.0, map-obj@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" + +markdown-it-abbr@^1.0.4: + version "1.0.4" + resolved "https://registry.yarnpkg.com/markdown-it-abbr/-/markdown-it-abbr-1.0.4.tgz#d66b5364521cbb3dd8aa59dadfba2fb6865c8fd8" + +markdown-it-deflist@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/markdown-it-deflist/-/markdown-it-deflist-2.0.2.tgz#33253190400dfa5398bef9d0adacac0d0676bc58" + +markdown-it-emoji@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/markdown-it-emoji/-/markdown-it-emoji-1.3.0.tgz#903ae1a9968c3f17d4e142f115d4ec575e56d2cb" + +markdown-it-footnote@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/markdown-it-footnote/-/markdown-it-footnote-3.0.1.tgz#7f3730747cacc86e2fe0bf8a17a710f34791517a" + +markdown-it-mathjax@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/markdown-it-mathjax/-/markdown-it-mathjax-2.0.0.tgz#ae2b4f4c5c719a03f9e475c664f7b2685231d9e9" + +markdown-it-pandoc-renderer@1.1.3: + version "1.1.3" + resolved "https://registry.yarnpkg.com/markdown-it-pandoc-renderer/-/markdown-it-pandoc-renderer-1.1.3.tgz#77f1a5b488c5460ab1e1dcbcfcc07d12674f7a3a" + +markdown-it-sub@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/markdown-it-sub/-/markdown-it-sub-1.0.0.tgz#375fd6026eae7ddcb012497f6411195ea1e3afe8" + +markdown-it-sup@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/markdown-it-sup/-/markdown-it-sup-1.0.0.tgz#cb9c9ff91a5255ac08f3fd3d63286e15df0a1fc3" + +markdown-it@^8.3.1: + version "8.3.1" + resolved "https://registry.yarnpkg.com/markdown-it/-/markdown-it-8.3.1.tgz#2f4b622948ccdc193d66f3ca2d43125ac4ac7323" + dependencies: + argparse "^1.0.7" + entities "~1.1.1" + linkify-it "^2.0.0" + mdurl "^1.0.1" + uc.micro "^1.0.3" + +math-expression-evaluator@^1.2.14: + version "1.2.17" + resolved "https://registry.yarnpkg.com/math-expression-evaluator/-/math-expression-evaluator-1.2.17.tgz#de819fdbcd84dccd8fae59c6aeb79615b9d266ac" + +mdurl@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e" + +media-typer@0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" + +memory-fs@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.2.0.tgz#f2bb25368bc121e391c2520de92969caee0a0290" + +memory-fs@^0.4.0, memory-fs@~0.4.1: + version "0.4.1" + resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" + dependencies: + errno "^0.1.3" + readable-stream "^2.0.1" + +meow@^3.3.0, meow@^3.7.0: + version "3.7.0" + resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb" + dependencies: + camelcase-keys "^2.0.0" + decamelize "^1.1.2" + loud-rejection "^1.0.0" + map-obj "^1.0.1" + minimist "^1.1.3" + normalize-package-data "^2.3.4" + object-assign "^4.0.1" + read-pkg-up "^1.0.1" + redent "^1.0.0" + trim-newlines "^1.0.0" + +merge-descriptors@1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" + +methods@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" + +micromatch@^2.1.5, micromatch@^2.3.11: + version "2.3.11" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-2.3.11.tgz#86677c97d1720b363431d04d0d15293bd38c1565" + dependencies: + arr-diff "^2.0.0" + array-unique "^0.2.1" + braces "^1.8.2" + expand-brackets "^0.1.4" + extglob "^0.3.1" + filename-regex "^2.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.1" + kind-of "^3.0.2" + normalize-path "^2.0.1" + object.omit "^2.0.0" + parse-glob "^3.0.4" + regex-cache "^0.4.2" + +miller-rabin@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.0.tgz#4a62fb1d42933c05583982f4c716f6fb9e6c6d3d" + dependencies: + bn.js "^4.0.0" + brorand "^1.0.1" + +mime-db@~1.27.0: + version "1.27.0" + resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.27.0.tgz#820f572296bbd20ec25ed55e5b5de869e5436eb1" + +mime-types@^2.1.12, mime-types@~2.1.11, mime-types@~2.1.15, mime-types@~2.1.7: + version "2.1.15" + resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.15.tgz#a4ebf5064094569237b8cf70046776d09fc92aed" + dependencies: + mime-db "~1.27.0" + +mime@1.3.4: + version "1.3.4" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53" + +mime@1.3.x, mime@^1.3.4: + version "1.3.6" + resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.6.tgz#591d84d3653a6b0b4a3b9df8de5aa8108e72e5e0" + +mimic-fn@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.1.0.tgz#e667783d92e89dbd342818b5230b9d62a672ad18" + +minimalistic-assert@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz#702be2dda6b37f4836bcb3f5db56641b64a1d3d3" + +minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + +"minimatch@2 || 3", minimatch@^3.0.0, minimatch@^3.0.2, minimatch@^3.0.3, minimatch@^3.0.4, minimatch@~3.0.2: + version "3.0.4" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + dependencies: + brace-expansion "^1.1.7" + +minimist@0.0.8: + version "0.0.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" + +minimist@^1.1.0, minimist@^1.1.3, minimist@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.0.tgz#a35008b20f41383eec1fb914f4cd5df79a264284" + +mixin-object@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/mixin-object/-/mixin-object-2.0.1.tgz#4fb949441dab182540f1fe035ba60e1947a5e57e" + dependencies: + for-in "^0.1.3" + is-extendable "^0.1.1" + +mkdirp@0.5.1, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@~0.5.0, mkdirp@~0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" + dependencies: + minimist "0.0.8" + +ms@0.7.1: + version "0.7.1" + resolved "https://registry.yarnpkg.com/ms/-/ms-0.7.1.tgz#9cd13c03adbff25b65effde7ce864ee952017098" + +ms@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + +multimatch@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/multimatch/-/multimatch-2.1.0.tgz#9c7906a22fb4c02919e2f5f75161b4cdbd4b2a2b" + dependencies: + array-differ "^1.0.0" + array-union "^1.0.1" + arrify "^1.0.0" + minimatch "^3.0.0" + +mute-stream@0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0" + +nan@^2.3.0, nan@^2.3.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.6.2.tgz#e4ff34e6c95fdfb5aecc08de6596f43605a7db45" + +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + +ncname@1.0.x: + version "1.0.0" + resolved "https://registry.yarnpkg.com/ncname/-/ncname-1.0.0.tgz#5b57ad18b1ca092864ef62b0b1ed8194f383b71c" + dependencies: + xml-char-classes "^1.0.0" + +negotiator@0.6.1: + version "0.6.1" + resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.1.tgz#2b327184e8992101177b28563fb5e7102acd0ca9" + +no-case@^2.2.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/no-case/-/no-case-2.3.1.tgz#7aeba1c73a52184265554b7dc03baf720df80081" + dependencies: + lower-case "^1.1.1" + +node-dir@^0.1.10: + version "0.1.17" + resolved "https://registry.yarnpkg.com/node-dir/-/node-dir-0.1.17.tgz#5f5665d93351335caabef8f1c554516cf5f1e4e5" + dependencies: + minimatch "^3.0.2" + +node-gyp@^3.3.1: + version "3.6.2" + resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-3.6.2.tgz#9bfbe54562286284838e750eac05295853fa1c60" + dependencies: + fstream "^1.0.0" + glob "^7.0.3" + graceful-fs "^4.1.2" + minimatch "^3.0.2" + mkdirp "^0.5.0" + nopt "2 || 3" + npmlog "0 || 1 || 2 || 3 || 4" + osenv "0" + request "2" + rimraf "2" + semver "~5.3.0" + tar "^2.0.0" + which "1" + +node-libs-browser@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-1.1.1.tgz#2a38243abedd7dffcd07a97c9aca5668975a6fea" + dependencies: + assert "^1.1.1" + browserify-zlib "^0.1.4" + buffer "^4.3.0" + console-browserify "^1.1.0" + constants-browserify "^1.0.0" + crypto-browserify "^3.11.0" + domain-browser "^1.1.1" + events "^1.0.0" + https-browserify "0.0.1" + os-browserify "^0.2.0" + path-browserify "0.0.0" + process "^0.11.0" + punycode "^1.2.4" + querystring-es3 "^0.2.0" + readable-stream "^2.0.5" + stream-browserify "^2.0.1" + stream-http "^2.3.1" + string_decoder "^0.10.25" + timers-browserify "^1.4.2" + tty-browserify "0.0.0" + url "^0.11.0" + util "^0.10.3" + vm-browserify "0.0.4" + +node-libs-browser@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.0.0.tgz#a3a59ec97024985b46e958379646f96c4b616646" + dependencies: + assert "^1.1.1" + browserify-zlib "^0.1.4" + buffer "^4.3.0" + console-browserify "^1.1.0" + constants-browserify "^1.0.0" + crypto-browserify "^3.11.0" + domain-browser "^1.1.1" + events "^1.0.0" + https-browserify "0.0.1" + os-browserify "^0.2.0" + path-browserify "0.0.0" + process "^0.11.0" + punycode "^1.2.4" + querystring-es3 "^0.2.0" + readable-stream "^2.0.5" + stream-browserify "^2.0.1" + stream-http "^2.3.1" + string_decoder "^0.10.25" + timers-browserify "^2.0.2" + tty-browserify "0.0.0" + url "^0.11.0" + util "^0.10.3" + vm-browserify "0.0.4" + +node-pre-gyp@^0.6.29: + version "0.6.36" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.6.36.tgz#db604112cb74e0d477554e9b505b17abddfab786" + dependencies: + mkdirp "^0.5.1" + nopt "^4.0.1" + npmlog "^4.0.2" + rc "^1.1.7" + request "^2.81.0" + rimraf "^2.6.1" + semver "^5.3.0" + tar "^2.2.1" + tar-pack "^3.4.0" + +node-sass@^4.5.3: + version "4.5.3" + resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.5.3.tgz#d09c9d1179641239d1b97ffc6231fdcec53e1568" + dependencies: + async-foreach "^0.1.3" + chalk "^1.1.1" + cross-spawn "^3.0.0" + gaze "^1.0.0" + get-stdin "^4.0.1" + glob "^7.0.3" + in-publish "^2.0.0" + lodash.assign "^4.2.0" + lodash.clonedeep "^4.3.2" + lodash.mergewith "^4.6.0" + meow "^3.7.0" + mkdirp "^0.5.1" + nan "^2.3.2" + node-gyp "^3.3.1" + npmlog "^4.0.0" + request "^2.79.0" + sass-graph "^2.1.1" + stdout-stream "^1.4.0" + +"nopt@2 || 3", nopt@~3.0.1: + version "3.0.6" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" + dependencies: + abbrev "1" + +nopt@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d" + dependencies: + abbrev "1" + osenv "^0.1.4" + +normalize-package-data@^2.3.2, normalize-package-data@^2.3.4: + version "2.3.8" + resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.3.8.tgz#d819eda2a9dedbd1ffa563ea4071d936782295bb" + dependencies: + hosted-git-info "^2.1.4" + is-builtin-module "^1.0.0" + semver "2 || 3 || 4 || 5" + validate-npm-package-license "^3.0.1" + +normalize-path@^2.0.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + dependencies: + remove-trailing-separator "^1.0.1" + +normalize-range@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/normalize-range/-/normalize-range-0.1.2.tgz#2d10c06bdfd312ea9777695a4d28439456b75942" + +normalize-scss@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/normalize-scss/-/normalize-scss-7.0.0.tgz#92eaac6554cc376336c06682a0d6a2099bbb0889" + +normalize-selector@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/normalize-selector/-/normalize-selector-0.2.0.tgz#d0b145eb691189c63a78d201dc4fdb1293ef0c03" + +normalize-url@^1.4.0: + version "1.9.1" + resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-1.9.1.tgz#2cc0d66b31ea23036458436e3620d85954c66c3c" + dependencies: + object-assign "^4.0.1" + prepend-http "^1.0.0" + query-string "^4.1.0" + sort-keys "^1.0.0" + +"npmlog@0 || 1 || 2 || 3 || 4", npmlog@^4.0.0, npmlog@^4.0.2: + version "4.1.0" + resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.0.tgz#dc59bee85f64f00ed424efb2af0783df25d1c0b5" + dependencies: + are-we-there-yet "~1.1.2" + console-control-strings "~1.1.0" + gauge "~2.7.3" + set-blocking "~2.0.0" + +nth-check@~1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-1.0.1.tgz#9929acdf628fc2c41098deab82ac580cf149aae4" + dependencies: + boolbase "~1.0.0" + +num2fraction@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/num2fraction/-/num2fraction-1.2.2.tgz#6f682b6a027a4e9ddfa4564cd2589d1d4e669ede" + +number-is-nan@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + +oauth-sign@~0.8.1: + version "0.8.2" + resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43" + +object-assign@^4.0.1, object-assign@^4.1.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + +object-hash@^1.1.4: + version "1.1.8" + resolved "https://registry.yarnpkg.com/object-hash/-/object-hash-1.1.8.tgz#28a659cf987d96a4dabe7860289f3b5326c4a03c" + +object.omit@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/object.omit/-/object.omit-2.0.1.tgz#1a9c744829f39dbb858c76ca3579ae2a54ebd1fa" + dependencies: + for-own "^0.1.4" + is-extendable "^0.1.1" + +on-finished@~2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" + dependencies: + ee-first "1.1.1" + +once@^1.3.0, once@^1.3.3: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + dependencies: + wrappy "1" + +onecolor@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/onecolor/-/onecolor-3.0.4.tgz#75a46f80da6c7aaa5b4daae17a47198bd9652494" + +onetime@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-1.1.0.tgz#a1f7838f8314c516f05ecefcbc4ccfe04b4ed789" + +onetime@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" + dependencies: + mimic-fn "^1.0.0" + +opener@^1.4.3: + version "1.4.3" + resolved "https://registry.yarnpkg.com/opener/-/opener-1.4.3.tgz#5c6da2c5d7e5831e8ffa3964950f8d6674ac90b8" + +opn@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/opn/-/opn-4.0.2.tgz#7abc22e644dff63b0a96d5ab7f2790c0f01abc95" + dependencies: + object-assign "^4.0.1" + pinkie-promise "^2.0.0" + +optimize-css-assets-webpack-plugin@^1.3.0: + version "1.3.2" + resolved "https://registry.yarnpkg.com/optimize-css-assets-webpack-plugin/-/optimize-css-assets-webpack-plugin-1.3.2.tgz#eb27456e21eefbd8080f31e8368c59684e585a2c" + dependencies: + cssnano "^3.4.0" + underscore "^1.8.3" + webpack-sources "^0.1.0" + +optionator@^0.8.2: + version "0.8.2" + resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.2.tgz#364c5e409d3f4d6301d6c0b4c05bba50180aeb64" + dependencies: + deep-is "~0.1.3" + fast-levenshtein "~2.0.4" + levn "~0.3.0" + prelude-ls "~1.1.2" + type-check "~0.3.2" + wordwrap "~1.0.0" + +ora@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/ora/-/ora-1.2.0.tgz#32fb3183500efe83f5ea89101785f0ee6060fec9" + dependencies: + chalk "^1.1.1" + cli-cursor "^2.1.0" + cli-spinners "^1.0.0" + log-symbols "^1.0.2" + +os-browserify@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.2.1.tgz#63fc4ccee5d2d7763d26bbf8601078e6c2e0044f" + +os-homedir@^1.0.0, os-homedir@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + +os-locale@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/os-locale/-/os-locale-1.4.0.tgz#20f9f17ae29ed345e8bde583b13d2009803c14d9" + dependencies: + lcid "^1.0.0" + +os-tmpdir@^1.0.0, os-tmpdir@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + +osenv@0, osenv@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.4.tgz#42fe6d5953df06c8064be6f176c3d05aaaa34644" + dependencies: + os-homedir "^1.0.0" + os-tmpdir "^1.0.0" + +p-limit@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.1.0.tgz#b07ff2d9a5d88bec806035895a2bab66a27988bc" + +p-locate@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" + dependencies: + p-limit "^1.1.0" + +pako@~0.2.0: + version "0.2.9" + resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75" + +param-case@2.1.x: + version "2.1.1" + resolved "https://registry.yarnpkg.com/param-case/-/param-case-2.1.1.tgz#df94fd8cf6531ecf75e6bef9a0858fbc72be2247" + dependencies: + no-case "^2.2.0" + +parse-asn1@^5.0.0: + version "5.1.0" + resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.0.tgz#37c4f9b7ed3ab65c74817b5f2480937fbf97c712" + dependencies: + asn1.js "^4.0.0" + browserify-aes "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.0" + pbkdf2 "^3.0.3" + +parse-glob@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" + dependencies: + glob-base "^0.3.0" + is-dotfile "^1.0.0" + is-extglob "^1.0.0" + is-glob "^2.0.0" + +parse-json@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" + dependencies: + error-ex "^1.2.0" + +parseurl@~1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.1.tgz#c8ab8c9223ba34888aa64a297b28853bec18da56" + +path-browserify@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.0.tgz#a0b870729aae214005b7d5032ec2cbbb0fb4451a" + +path-exists@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" + dependencies: + pinkie-promise "^2.0.0" + +path-exists@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + +path-is-inside@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-is-inside/-/path-is-inside-1.0.2.tgz#365417dede44430d1c11af61027facf074bdfc53" + +path-parse@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.5.tgz#3c1adf871ea9cd6c9431b6ea2bd74a0ff055c4c1" + +path-to-regexp@0.1.7: + version "0.1.7" + resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" + +path-type@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" + dependencies: + graceful-fs "^4.1.2" + pify "^2.0.0" + pinkie-promise "^2.0.0" + +path-type@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/path-type/-/path-type-2.0.0.tgz#f012ccb8415b7096fc2daa1054c3d72389594c73" + dependencies: + pify "^2.0.0" + +pbkdf2@^3.0.3: + version "3.0.12" + resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.12.tgz#be36785c5067ea48d806ff923288c5f750b6b8a2" + dependencies: + create-hash "^1.1.2" + create-hmac "^1.1.4" + ripemd160 "^2.0.1" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +performance-now@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-0.2.0.tgz#33ef30c5c77d4ea21c5a53869d91b56d8f2555e5" + +pify@^2.0.0, pify@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" + +pinkie-promise@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" + dependencies: + pinkie "^2.0.0" + +pinkie@^2.0.0: + version "2.0.4" + resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" + +pipetteur@^2.0.0: + version "2.0.3" + resolved "https://registry.yarnpkg.com/pipetteur/-/pipetteur-2.0.3.tgz#1955760959e8d1a11cb2a50ec83eec470633e49f" + dependencies: + onecolor "^3.0.4" + synesthesia "^1.0.1" + +pkg-dir@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-1.0.0.tgz#7a4b508a8d5bb2d629d447056ff4e9c9314cf3d4" + dependencies: + find-up "^1.0.0" + +plur@^2.0.0, plur@^2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/plur/-/plur-2.1.2.tgz#7482452c1a0f508e3e344eaec312c91c29dc655a" + dependencies: + irregular-plurals "^1.0.0" + +pluralize@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/pluralize/-/pluralize-1.2.1.tgz#d1a21483fd22bb41e58a12fa3421823140897c45" + +postcss-calc@^5.2.0: + version "5.3.1" + resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-5.3.1.tgz#77bae7ca928ad85716e2fda42f261bf7c1d65b5e" + dependencies: + postcss "^5.0.2" + postcss-message-helpers "^2.0.0" + reduce-css-calc "^1.2.6" + +postcss-colormin@^2.1.8: + version "2.2.2" + resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-2.2.2.tgz#6631417d5f0e909a3d7ec26b24c8a8d1e4f96e4b" + dependencies: + colormin "^1.0.5" + postcss "^5.0.13" + postcss-value-parser "^3.2.3" + +postcss-convert-values@^2.3.4: + version "2.6.1" + resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-2.6.1.tgz#bbd8593c5c1fd2e3d1c322bb925dcae8dae4d62d" + dependencies: + postcss "^5.0.11" + postcss-value-parser "^3.1.2" + +postcss-discard-comments@^2.0.4: + version "2.0.4" + resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-2.0.4.tgz#befe89fafd5b3dace5ccce51b76b81514be00e3d" + dependencies: + postcss "^5.0.14" + +postcss-discard-duplicates@^2.0.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-2.1.0.tgz#b9abf27b88ac188158a5eb12abcae20263b91932" + dependencies: + postcss "^5.0.4" + +postcss-discard-empty@^2.0.1: + version "2.1.0" + resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-2.1.0.tgz#d2b4bd9d5ced5ebd8dcade7640c7d7cd7f4f92b5" + dependencies: + postcss "^5.0.14" + +postcss-discard-overridden@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-0.1.1.tgz#8b1eaf554f686fb288cd874c55667b0aa3668d58" + dependencies: + postcss "^5.0.16" + +postcss-discard-unused@^2.2.1: + version "2.2.3" + resolved "https://registry.yarnpkg.com/postcss-discard-unused/-/postcss-discard-unused-2.2.3.tgz#bce30b2cc591ffc634322b5fb3464b6d934f4433" + dependencies: + postcss "^5.0.14" + uniqs "^2.0.0" + +postcss-filter-plugins@^2.0.0: + version "2.0.2" + resolved "https://registry.yarnpkg.com/postcss-filter-plugins/-/postcss-filter-plugins-2.0.2.tgz#6d85862534d735ac420e4a85806e1f5d4286d84c" + dependencies: + postcss "^5.0.4" + uniqid "^4.0.0" + +postcss-less@^0.14.0: + version "0.14.0" + resolved "https://registry.yarnpkg.com/postcss-less/-/postcss-less-0.14.0.tgz#c631b089c6cce422b9a10f3a958d2bedd3819324" + dependencies: + postcss "^5.0.21" + +postcss-load-config@^1.1.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/postcss-load-config/-/postcss-load-config-1.2.0.tgz#539e9afc9ddc8620121ebf9d8c3673e0ce50d28a" + dependencies: + cosmiconfig "^2.1.0" + object-assign "^4.1.0" + postcss-load-options "^1.2.0" + postcss-load-plugins "^2.3.0" + +postcss-load-options@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/postcss-load-options/-/postcss-load-options-1.2.0.tgz#b098b1559ddac2df04bc0bb375f99a5cfe2b6d8c" + dependencies: + cosmiconfig "^2.1.0" + object-assign "^4.1.0" + +postcss-load-plugins@^2.3.0: + version "2.3.0" + resolved "https://registry.yarnpkg.com/postcss-load-plugins/-/postcss-load-plugins-2.3.0.tgz#745768116599aca2f009fad426b00175049d8d92" + dependencies: + cosmiconfig "^2.1.1" + object-assign "^4.1.0" + +postcss-media-query-parser@^0.2.0: + version "0.2.3" + resolved "https://registry.yarnpkg.com/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz#27b39c6f4d94f81b1a73b8f76351c609e5cef244" + +postcss-merge-idents@^2.1.5: + version "2.1.7" + resolved "https://registry.yarnpkg.com/postcss-merge-idents/-/postcss-merge-idents-2.1.7.tgz#4c5530313c08e1d5b3bbf3d2bbc747e278eea270" + dependencies: + has "^1.0.1" + postcss "^5.0.10" + postcss-value-parser "^3.1.1" + +postcss-merge-longhand@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-2.0.2.tgz#23d90cd127b0a77994915332739034a1a4f3d658" + dependencies: + postcss "^5.0.4" + +postcss-merge-rules@^2.0.3: + version "2.1.2" + resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-2.1.2.tgz#d1df5dfaa7b1acc3be553f0e9e10e87c61b5f721" + dependencies: + browserslist "^1.5.2" + caniuse-api "^1.5.2" + postcss "^5.0.4" + postcss-selector-parser "^2.2.2" + vendors "^1.0.0" + +postcss-message-helpers@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/postcss-message-helpers/-/postcss-message-helpers-2.0.0.tgz#a4f2f4fab6e4fe002f0aed000478cdf52f9ba60e" + +postcss-minify-font-values@^1.0.2: + version "1.0.5" + resolved "https://registry.yarnpkg.com/postcss-minify-font-values/-/postcss-minify-font-values-1.0.5.tgz#4b58edb56641eba7c8474ab3526cafd7bbdecb69" + dependencies: + object-assign "^4.0.1" + postcss "^5.0.4" + postcss-value-parser "^3.0.2" + +postcss-minify-gradients@^1.0.1: + version "1.0.5" + resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-1.0.5.tgz#5dbda11373703f83cfb4a3ea3881d8d75ff5e6e1" + dependencies: + postcss "^5.0.12" + postcss-value-parser "^3.3.0" + +postcss-minify-params@^1.0.4: + version "1.2.2" + resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-1.2.2.tgz#ad2ce071373b943b3d930a3fa59a358c28d6f1f3" + dependencies: + alphanum-sort "^1.0.1" + postcss "^5.0.2" + postcss-value-parser "^3.0.2" + uniqs "^2.0.0" + +postcss-minify-selectors@^2.0.4: + version "2.1.1" + resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-2.1.1.tgz#b2c6a98c0072cf91b932d1a496508114311735bf" + dependencies: + alphanum-sort "^1.0.2" + has "^1.0.1" + postcss "^5.0.14" + postcss-selector-parser "^2.0.0" + +postcss-modules-extract-imports@^1.0.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-1.2.0.tgz#66140ecece38ef06bf0d3e355d69bf59d141ea85" + dependencies: + postcss "^6.0.1" + +postcss-modules-local-by-default@^1.0.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-1.2.0.tgz#f7d80c398c5a393fa7964466bd19500a7d61c069" + dependencies: + css-selector-tokenizer "^0.7.0" + postcss "^6.0.1" + +postcss-modules-scope@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-1.1.0.tgz#d6ea64994c79f97b62a72b426fbe6056a194bb90" + dependencies: + css-selector-tokenizer "^0.7.0" + postcss "^6.0.1" + +postcss-modules-values@^1.1.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-1.3.0.tgz#ecffa9d7e192518389f42ad0e83f72aec456ea20" + dependencies: + icss-replace-symbols "^1.1.0" + postcss "^6.0.1" + +postcss-normalize-charset@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-1.1.1.tgz#ef9ee71212d7fe759c78ed162f61ed62b5cb93f1" + dependencies: + postcss "^5.0.5" + +postcss-normalize-url@^3.0.7: + version "3.0.8" + resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-3.0.8.tgz#108f74b3f2fcdaf891a2ffa3ea4592279fc78222" + dependencies: + is-absolute-url "^2.0.0" + normalize-url "^1.4.0" + postcss "^5.0.14" + postcss-value-parser "^3.2.3" + +postcss-ordered-values@^2.1.0: + version "2.2.3" + resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-2.2.3.tgz#eec6c2a67b6c412a8db2042e77fe8da43f95c11d" + dependencies: + postcss "^5.0.4" + postcss-value-parser "^3.0.1" + +postcss-reduce-idents@^2.2.2: + version "2.4.0" + resolved "https://registry.yarnpkg.com/postcss-reduce-idents/-/postcss-reduce-idents-2.4.0.tgz#c2c6d20cc958284f6abfbe63f7609bf409059ad3" + dependencies: + postcss "^5.0.4" + postcss-value-parser "^3.0.2" + +postcss-reduce-initial@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-1.0.1.tgz#68f80695f045d08263a879ad240df8dd64f644ea" + dependencies: + postcss "^5.0.4" + +postcss-reduce-transforms@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-1.0.4.tgz#ff76f4d8212437b31c298a42d2e1444025771ae1" + dependencies: + has "^1.0.1" + postcss "^5.0.8" + postcss-value-parser "^3.0.1" + +postcss-reporter@^1.2.1, postcss-reporter@^1.3.3: + version "1.4.1" + resolved "https://registry.yarnpkg.com/postcss-reporter/-/postcss-reporter-1.4.1.tgz#c136f0a5b161915f379dd3765c61075f7e7b9af2" + dependencies: + chalk "^1.0.0" + lodash "^4.1.0" + log-symbols "^1.0.2" + postcss "^5.0.0" + +postcss-reporter@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/postcss-reporter/-/postcss-reporter-3.0.0.tgz#09ea0f37a444c5693878606e09b018ebeff7cf8f" + dependencies: + chalk "^1.0.0" + lodash "^4.1.0" + log-symbols "^1.0.2" + postcss "^5.0.0" + +postcss-resolve-nested-selector@^0.1.1: + version "0.1.1" + resolved "https://registry.yarnpkg.com/postcss-resolve-nested-selector/-/postcss-resolve-nested-selector-0.1.1.tgz#29ccbc7c37dedfac304e9fff0bf1596b3f6a0e4e" + +postcss-scss@^0.4.0: + version "0.4.1" + resolved "https://registry.yarnpkg.com/postcss-scss/-/postcss-scss-0.4.1.tgz#ad771b81f0f72f5f4845d08aa60f93557653d54c" + dependencies: + postcss "^5.2.13" + +postcss-selector-parser@^2.0.0, postcss-selector-parser@^2.1.1, postcss-selector-parser@^2.2.2: + version "2.2.3" + resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-2.2.3.tgz#f9437788606c3c9acee16ffe8d8b16297f27bb90" + dependencies: + flatten "^1.0.2" + indexes-of "^1.0.1" + uniq "^1.0.1" + +postcss-svgo@^2.1.1: + version "2.1.6" + resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-2.1.6.tgz#b6df18aa613b666e133f08adb5219c2684ac108d" + dependencies: + is-svg "^2.0.0" + postcss "^5.0.14" + postcss-value-parser "^3.2.3" + svgo "^0.7.0" + +postcss-unique-selectors@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-2.0.2.tgz#981d57d29ddcb33e7b1dfe1fd43b8649f933ca1d" + dependencies: + alphanum-sort "^1.0.1" + postcss "^5.0.4" + uniqs "^2.0.0" + +postcss-value-parser@^3.0.1, postcss-value-parser@^3.0.2, postcss-value-parser@^3.1.1, postcss-value-parser@^3.1.2, postcss-value-parser@^3.2.3, postcss-value-parser@^3.3.0: + version "3.3.0" + resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-3.3.0.tgz#87f38f9f18f774a4ab4c8a232f5c5ce8872a9d15" + +postcss-zindex@^2.0.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/postcss-zindex/-/postcss-zindex-2.2.0.tgz#d2109ddc055b91af67fc4cb3b025946639d2af22" + dependencies: + has "^1.0.1" + postcss "^5.0.4" + uniqs "^2.0.0" + +postcss@^5.0.0, postcss@^5.0.10, postcss@^5.0.11, postcss@^5.0.12, postcss@^5.0.13, postcss@^5.0.14, postcss@^5.0.16, postcss@^5.0.18, postcss@^5.0.2, postcss@^5.0.20, postcss@^5.0.21, postcss@^5.0.4, postcss@^5.0.5, postcss@^5.0.6, postcss@^5.0.8, postcss@^5.2.13, postcss@^5.2.16, postcss@^5.2.4: + version "5.2.17" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-5.2.17.tgz#cf4f597b864d65c8a492b2eabe9d706c879c388b" + dependencies: + chalk "^1.1.3" + js-base64 "^2.1.9" + source-map "^0.5.6" + supports-color "^3.2.3" + +postcss@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/postcss/-/postcss-6.0.1.tgz#000dbd1f8eef217aa368b9a212c5fc40b2a8f3f2" + dependencies: + chalk "^1.1.3" + source-map "^0.5.6" + supports-color "^3.2.3" + +prelude-ls@~1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + +prepend-http@^1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc" + +preserve@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/preserve/-/preserve-0.2.0.tgz#815ed1f6ebc65926f865b310c0713bcb3315ce4b" + +pretty-error@^2.0.2: + version "2.1.0" + resolved "https://registry.yarnpkg.com/pretty-error/-/pretty-error-2.1.0.tgz#87f4e9d706a24c87d6cbee9fabec001fcf8c75d8" + dependencies: + renderkid "^2.0.1" + utila "~0.4" + +prismjs@^1.6.0: + version "1.6.0" + resolved "https://registry.yarnpkg.com/prismjs/-/prismjs-1.6.0.tgz#118d95fb7a66dba2272e343b345f5236659db365" + optionalDependencies: + clipboard "^1.5.5" + +private@^0.1.6: + version "0.1.7" + resolved "https://registry.yarnpkg.com/private/-/private-0.1.7.tgz#68ce5e8a1ef0a23bb570cc28537b5332aba63ef1" + +process-nextick-args@~1.0.6: + version "1.0.7" + resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-1.0.7.tgz#150e20b756590ad3f91093f25a4f2ad8bff30ba3" + +process@^0.11.0, process@~0.11.0: + version "0.11.10" + resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + +progress@^1.1.8: + version "1.1.8" + resolved "https://registry.yarnpkg.com/progress/-/progress-1.1.8.tgz#e260c78f6161cdd9b0e56cc3e0a85de17c7a57be" + +proto-list@~1.2.1: + version "1.2.4" + resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" + +proxy-addr@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-1.1.4.tgz#27e545f6960a44a627d9b44467e35c1b6b4ce2f3" + dependencies: + forwarded "~0.1.0" + ipaddr.js "1.3.0" + +prr@~0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/prr/-/prr-0.0.0.tgz#1a84b85908325501411853d0081ee3fa86e2926a" + +pseudomap@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" + +public-encrypt@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.0.tgz#39f699f3a46560dd5ebacbca693caf7c65c18cc6" + dependencies: + bn.js "^4.1.0" + browserify-rsa "^4.0.0" + create-hash "^1.1.0" + parse-asn1 "^5.0.0" + randombytes "^2.0.1" + +punycode@1.3.2: + version "1.3.2" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" + +punycode@^1.2.4, punycode@^1.4.1: + version "1.4.1" + resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e" + +q@^1.1.2: + version "1.5.0" + resolved "https://registry.yarnpkg.com/q/-/q-1.5.0.tgz#dd01bac9d06d30e6f219aecb8253ee9ebdc308f1" + +qs@6.4.0, qs@~6.4.0: + version "6.4.0" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.4.0.tgz#13e26d28ad6b0ffaa91312cd3bf708ed351e7233" + +query-string@^4.1.0: + version "4.3.4" + resolved "https://registry.yarnpkg.com/query-string/-/query-string-4.3.4.tgz#bbb693b9ca915c232515b228b1a02b609043dbeb" + dependencies: + object-assign "^4.1.0" + strict-uri-encode "^1.0.0" + +querystring-es3@^0.2.0: + version "0.2.1" + resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" + +querystring@0.2.0, querystring@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" + +ramda@^0.23.0: + version "0.23.0" + resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.23.0.tgz#ccd13fff73497a93974e3e86327bfd87bd6e8e2b" + +randomatic@^1.1.3: + version "1.1.6" + resolved "https://registry.yarnpkg.com/randomatic/-/randomatic-1.1.6.tgz#110dcabff397e9dcff7c0789ccc0a49adf1ec5bb" + dependencies: + is-number "^2.0.2" + kind-of "^3.0.2" + +randombytes@^2.0.0, randombytes@^2.0.1: + version "2.0.3" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.0.3.tgz#674c99760901c3c4112771a31e521dc349cc09ec" + +range-parser@^1.0.3, range-parser@~1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.0.tgz#f49be6b487894ddc40dcc94a322f611092e00d5e" + +raw-loader@^0.5.1: + version "0.5.1" + resolved "https://registry.yarnpkg.com/raw-loader/-/raw-loader-0.5.1.tgz#0c3d0beaed8a01c966d9787bf778281252a979aa" + +rc@^1.1.7: + version "1.2.1" + resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.1.tgz#2e03e8e42ee450b8cb3dce65be1bf8974e1dfd95" + dependencies: + deep-extend "~0.4.0" + ini "~1.3.0" + minimist "^1.2.0" + strip-json-comments "~2.0.1" + +read-file-stdin@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/read-file-stdin/-/read-file-stdin-0.2.1.tgz#25eccff3a153b6809afacb23ee15387db9e0ee61" + dependencies: + gather-stream "^1.0.0" + +read-pkg-up@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" + dependencies: + find-up "^1.0.0" + read-pkg "^1.0.0" + +read-pkg-up@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-2.0.0.tgz#6b72a8048984e0c41e79510fd5e9fa99b3b549be" + dependencies: + find-up "^2.0.0" + read-pkg "^2.0.0" + +read-pkg@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" + dependencies: + load-json-file "^1.0.0" + normalize-package-data "^2.3.2" + path-type "^1.0.0" + +read-pkg@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-2.0.0.tgz#8ef1c0623c6a6db0dc6713c4bfac46332b2368f8" + dependencies: + load-json-file "^2.0.0" + normalize-package-data "^2.3.2" + path-type "^2.0.0" + +readable-stream@1.0, "readable-stream@>=1.0.33-1 <1.1.0-0": + version "1.0.34" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.34.tgz#125820e34bc842d2f2aaafafe4c2916ee32c157c" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + +readable-stream@^1.0.33, readable-stream@~1.1.9: + version "1.1.14" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9" + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + +readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.5, readable-stream@^2.0.6, readable-stream@^2.1.4, readable-stream@^2.2.2, readable-stream@^2.2.6: + version "2.2.9" + resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.2.9.tgz#cf78ec6f4a6d1eb43d26488cac97f042e74b7fc8" + dependencies: + buffer-shims "~1.0.0" + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "~1.0.0" + process-nextick-args "~1.0.6" + string_decoder "~1.0.0" + util-deprecate "~1.0.1" + +readdirp@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.1.0.tgz#4ed0ad060df3073300c48440373f72d1cc642d78" + dependencies: + graceful-fs "^4.1.2" + minimatch "^3.0.2" + readable-stream "^2.0.2" + set-immediate-shim "^1.0.1" + +readline2@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/readline2/-/readline2-1.0.1.tgz#41059608ffc154757b715d9989d199ffbf372e35" + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + mute-stream "0.0.5" + +rechoir@^0.6.2: + version "0.6.2" + resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" + dependencies: + resolve "^1.1.6" + +redent@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde" + dependencies: + indent-string "^2.1.0" + strip-indent "^1.0.1" + +reduce-css-calc@^1.2.6: + version "1.3.0" + resolved "https://registry.yarnpkg.com/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz#747c914e049614a4c9cfbba629871ad1d2927716" + dependencies: + balanced-match "^0.4.2" + math-expression-evaluator "^1.2.14" + reduce-function-call "^1.0.1" + +reduce-function-call@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/reduce-function-call/-/reduce-function-call-1.0.2.tgz#5a200bf92e0e37751752fe45b0ab330fd4b6be99" + dependencies: + balanced-match "^0.4.2" + +regenerate@^1.2.1: + version "1.3.2" + resolved "https://registry.yarnpkg.com/regenerate/-/regenerate-1.3.2.tgz#d1941c67bad437e1be76433add5b385f95b19260" + +regenerator-runtime@^0.10.0: + version "0.10.5" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.10.5.tgz#336c3efc1220adcedda2c9fab67b5a7955a33658" + +regenerator-transform@0.9.11: + version "0.9.11" + resolved "https://registry.yarnpkg.com/regenerator-transform/-/regenerator-transform-0.9.11.tgz#3a7d067520cb7b7176769eb5ff868691befe1283" + dependencies: + babel-runtime "^6.18.0" + babel-types "^6.19.0" + private "^0.1.6" + +regex-cache@^0.4.2: + version "0.4.3" + resolved "https://registry.yarnpkg.com/regex-cache/-/regex-cache-0.4.3.tgz#9b1a6c35d4d0dfcef5711ae651e8e9d3d7114145" + dependencies: + is-equal-shallow "^0.1.3" + is-primitive "^2.0.0" + +regexpu-core@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-1.0.0.tgz#86a763f58ee4d7c2f6b102e4764050de7ed90c6b" + dependencies: + regenerate "^1.2.1" + regjsgen "^0.2.0" + regjsparser "^0.1.4" + +regexpu-core@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-2.0.0.tgz#49d038837b8dcf8bfa5b9a42139938e6ea2ae240" + dependencies: + regenerate "^1.2.1" + regjsgen "^0.2.0" + regjsparser "^0.1.4" + +regjsgen@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/regjsgen/-/regjsgen-0.2.0.tgz#6c016adeac554f75823fe37ac05b92d5a4edb1f7" + +regjsparser@^0.1.4: + version "0.1.5" + resolved "https://registry.yarnpkg.com/regjsparser/-/regjsparser-0.1.5.tgz#7ee8f84dc6fa792d3fd0ae228d24bd949ead205c" + dependencies: + jsesc "~0.5.0" + +relateurl@0.2.x: + version "0.2.7" + resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9" + +remove-trailing-separator@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.0.1.tgz#615ebb96af559552d4bf4057c8436d486ab63cc4" + +renderkid@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/renderkid/-/renderkid-2.0.1.tgz#898cabfc8bede4b7b91135a3ffd323e58c0db319" + dependencies: + css-select "^1.1.0" + dom-converter "~0.1" + htmlparser2 "~3.3.0" + strip-ansi "^3.0.0" + utila "~0.3" + +repeat-element@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.2.tgz#ef089a178d1483baae4d93eb98b4f9e4e11d990a" + +repeat-string@^1.5.2: + version "1.6.1" + resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + +repeating@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" + dependencies: + is-finite "^1.0.0" + +request@2, request@^2.79.0, request@^2.81.0: + version "2.81.0" + resolved "https://registry.yarnpkg.com/request/-/request-2.81.0.tgz#c6928946a0e06c5f8d6f8a9333469ffda46298a0" + dependencies: + aws-sign2 "~0.6.0" + aws4 "^1.2.1" + caseless "~0.12.0" + combined-stream "~1.0.5" + extend "~3.0.0" + forever-agent "~0.6.1" + form-data "~2.1.1" + har-validator "~4.2.1" + hawk "~3.1.3" + http-signature "~1.1.0" + is-typedarray "~1.0.0" + isstream "~0.1.2" + json-stringify-safe "~5.0.1" + mime-types "~2.1.7" + oauth-sign "~0.8.1" + performance-now "^0.2.0" + qs "~6.4.0" + safe-buffer "^5.0.1" + stringstream "~0.0.4" + tough-cookie "~2.3.0" + tunnel-agent "^0.6.0" + uuid "^3.0.0" + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + +require-from-string@^1.1.0: + version "1.2.1" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-1.2.1.tgz#529c9ccef27380adfec9a2f965b649bbee636418" + +require-main-filename@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-1.0.1.tgz#97f717b69d48784f5f526a6c5aa8ffdda055a4d1" + +require-uncached@^1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/require-uncached/-/require-uncached-1.0.3.tgz#4e0d56d6c9662fd31e43011c4b95aa49955421d3" + dependencies: + caller-path "^0.1.0" + resolve-from "^1.0.0" + +requires-port@1.x.x: + version "1.0.0" + resolved "https://registry.yarnpkg.com/requires-port/-/requires-port-1.0.0.tgz#925d2601d39ac485e091cf0da5c6e694dc3dcaff" + +resolve-from@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-1.0.1.tgz#26cbfe935d1aeeeabb29bc3fe5aeb01e93d44226" + +resolve-from@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-2.0.0.tgz#9480ab20e94ffa1d9e80a804c7ea147611966b57" + +resolve@^1.1.6, resolve@^1.2.0, resolve@^1.3.3: + version "1.3.3" + resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.3.3.tgz#655907c3469a8680dc2de3a275a8fdd69691f0e5" + dependencies: + path-parse "^1.0.5" + +restore-cursor@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-1.0.1.tgz#34661f46886327fed2991479152252df92daa541" + dependencies: + exit-hook "^1.0.0" + onetime "^1.0.0" + +restore-cursor@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" + dependencies: + onetime "^2.0.0" + signal-exit "^3.0.2" + +right-align@^0.1.1: + version "0.1.3" + resolved "https://registry.yarnpkg.com/right-align/-/right-align-0.1.3.tgz#61339b722fe6a3515689210d24e14c96148613ef" + dependencies: + align-text "^0.1.1" + +rimraf@2, rimraf@^2.2.8, rimraf@^2.5.1, rimraf@^2.6.0, rimraf@^2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.1.tgz#c2338ec643df7a1b7fe5c54fa86f57428a55f33d" + dependencies: + glob "^7.0.5" + +ripemd160@^2.0.0, ripemd160@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.1.tgz#0f4584295c53a3628af7e6d79aca21ce57d1c6e7" + dependencies: + hash-base "^2.0.0" + inherits "^2.0.1" + +run-async@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/run-async/-/run-async-0.1.0.tgz#c8ad4a5e110661e402a7d21b530e009f25f8e389" + dependencies: + once "^1.3.0" + +rx-lite@^3.1.2: + version "3.1.2" + resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102" + +safe-buffer@^5.0.1, safe-buffer@~5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.0.1.tgz#d263ca54696cd8a306b5ca6551e92de57918fbe7" + +sass-graph@^2.1.1: + version "2.2.4" + resolved "https://registry.yarnpkg.com/sass-graph/-/sass-graph-2.2.4.tgz#13fbd63cd1caf0908b9fd93476ad43a51d1e0b49" + dependencies: + glob "^7.0.0" + lodash "^4.0.0" + scss-tokenizer "^0.2.3" + yargs "^7.0.0" + +sass-loader@^6.0.5: + version "6.0.5" + resolved "https://registry.yarnpkg.com/sass-loader/-/sass-loader-6.0.5.tgz#a847910f36442aa56c5985879d54eb519e24a328" + dependencies: + async "^2.1.5" + clone-deep "^0.2.4" + loader-utils "^1.0.1" + lodash.tail "^4.1.1" + pify "^2.3.0" + +sax@~1.2.1: + version "1.2.2" + resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.2.tgz#fd8631a23bc7826bef5d871bdb87378c95647828" + +scss-tokenizer@^0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz#8eb06db9a9723333824d3f5530641149847ce5d1" + dependencies: + js-base64 "^2.1.8" + source-map "^0.4.2" + +select@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/select/-/select-1.1.2.tgz#0e7350acdec80b1108528786ec1d4418d11b396d" + +"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@~5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" + +send@0.15.3: + version "0.15.3" + resolved "https://registry.yarnpkg.com/send/-/send-0.15.3.tgz#5013f9f99023df50d1bd9892c19e3defd1d53309" + dependencies: + debug "2.6.7" + depd "~1.1.0" + destroy "~1.0.4" + encodeurl "~1.0.1" + escape-html "~1.0.3" + etag "~1.8.0" + fresh "0.5.0" + http-errors "~1.6.1" + mime "1.3.4" + ms "2.0.0" + on-finished "~2.3.0" + range-parser "~1.2.0" + statuses "~1.3.1" + +serve-static@1.12.3: + version "1.12.3" + resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.12.3.tgz#9f4ba19e2f3030c547f8af99107838ec38d5b1e2" + dependencies: + encodeurl "~1.0.1" + escape-html "~1.0.3" + parseurl "~1.3.1" + send "0.15.3" + +set-blocking@^2.0.0, set-blocking@~2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + +set-immediate-shim@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz#4b2b1b27eb808a9f8dcc481a58e5e56f599f3f61" + +setimmediate@^1.0.4: + version "1.0.5" + resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + +setprototypeof@1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.0.3.tgz#66567e37043eeb4f04d91bd658c0cbefb55b8e04" + +sha.js@^2.4.0, sha.js@^2.4.8: + version "2.4.8" + resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.8.tgz#37068c2c476b6baf402d14a49c67f597921f634f" + dependencies: + inherits "^2.0.1" + +shallow-clone@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-0.1.2.tgz#5909e874ba77106d73ac414cfec1ffca87d97060" + dependencies: + is-extendable "^0.1.1" + kind-of "^2.0.1" + lazy-cache "^0.2.3" + mixin-object "^2.0.1" + +shelljs@^0.7.5, shelljs@^0.7.6: + version "0.7.7" + resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.7.7.tgz#b2f5c77ef97148f4b4f6e22682e10bba8667cff1" + dependencies: + glob "^7.0.0" + interpret "^1.0.0" + rechoir "^0.6.2" + +sigmund@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/sigmund/-/sigmund-1.0.1.tgz#3ff21f198cad2175f9f3b781853fd94d0d19b590" + +signal-exit@^3.0.0, signal-exit@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" + +slash@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" + +slice-ansi@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35" + +sntp@1.x.x: + version "1.0.9" + resolved "https://registry.yarnpkg.com/sntp/-/sntp-1.0.9.tgz#6541184cc90aeea6c6e7b35e2659082443c66198" + dependencies: + hoek "2.x.x" + +sort-keys@^1.0.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-1.1.2.tgz#441b6d4d346798f1b4e49e8920adfba0e543f9ad" + dependencies: + is-plain-obj "^1.0.0" + +source-list-map@^0.1.7, source-list-map@~0.1.7: + version "0.1.8" + resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-0.1.8.tgz#c550b2ab5427f6b3f21f5afead88c4f5587b2106" + +source-list-map@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-1.1.2.tgz#9889019d1024cce55cdc069498337ef6186a11a1" + +source-map-support@^0.4.2: + version "0.4.15" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.4.15.tgz#03202df65c06d2bd8c7ec2362a193056fef8d3b1" + dependencies: + source-map "^0.5.6" + +source-map@0.5.x, source-map@^0.5.0, source-map@^0.5.3, source-map@^0.5.6, source-map@~0.5.1, source-map@~0.5.3: + version "0.5.6" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.6.tgz#75ce38f52bf0733c5a7f0c118d81334a2bb5f412" + +source-map@^0.4.2: + version "0.4.4" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.4.4.tgz#eba4f5da9c0dc999de68032d8b4f76173652036b" + dependencies: + amdefine ">=0.0.4" + +spdx-correct@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-1.0.2.tgz#4b3073d933ff51f3912f03ac5519498a4150db40" + dependencies: + spdx-license-ids "^1.0.2" + +spdx-expression-parse@~1.0.0: + version "1.0.4" + resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz#9bdf2f20e1f40ed447fbe273266191fced51626c" + +spdx-license-ids@^1.0.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz#c9df7a3424594ade6bd11900d596696dc06bac57" + +specificity@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/specificity/-/specificity-0.3.0.tgz#332472d4e5eb5af20821171933998a6bc3b1ce6f" + +split2@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/split2/-/split2-0.2.1.tgz#02ddac9adc03ec0bb78c1282ec079ca6e85ae900" + dependencies: + through2 "~0.6.1" + +sprintf-js@~1.0.2: + version "1.0.3" + resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + +sshpk@^1.7.0: + version "1.13.0" + resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.13.0.tgz#ff2a3e4fd04497555fed97b39a0fd82fafb3a33c" + dependencies: + asn1 "~0.2.3" + assert-plus "^1.0.0" + dashdash "^1.12.0" + getpass "^0.1.1" + optionalDependencies: + bcrypt-pbkdf "^1.0.0" + ecc-jsbn "~0.1.1" + jodid25519 "^1.0.0" + jsbn "~0.1.0" + tweetnacl "~0.14.0" + +stackframe@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/stackframe/-/stackframe-1.0.3.tgz#fe64ab20b170e4ce49044b126c119dfa0e5dc7cc" + +"statuses@>= 1.3.1 < 2", statuses@~1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.3.1.tgz#faf51b9eb74aaef3b3acf4ad5f61abf24cb7b93e" + +stdout-stream@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/stdout-stream/-/stdout-stream-1.4.0.tgz#a2c7c8587e54d9427ea9edb3ac3f2cd522df378b" + dependencies: + readable-stream "^2.0.1" + +stream-browserify@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.1.tgz#66266ee5f9bdb9940a4e4514cafb43bb71e5c9db" + dependencies: + inherits "~2.0.1" + readable-stream "^2.0.2" + +stream-combiner@^0.2.1: + version "0.2.2" + resolved "https://registry.yarnpkg.com/stream-combiner/-/stream-combiner-0.2.2.tgz#aec8cbac177b56b6f4fa479ced8c1912cee52858" + dependencies: + duplexer "~0.1.1" + through "~2.3.4" + +stream-http@^2.3.1: + version "2.7.1" + resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.7.1.tgz#546a51741ad5a6b07e9e31b0b10441a917df528a" + dependencies: + builtin-status-codes "^3.0.0" + inherits "^2.0.1" + readable-stream "^2.2.6" + to-arraybuffer "^1.0.0" + xtend "^4.0.0" + +strict-uri-encode@^1.0.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/strict-uri-encode/-/strict-uri-encode-1.1.0.tgz#279b225df1d582b1f54e65addd4352e18faa0713" + +string-length@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/string-length/-/string-length-1.0.1.tgz#56970fb1c38558e9e70b728bf3de269ac45adfac" + dependencies: + strip-ansi "^3.0.0" + +string-width@^1.0.1, string-width@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + dependencies: + code-point-at "^1.0.0" + is-fullwidth-code-point "^1.0.0" + strip-ansi "^3.0.0" + +string-width@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.0.0.tgz#635c5436cc72a6e0c387ceca278d4e2eec52687e" + dependencies: + is-fullwidth-code-point "^2.0.0" + strip-ansi "^3.0.0" + +string_decoder@^0.10.25, string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-0.10.31.tgz#62e203bc41766c6c28c9fc84301dab1c5310fa94" + +string_decoder@~1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.0.1.tgz#62e200f039955a6810d8df0a33ffc0f013662d98" + dependencies: + safe-buffer "^5.0.1" + +stringstream@~0.0.4: + version "0.0.5" + resolved "https://registry.yarnpkg.com/stringstream/-/stringstream-0.0.5.tgz#4e484cd4de5a0bbbee18e46307710a8a81621878" + +strip-ansi@^3.0.0, strip-ansi@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + dependencies: + ansi-regex "^2.0.0" + +strip-bom@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" + dependencies: + is-utf8 "^0.2.0" + +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + +strip-indent@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2" + dependencies: + get-stdin "^4.0.1" + +strip-json-comments@~2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + +style-search@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/style-search/-/style-search-0.1.0.tgz#7958c793e47e32e07d2b5cafe5c0bf8e12e77902" + +stylehacks@^2.3.2: + version "2.3.2" + resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-2.3.2.tgz#64c83e0438a68c9edf449e8c552a7d9ab6009b0b" + dependencies: + browserslist "^1.1.3" + chalk "^1.1.1" + log-symbols "^1.0.2" + minimist "^1.2.0" + plur "^2.1.2" + postcss "^5.0.18" + postcss-reporter "^1.3.3" + postcss-selector-parser "^2.0.0" + read-file-stdin "^0.2.1" + text-table "^0.2.0" + write-file-stdout "0.0.2" + +stylelint-config-standard@^16.0.0: + version "16.0.0" + resolved "https://registry.yarnpkg.com/stylelint-config-standard/-/stylelint-config-standard-16.0.0.tgz#bb7387bff1d7dd7186a52b3ebf885b2405d691bf" + +stylelint-processor-html@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/stylelint-processor-html/-/stylelint-processor-html-1.0.0.tgz#6892b6b2855a45f0291cd845191d6908130a2918" + dependencies: + htmlparser2 "^3.9.1" + +stylelint-webpack-plugin@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/stylelint-webpack-plugin/-/stylelint-webpack-plugin-0.7.0.tgz#48d6683fddf93b758e194c4468fada4771230c39" + dependencies: + arrify "^1.0.1" + chalk "^1.1.3" + minimatch "^3.0.3" + object-assign "^4.1.0" + ramda "^0.23.0" + stylelint "^7.7.0" + +stylelint@^7.7.0: + version "7.10.1" + resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-7.10.1.tgz#209a7ce5e781fc2a62489fbb31ec0201ec675db2" + dependencies: + autoprefixer "^6.0.0" + balanced-match "^0.4.0" + chalk "^1.1.1" + colorguard "^1.2.0" + cosmiconfig "^2.1.1" + debug "^2.6.0" + doiuse "^2.4.1" + execall "^1.0.0" + file-entry-cache "^2.0.0" + get-stdin "^5.0.0" + globby "^6.0.0" + globjoin "^0.1.4" + html-tags "^1.1.1" + ignore "^3.2.0" + imurmurhash "^0.1.4" + known-css-properties "^0.0.7" + lodash "^4.17.4" + log-symbols "^1.0.2" + meow "^3.3.0" + micromatch "^2.3.11" + normalize-selector "^0.2.0" + postcss "^5.0.20" + postcss-less "^0.14.0" + postcss-media-query-parser "^0.2.0" + postcss-reporter "^3.0.0" + postcss-resolve-nested-selector "^0.1.1" + postcss-scss "^0.4.0" + postcss-selector-parser "^2.1.1" + postcss-value-parser "^3.1.1" + resolve-from "^2.0.0" + specificity "^0.3.0" + string-width "^2.0.0" + style-search "^0.1.0" + stylehacks "^2.3.2" + sugarss "^0.2.0" + svg-tags "^1.0.0" + table "^4.0.1" + +sugarss@^0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/sugarss/-/sugarss-0.2.0.tgz#ac34237563327c6ff897b64742bf6aec190ad39e" + dependencies: + postcss "^5.2.4" + +supports-color@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-2.0.0.tgz#535d045ce6b6363fa40117084629995e9df324c7" + +supports-color@^3.1.0, supports-color@^3.2.3: + version "3.2.3" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-3.2.3.tgz#65ac0504b3954171d8a64946b2ae3cbb8a5f54f6" + dependencies: + has-flag "^1.0.0" + +svg-tags@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/svg-tags/-/svg-tags-1.0.0.tgz#58f71cee3bd519b59d4b2a843b6c7de64ac04764" + +svgo@^0.7.0: + version "0.7.2" + resolved "https://registry.yarnpkg.com/svgo/-/svgo-0.7.2.tgz#9f5772413952135c6fefbf40afe6a4faa88b4bb5" + dependencies: + coa "~1.0.1" + colors "~1.1.2" + csso "~2.3.1" + js-yaml "~3.7.0" + mkdirp "~0.5.1" + sax "~1.2.1" + whet.extend "~0.9.9" + +synesthesia@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/synesthesia/-/synesthesia-1.0.1.tgz#5ef95ea548c0d5c6e6f9bb4b0d0731dff864a777" + dependencies: + css-color-names "0.0.3" + +table@^3.7.8: + version "3.8.3" + resolved "https://registry.yarnpkg.com/table/-/table-3.8.3.tgz#2bbc542f0fda9861a755d3947fefd8b3f513855f" + dependencies: + ajv "^4.7.0" + ajv-keywords "^1.0.0" + chalk "^1.1.1" + lodash "^4.0.0" + slice-ansi "0.0.4" + string-width "^2.0.0" + +table@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/table/-/table-4.0.1.tgz#a8116c133fac2c61f4a420ab6cdf5c4d61f0e435" + dependencies: + ajv "^4.7.0" + ajv-keywords "^1.0.0" + chalk "^1.1.1" + lodash "^4.0.0" + slice-ansi "0.0.4" + string-width "^2.0.0" + +tapable@^0.1.8: + version "0.1.10" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.1.10.tgz#29c35707c2b70e50d07482b5d202e8ed446dafd4" + +tapable@^0.2.5, tapable@~0.2.5: + version "0.2.6" + resolved "https://registry.yarnpkg.com/tapable/-/tapable-0.2.6.tgz#206be8e188860b514425375e6f1ae89bfb01fd8d" + +tar-pack@^3.4.0: + version "3.4.0" + resolved "https://registry.yarnpkg.com/tar-pack/-/tar-pack-3.4.0.tgz#23be2d7f671a8339376cbdb0b8fe3fdebf317984" + dependencies: + debug "^2.2.0" + fstream "^1.0.10" + fstream-ignore "^1.0.5" + once "^1.3.3" + readable-stream "^2.1.4" + rimraf "^2.5.1" + tar "^2.2.1" + uid-number "^0.0.6" + +tar@^2.0.0, tar@^2.2.1: + version "2.2.1" + resolved "https://registry.yarnpkg.com/tar/-/tar-2.2.1.tgz#8e4d2a256c0e2185c6b18ad694aec968b83cb1d1" + dependencies: + block-stream "*" + fstream "^1.0.2" + inherits "2" + +text-table@^0.2.0, text-table@~0.2.0: + version "0.2.0" + resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" + +through2@^0.6.1, through2@^0.6.3, through2@~0.6.1: + version "0.6.5" + resolved "https://registry.yarnpkg.com/through2/-/through2-0.6.5.tgz#41ab9c67b29d57209071410e1d7a7a968cd3ad48" + dependencies: + readable-stream ">=1.0.33-1 <1.1.0-0" + xtend ">=4.0.0 <4.1.0-0" + +"through@>=2.2.7 <3", through@^2.3.6, through@~2.3.4: + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + +timers-browserify@^1.4.2: + version "1.4.2" + resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-1.4.2.tgz#c9c58b575be8407375cb5e2462dacee74359f41d" + dependencies: + process "~0.11.0" + +timers-browserify@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.2.tgz#ab4883cf597dcd50af211349a00fbca56ac86b86" + dependencies: + setimmediate "^1.0.4" + +tiny-emitter@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/tiny-emitter/-/tiny-emitter-2.0.0.tgz#bad327adb1804b42a231afa741532bd884cd09ad" + +to-arraybuffer@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" + +to-fast-properties@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-1.0.3.tgz#b83571fa4d8c25b82e231b06e3a3055de4ca1a47" + +toposort@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/toposort/-/toposort-1.0.3.tgz#f02cd8a74bd8be2fc0e98611c3bacb95a171869c" + +tough-cookie@~2.3.0: + version "2.3.2" + resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.2.tgz#f081f76e4c85720e6c37a5faced737150d84072a" + dependencies: + punycode "^1.4.1" + +trim-newlines@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" + +trim-right@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" + +tryit@^1.0.1: + version "1.0.3" + resolved "https://registry.yarnpkg.com/tryit/-/tryit-1.0.3.tgz#393be730a9446fd1ead6da59a014308f36c289cb" + +tty-browserify@0.0.0: + version "0.0.0" + resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" + +tunnel-agent@^0.6.0: + version "0.6.0" + resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + dependencies: + safe-buffer "^5.0.1" + +tweetnacl@^0.14.3, tweetnacl@~0.14.0: + version "0.14.5" + resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + +type-check@~0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + dependencies: + prelude-ls "~1.1.2" + +type-is@~1.6.15: + version "1.6.15" + resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.15.tgz#cab10fb4909e441c82842eafe1ad646c81804410" + dependencies: + media-typer "0.3.0" + mime-types "~2.1.15" + +typedarray@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + +uc.micro@^1.0.1, uc.micro@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/uc.micro/-/uc.micro-1.0.3.tgz#7ed50d5e0f9a9fb0a573379259f2a77458d50192" + +uglify-js@3.0.x: + version "3.0.14" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.0.14.tgz#2697af126fd215aac556facb1edfb17875204760" + dependencies: + commander "~2.9.0" + source-map "~0.5.1" + +uglify-js@^2.8.27: + version "2.8.27" + resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-2.8.27.tgz#47787f912b0f242e5b984343be8e35e95f694c9c" + dependencies: + source-map "~0.5.1" + yargs "~3.10.0" + optionalDependencies: + uglify-to-browserify "~1.0.0" + +uglify-to-browserify@~1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz#6e0924d6bda6b5afe349e39a6d632850a0f882b7" + +uid-number@^0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" + +ultron@~1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/ultron/-/ultron-1.1.0.tgz#b07a2e6a541a815fc6a34ccd4533baec307ca864" + +unc-path-regex@^0.1.0: + version "0.1.2" + resolved "https://registry.yarnpkg.com/unc-path-regex/-/unc-path-regex-0.1.2.tgz#e73dd3d7b0d7c5ed86fbac6b0ae7d8c6a69d50fa" + +underscore@^1.8.3: + version "1.8.3" + resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.8.3.tgz#4f3fb53b106e6097fcf9cb4109f2a5e9bdfa5022" + +uniq@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/uniq/-/uniq-1.0.1.tgz#b31c5ae8254844a3a8281541ce2b04b865a734ff" + +uniqid@^4.0.0: + version "4.1.1" + resolved "https://registry.yarnpkg.com/uniqid/-/uniqid-4.1.1.tgz#89220ddf6b751ae52b5f72484863528596bb84c1" + dependencies: + macaddress "^0.2.8" + +uniqs@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/uniqs/-/uniqs-2.0.0.tgz#ffede4b36b25290696e6e165d4a59edb998e6b02" + +unpipe@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" + +upper-case@^1.1.1: + version "1.1.3" + resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-1.1.3.tgz#f6b4501c2ec4cdd26ba78be7222961de77621598" + +url-loader@^0.5.8: + version "0.5.8" + resolved "https://registry.yarnpkg.com/url-loader/-/url-loader-0.5.8.tgz#b9183b1801e0f847718673673040bc9dc1c715c5" + dependencies: + loader-utils "^1.0.2" + mime "1.3.x" + +url@^0.11.0: + version "0.11.0" + resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" + dependencies: + punycode "1.3.2" + querystring "0.2.0" + +user-home@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/user-home/-/user-home-2.0.0.tgz#9c70bfd8169bc1dcbf48604e0f04b8b49cde9e9f" + dependencies: + os-homedir "^1.0.0" + +util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + +util@0.10.3, util@^0.10.3: + version "0.10.3" + resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" + dependencies: + inherits "2.0.1" + +utila@~0.3: + version "0.3.3" + resolved "https://registry.yarnpkg.com/utila/-/utila-0.3.3.tgz#d7e8e7d7e309107092b05f8d9688824d633a4226" + +utila@~0.4: + version "0.4.0" + resolved "https://registry.yarnpkg.com/utila/-/utila-0.4.0.tgz#8a16a05d445657a3aea5eecc5b12a4fa5379772c" + +utils-merge@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.0.tgz#0294fb922bb9375153541c4f7096231f287c8af8" + +uuid@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.0.1.tgz#6544bba2dfda8c1cf17e629a3a305e2bb1fee6c1" + +validate-npm-package-license@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc" + dependencies: + spdx-correct "~1.0.0" + spdx-expression-parse "~1.0.0" + +vary@~1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.1.tgz#67535ebb694c1d52257457984665323f587e8d37" + +vendors@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/vendors/-/vendors-1.0.1.tgz#37ad73c8ee417fb3d580e785312307d274847f22" + +verror@1.3.6: + version "1.3.6" + resolved "https://registry.yarnpkg.com/verror/-/verror-1.3.6.tgz#cff5df12946d297d2baaefaa2689e25be01c005c" + dependencies: + extsprintf "1.0.2" + +vm-browserify@0.0.4: + version "0.0.4" + resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-0.0.4.tgz#5d7ea45bbef9e4a6ff65f95438e0a87c357d5a73" + dependencies: + indexof "0.0.1" + +vue-hot-reload-api@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/vue-hot-reload-api/-/vue-hot-reload-api-2.1.0.tgz#9ca58a6e0df9078554ce1708688b6578754d86de" + +vue-loader@^12.1.0: + version "12.2.1" + resolved "https://registry.yarnpkg.com/vue-loader/-/vue-loader-12.2.1.tgz#53f27c0973d386768f5a75156f4129b5efc6ba55" + dependencies: + consolidate "^0.14.0" + hash-sum "^1.0.2" + js-beautify "^1.6.3" + loader-utils "^1.1.0" + lru-cache "^4.0.1" + postcss "^5.0.21" + postcss-load-config "^1.1.0" + postcss-selector-parser "^2.0.0" + resolve "^1.3.3" + source-map "^0.5.6" + vue-hot-reload-api "^2.1.0" + vue-style-loader "^3.0.0" + vue-template-es2015-compiler "^1.2.2" + +vue-style-loader@^3.0.0, vue-style-loader@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/vue-style-loader/-/vue-style-loader-3.0.1.tgz#c8b639bb2f24baf9d78274dc17e4f264c1deda08" + dependencies: + hash-sum "^1.0.2" + loader-utils "^1.0.2" + +vue-template-compiler@^2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/vue-template-compiler/-/vue-template-compiler-2.3.3.tgz#b5bab9ec57309c906b82a78c81a02179dbc2f470" + dependencies: + de-indent "^1.0.2" + he "^1.1.0" + +vue-template-es2015-compiler@^1.2.2: + version "1.5.2" + resolved "https://registry.yarnpkg.com/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.5.2.tgz#a0a6c50c941d2a4abda963f2f42c337ac450ee95" + +vue@^2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/vue/-/vue-2.3.3.tgz#d1eaa8fde5240735a4563e74f2c7fead9cbb064c" + +vuex@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/vuex/-/vuex-2.3.1.tgz#cde8e997c1f9957719bc7dea154f9aa691d981a6" + +watchpack@^1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.3.1.tgz#7d8693907b28ce6013e7f3610aa2a1acf07dad87" + dependencies: + async "^2.1.2" + chokidar "^1.4.3" + graceful-fs "^4.1.2" + +webpack-bundle-analyzer@^2.2.1: + version "2.8.2" + resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-2.8.2.tgz#8b6240c29a9d63bc72f09d920fb050adbcce9fe8" + dependencies: + acorn "^5.0.3" + chalk "^1.1.3" + commander "^2.9.0" + ejs "^2.5.6" + express "^4.15.2" + filesize "^3.5.9" + gzip-size "^3.0.0" + lodash "^4.17.4" + mkdirp "^0.5.1" + opener "^1.4.3" + ws "^2.3.1" + +webpack-dev-middleware@^1.10.0: + version "1.10.2" + resolved "https://registry.yarnpkg.com/webpack-dev-middleware/-/webpack-dev-middleware-1.10.2.tgz#2e252ce1dfb020dbda1ccb37df26f30ab014dbd1" + dependencies: + memory-fs "~0.4.1" + mime "^1.3.4" + path-is-absolute "^1.0.0" + range-parser "^1.0.3" + +webpack-hot-middleware@^2.18.0: + version "2.18.0" + resolved "https://registry.yarnpkg.com/webpack-hot-middleware/-/webpack-hot-middleware-2.18.0.tgz#a16bb535b83a6ac94a78ac5ebce4f3059e8274d3" + dependencies: + ansi-html "0.0.7" + html-entities "^1.2.0" + querystring "^0.2.0" + strip-ansi "^3.0.0" + +webpack-merge@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/webpack-merge/-/webpack-merge-4.1.0.tgz#6ad72223b3e0b837e531e4597c199f909361511e" + dependencies: + lodash "^4.17.4" + +webpack-sources@^0.1.0: + version "0.1.5" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-0.1.5.tgz#aa1f3abf0f0d74db7111c40e500b84f966640750" + dependencies: + source-list-map "~0.1.7" + source-map "~0.5.3" + +webpack-sources@^0.2.3: + version "0.2.3" + resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-0.2.3.tgz#17c62bfaf13c707f9d02c479e0dcdde8380697fb" + dependencies: + source-list-map "^1.1.1" + source-map "~0.5.3" + +webpack@^2.6.1: + version "2.6.1" + resolved "https://registry.yarnpkg.com/webpack/-/webpack-2.6.1.tgz#2e0457f0abb1ac5df3ab106c69c672f236785f07" + dependencies: + acorn "^5.0.0" + acorn-dynamic-import "^2.0.0" + ajv "^4.7.0" + ajv-keywords "^1.1.1" + async "^2.1.2" + enhanced-resolve "^3.0.0" + interpret "^1.0.0" + json-loader "^0.5.4" + json5 "^0.5.1" + loader-runner "^2.3.0" + loader-utils "^0.2.16" + memory-fs "~0.4.1" + mkdirp "~0.5.0" + node-libs-browser "^2.0.0" + source-map "^0.5.3" + supports-color "^3.1.0" + tapable "~0.2.5" + uglify-js "^2.8.27" + watchpack "^1.3.1" + webpack-sources "^0.2.3" + yargs "^6.0.0" + +whet.extend@~0.9.9: + version "0.9.9" + resolved "https://registry.yarnpkg.com/whet.extend/-/whet.extend-0.9.9.tgz#f877d5bf648c97e5aa542fadc16d6a259b9c11a1" + +which-module@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/which-module/-/which-module-1.0.0.tgz#bba63ca861948994ff307736089e3b96026c2a4f" + +which@1, which@^1.2.9: + version "1.2.14" + resolved "https://registry.yarnpkg.com/which/-/which-1.2.14.tgz#9a87c4378f03e827cecaf1acdf56c736c01c14e5" + dependencies: + isexe "^2.0.0" + +wide-align@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.2.tgz#571e0f1b0604636ebc0dfc21b0339bbe31341710" + dependencies: + string-width "^1.0.2" + +window-size@0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/window-size/-/window-size-0.1.0.tgz#5438cd2ea93b202efa3a19fe8887aee7c94f9c9d" + +wordwrap@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-0.0.2.tgz#b79669bb42ecb409f83d583cad52ca17eaa1643f" + +wordwrap@~1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + +wrap-ansi@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85" + dependencies: + string-width "^1.0.1" + strip-ansi "^3.0.1" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + +write-file-stdout@0.0.2: + version "0.0.2" + resolved "https://registry.yarnpkg.com/write-file-stdout/-/write-file-stdout-0.0.2.tgz#c252d7c7c5b1b402897630e3453c7bfe690d9ca1" + +write@^0.2.1: + version "0.2.1" + resolved "https://registry.yarnpkg.com/write/-/write-0.2.1.tgz#5fc03828e264cea3fe91455476f7a3c566cb0757" + dependencies: + mkdirp "^0.5.1" + +ws@^2.3.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-2.3.1.tgz#6b94b3e447cb6a363f785eaf94af6359e8e81c80" + dependencies: + safe-buffer "~5.0.1" + ultron "~1.1.0" + +xml-char-classes@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/xml-char-classes/-/xml-char-classes-1.0.0.tgz#64657848a20ffc5df583a42ad8a277b4512bbc4d" + +"xtend@>=4.0.0 <4.1.0-0", xtend@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af" + +y18n@^3.2.1: + version "3.2.1" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-3.2.1.tgz#6d15fba884c08679c0d77e88e7759e811e07fa41" + +yallist@^2.0.0: + version "2.1.2" + resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" + +yargs-parser@^4.2.0: + version "4.2.1" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-4.2.1.tgz#29cceac0dc4f03c6c87b4a9f217dd18c9f74871c" + dependencies: + camelcase "^3.0.0" + +yargs-parser@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-5.0.0.tgz#275ecf0d7ffe05c77e64e7c86e4cd94bf0e1228a" + dependencies: + camelcase "^3.0.0" + +yargs@^1.2.6: + version "1.3.3" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-1.3.3.tgz#054de8b61f22eefdb7207059eaef9d6b83fb931a" + +yargs@^3.5.4, yargs@~3.10.0: + version "3.10.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-3.10.0.tgz#f7ee7bd857dd7c1d2d38c0e74efbd681d1431fd1" + dependencies: + camelcase "^1.0.2" + cliui "^2.1.0" + decamelize "^1.0.0" + window-size "0.1.0" + +yargs@^6.0.0: + version "6.6.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-6.6.0.tgz#782ec21ef403345f830a808ca3d513af56065208" + dependencies: + camelcase "^3.0.0" + cliui "^3.2.0" + decamelize "^1.1.1" + get-caller-file "^1.0.1" + os-locale "^1.4.0" + read-pkg-up "^1.0.1" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^1.0.2" + which-module "^1.0.0" + y18n "^3.2.1" + yargs-parser "^4.2.0" + +yargs@^7.0.0: + version "7.1.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-7.1.0.tgz#6ba318eb16961727f5d284f8ea003e8d6154d0c8" + dependencies: + camelcase "^3.0.0" + cliui "^3.2.0" + decamelize "^1.1.1" + get-caller-file "^1.0.1" + os-locale "^1.4.0" + read-pkg-up "^1.0.1" + require-directory "^2.1.1" + require-main-filename "^1.0.1" + set-blocking "^2.0.0" + string-width "^1.0.2" + which-module "^1.0.0" + y18n "^3.2.1" + yargs-parser "^5.0.0"