From fae1963445a6ebc27fc090225855e757d30c5fb5 Mon Sep 17 00:00:00 2001 From: Anir Nathwani Date: Tue, 17 Sep 2019 14:51:43 +0100 Subject: [PATCH 01/70] 1.3.2 --- exercises/02_http/01_url/index.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/exercises/02_http/01_url/index.js b/exercises/02_http/01_url/index.js index c7a9340a..30eac127 100644 --- a/exercises/02_http/01_url/index.js +++ b/exercises/02_http/01_url/index.js @@ -37,12 +37,17 @@ router.get('/anon', ctx => { // anon case }) -router.get('/books/:index', ctx => { - const books = ['The Hobbit', 'Alice in Wonderland', 'The Secret Garden'] +router.get('/books/:index/:index2', ctx => { + const books = ['The Hobbit', 'Alice in Wonderland', 'The Secret Garden','Animal Farm'] const parameters = ctx.params console.log(parameters) - const title = books[parameters.index] - ctx.body = title + if (parameters.index > 3) { + ctx.body = "Number cannot be greater than 3" + }else{ + const title = books[parameters.index] + const title2 = books[parameters.index2] + ctx.body = title + title2 + parameters.index + } }) router.get('/name', ctx => ctx.body = JSON.stringify(ctx.query)) From 83c9e2ddf4ece2995a23c27378f0f0a1b2b14feb Mon Sep 17 00:00:00 2001 From: Anir Nathwani Date: Tue, 24 Sep 2019 13:07:44 +0100 Subject: [PATCH 02/70] update --- exercises/02_http/01_url/index.js | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/exercises/02_http/01_url/index.js b/exercises/02_http/01_url/index.js index 30eac127..912dc44a 100644 --- a/exercises/02_http/01_url/index.js +++ b/exercises/02_http/01_url/index.js @@ -41,12 +41,21 @@ router.get('/books/:index/:index2', ctx => { const books = ['The Hobbit', 'Alice in Wonderland', 'The Secret Garden','Animal Farm'] const parameters = ctx.params console.log(parameters) - if (parameters.index > 3) { + + + if (parameters.index > 3 || parameters.index2 > 3) { ctx.body = "Number cannot be greater than 3" - }else{ + } + else if (isNaN(parameters.index) || isNaN(parameters.index2)){ + ctx.body = "A number must be entered" + } + else if (Number.isInteger(parameters.index)){ + ctx.body = "A whole number must be entered" + } + else{ const title = books[parameters.index] const title2 = books[parameters.index2] - ctx.body = title + title2 + parameters.index + ctx.body = title + title2 } }) @@ -55,8 +64,19 @@ router.get('/name', ctx => ctx.body = JSON.stringify(ctx.query)) router.get('/hello/:name', ctx => { let myname = ctx.params.name if(ctx.query.format === 'upper') myname = myname.toUpperCase() + else if (ctx.query.format === 'lower') myname = myname.toLowerCase() + else if (ctx.query.format === 'reverse'){ + var array1 = myname.split("") + console.log(array1) + var array2 = array1.reverse() + console.log(array2) + var array3 = array1.join("") + console.log(array3) + ctx.body = `hello ${array3}` + //myname = join(Array.reverse(myname.split())) + } // only applies uppercase if formatting query exists - ctx.body = `hello ${myname}` + //ctx.body = `hello ${myname}` }) router.post('/form', ctx => { From 847df4b9e8bd2d7c2781112653c9d3b7b4ce7690 Mon Sep 17 00:00:00 2001 From: Anir Nathwani Date: Tue, 24 Sep 2019 14:46:15 +0100 Subject: [PATCH 03/70] update --- exercises/07_unit_testing/todo/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/07_unit_testing/todo/package.json b/exercises/07_unit_testing/todo/package.json index 8b83c896..ace21014 100644 --- a/exercises/07_unit_testing/todo/package.json +++ b/exercises/07_unit_testing/todo/package.json @@ -10,7 +10,7 @@ "author": "", "license": "ISC", "dependencies": { - "handlebars": "^4.2.0", + "handlebars": "^4.3.0", "http-status-codes": "^1.3.2", "koa": "^2.8.1", "koa-bodyparser": "^4.2.1", From 6f04e7d7f1b69b0076b099454de1d8d7c38f0bbf Mon Sep 17 00:00:00 2001 From: Anir Nathwani Date: Fri, 27 Sep 2019 10:59:51 +0100 Subject: [PATCH 04/70] test --- exercises/01_setup/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/exercises/01_setup/index.js b/exercises/01_setup/index.js index ef00019f..af07c3e0 100644 --- a/exercises/01_setup/index.js +++ b/exercises/01_setup/index.js @@ -10,3 +10,4 @@ const port = 8080 app.use(async ctx => ctx.body = 'Hello World') module.exports = app.listen(port, () => console.log(`listening on port ${port}`)) +//aasd \ No newline at end of file From cae34b63aaecffb72e83cbd0d94a54d460420d13 Mon Sep 17 00:00:00 2001 From: Anir Nathwani Date: Tue, 8 Oct 2019 14:25:37 +0100 Subject: [PATCH 05/70] push --- .../07_unit_testing/todo/modules/todo.js | 11 +++++++++- .../todo/unit tests/todo.spec.js | 20 ++++++++++++++++++- npm-debug.log | 19 ++++++++++++++++++ 3 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 npm-debug.log diff --git a/exercises/07_unit_testing/todo/modules/todo.js b/exercises/07_unit_testing/todo/modules/todo.js index 5a034683..c03b8174 100644 --- a/exercises/07_unit_testing/todo/modules/todo.js +++ b/exercises/07_unit_testing/todo/modules/todo.js @@ -10,7 +10,16 @@ module.exports.clear = () => { module.exports.add = (item, qty) => { qty = Number(qty) if(isNaN(qty)) throw new Error('the quantity must be a number') - data.push({item: item, qty: qty}) + let flag = false + for(let index in data) { + if (data[index].item === item) { + data[index].qty+= qty + flag = true + } + } + if(flag === false) { + data.push({item: item, qty: qty}) + } } module.exports.getAll = () => { diff --git a/exercises/07_unit_testing/todo/unit tests/todo.spec.js b/exercises/07_unit_testing/todo/unit tests/todo.spec.js index 55eb70db..2c46bac0 100644 --- a/exercises/07_unit_testing/todo/unit tests/todo.spec.js +++ b/exercises/07_unit_testing/todo/unit tests/todo.spec.js @@ -41,8 +41,26 @@ describe('add()', () => { done() } }) - + // New test goes HERE! + test('duplicates should increase qty', async done => { + expect.assertions(2) + try { + // ACT + todo.add('bread', 4) + todo.add('bread', 2) + // ASSERT + const count = todo.countItems() + expect(count).toBe(1) + const data = todo.getAll() + const qty = data[0].qty + expect(qty).toEqual(6) + } catch(err) { + done.fail('test failed') + } finally { + done() + } + }) }) diff --git a/npm-debug.log b/npm-debug.log new file mode 100644 index 00000000..74e9b8d4 --- /dev/null +++ b/npm-debug.log @@ -0,0 +1,19 @@ +0 info it worked if it ends with ok +1 verbose cli [ '/usr/bin/node', '/usr/bin/npm', 'run', 'test' ] +2 info using npm@3.5.2 +3 info using node@v8.10.0 +4 verbose stack Error: ENOENT: no such file or directory, open '/home/anir/foundation/package.json' +5 verbose cwd /home/anir/foundation +6 error Linux 5.0.0-23-generic +7 error argv "/usr/bin/node" "/usr/bin/npm" "run" "test" +8 error node v8.10.0 +9 error npm v3.5.2 +10 error path /home/anir/foundation/package.json +11 error code ENOENT +12 error errno -2 +13 error syscall open +14 error enoent ENOENT: no such file or directory, open '/home/anir/foundation/package.json' +15 error enoent ENOENT: no such file or directory, open '/home/anir/foundation/package.json' +15 error enoent This is most likely not a problem with npm itself +15 error enoent and is related to npm not being able to find a file. +16 verbose exit [ -2, true ] From 111e50081e594b741e9715acc073e5a9a1b3a34d Mon Sep 17 00:00:00 2001 From: "Mark Tyers (aa7401)" Date: Sat, 12 Oct 2019 07:53:17 +0100 Subject: [PATCH 06/70] Updated Git Installation Lab did not explain how to install git on different OS. Now covers how to install git on MacOS using either Xcode or HomeBrew. Covers apt command for Ubuntu and reminds not to install any GUI tools. --- 01 Setup.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/01 Setup.md b/01 Setup.md index a1a4e284..7f94b616 100644 --- a/01 Setup.md +++ b/01 Setup.md @@ -3,7 +3,9 @@ In this worksheet you will learn how to configure your work environment using VS Code. You should start by installing **Visual Studio Code** (NOT VISUAL STUDIO!) from the [website](https://code.visualstudio.com), note that it might already be installed. If you are using a Coventry University computer and the software is not installed you can do this using AppsAnywhere. -If you are using Windows 10 you will also need to install [Git](https://git-scm.com/download/win), this may already be installed on a Coventry University computer. +If you are using Windows 10 you will also need to install [Git](https://git-scm.com/download/win), this may already be installed on a Coventry University computer. If you are on MacOS you may already have it installed as it comes with the XCode IDE but if you have recently updated your OS you may need to run the `xcode-select --install` command to update the **Xcode Command-line Tools** but if you don't want to install XCode you can install git using [HomeBrew](http://brew.sh/) using the `brew install git` command. If you are running Ubuntu you can install it using the `sudo apt install git` command. + +DO NOT INSTALL THE GIT GUI TOOLS! Visual Studio Code comes with an integrated **Terminal** that can be used instead of the standard _Command Prompt_ or _Terminal_. If you are using Linux or MacOS this will give you a Bash prompt however on Windows 10 it defaults to the _Command Prompt_ and will need to be changed to the _Bash Shell_. From 23eca5013e87af5222bea83faafd337d3beb31c6 Mon Sep 17 00:00:00 2001 From: Mark Tyers Date: Sat, 12 Oct 2019 07:58:01 +0100 Subject: [PATCH 07/70] Cleaned Up Files There were some files in the root of the codee quality lab. These have now been put in a directory called linting. --- exercises/06_code_quality/README.md | 8 -------- exercises/06_code_quality/{ => linter}/index.js | 0 exercises/06_code_quality/{ => linter}/jsdoc.conf | 0 .../06_code_quality/{ => linter}/modules/accounts.js | 0 exercises/06_code_quality/{ => linter}/package.json | 0 5 files changed, 8 deletions(-) delete mode 100644 exercises/06_code_quality/README.md rename exercises/06_code_quality/{ => linter}/index.js (100%) rename exercises/06_code_quality/{ => linter}/jsdoc.conf (100%) rename exercises/06_code_quality/{ => linter}/modules/accounts.js (100%) rename exercises/06_code_quality/{ => linter}/package.json (100%) diff --git a/exercises/06_code_quality/README.md b/exercises/06_code_quality/README.md deleted file mode 100644 index 19df846d..00000000 --- a/exercises/06_code_quality/README.md +++ /dev/null @@ -1,8 +0,0 @@ -# Assignment Template - -This repository contains the base files for the assignment. To make use of this carry out the following steps: - -1. Fork this repository but change its name (replace `xxx` with your university username): - 1. If this is your original assignment, `xxx-coursework`. - 2. If this is your resit assignment code, `xxx-resit`. -2. Replace the contents of this file with the details of the topic you have been assigned. diff --git a/exercises/06_code_quality/index.js b/exercises/06_code_quality/linter/index.js similarity index 100% rename from exercises/06_code_quality/index.js rename to exercises/06_code_quality/linter/index.js diff --git a/exercises/06_code_quality/jsdoc.conf b/exercises/06_code_quality/linter/jsdoc.conf similarity index 100% rename from exercises/06_code_quality/jsdoc.conf rename to exercises/06_code_quality/linter/jsdoc.conf diff --git a/exercises/06_code_quality/modules/accounts.js b/exercises/06_code_quality/linter/modules/accounts.js similarity index 100% rename from exercises/06_code_quality/modules/accounts.js rename to exercises/06_code_quality/linter/modules/accounts.js diff --git a/exercises/06_code_quality/package.json b/exercises/06_code_quality/linter/package.json similarity index 100% rename from exercises/06_code_quality/package.json rename to exercises/06_code_quality/linter/package.json From 9b23edb60ae797a6ec4ef3ea70ca1e2911982783 Mon Sep 17 00:00:00 2001 From: Mark Tyers Date: Sat, 12 Oct 2019 09:21:11 +0100 Subject: [PATCH 08/70] Updated ESLint and JSDoc Exercise The exercise was unclear. Exercise is now based on the todo files which have been updated --- .eslintrc.json | 1 + .gitignore | 1 + 06 Code Quality.md | 34 +++--- exercises/06_code_quality/linter/index.js | 107 ++++-------------- .../linter/jest-test.config.js | 20 ++++ exercises/06_code_quality/linter/jsdoc.conf | 22 ---- .../linter/modules/accounts.js | 60 ---------- .../06_code_quality/linter/modules/todo.js | 26 +++++ exercises/06_code_quality/linter/package.json | 48 +++----- .../06_code_quality/linter/public/style.css | 11 ++ exercises/06_code_quality/linter/readme.md | 6 + .../linter/unit tests/todo.spec.js | 59 ++++++++++ .../06_code_quality/linter/views/empty.hbs | 19 ++++ .../06_code_quality/linter/views/home.hbs | 33 ++++++ exercises/06_code_quality/todo/index.js | 98 ++++++++-------- .../06_code_quality/todo/modules/list.js | 73 +++++++----- exercises/06_code_quality/todo/package.json | 5 +- .../06_code_quality/unit tests/user.spec.js | 76 ------------- .../06_code_quality/views/error.handlebars | 16 --- .../06_code_quality/views/index.handlebars | 16 --- .../06_code_quality/views/login.handlebars | 24 ---- .../06_code_quality/views/register.handlebars | 21 ---- 22 files changed, 330 insertions(+), 446 deletions(-) create mode 100644 exercises/06_code_quality/linter/jest-test.config.js delete mode 100644 exercises/06_code_quality/linter/jsdoc.conf delete mode 100644 exercises/06_code_quality/linter/modules/accounts.js create mode 100644 exercises/06_code_quality/linter/modules/todo.js create mode 100644 exercises/06_code_quality/linter/public/style.css create mode 100644 exercises/06_code_quality/linter/readme.md create mode 100644 exercises/06_code_quality/linter/unit tests/todo.spec.js create mode 100644 exercises/06_code_quality/linter/views/empty.hbs create mode 100644 exercises/06_code_quality/linter/views/home.hbs delete mode 100644 exercises/06_code_quality/unit tests/user.spec.js delete mode 100644 exercises/06_code_quality/views/error.handlebars delete mode 100644 exercises/06_code_quality/views/index.handlebars delete mode 100644 exercises/06_code_quality/views/login.handlebars delete mode 100644 exercises/06_code_quality/views/register.handlebars diff --git a/.eslintrc.json b/.eslintrc.json index 3fb6a540..fb7e68bd 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -53,6 +53,7 @@ "no-var": 2, "prefer-arrow-callback": 1, "prefer-const": 2, + "prefer-template": "error", "quotes": [1, "single"], "semi": [1, "never"], "space-before-blocks": ["error", { "functions": "always", "keywords": "always", "classes": "always" }], diff --git a/.gitignore b/.gitignore index 008f8e67..6dcdeeca 100644 --- a/.gitignore +++ b/.gitignore @@ -8,6 +8,7 @@ coverage/ docs/ sessions/ screenshots/* +out/ # sqlite databases # *.db diff --git a/06 Code Quality.md b/06 Code Quality.md index a65ca43d..5972de6a 100644 --- a/06 Code Quality.md +++ b/06 Code Quality.md @@ -56,7 +56,7 @@ The custom object prototype defined in the `list.js` module already contains the Now much of the business logic has been moved to the separate module, are there any module imports in `index.js` that are no longer needed? Locate these and delete. -## 2 Linting +## 3 Linting When using a language as flexible as JavaScript which contains so many legal (but terrible) features, it is important to use a linter. This will check your code against a set of rules. These ensure: @@ -64,14 +64,14 @@ When using a language as flexible as JavaScript which contains so many legal (bu 2. You are implementing optional syntax (such as indentation and semicolons) in a consistent manner. 3. You are writing code that is easy to maintain. -If you look over both your `index.js` and `accounts.js` files you should be feeling pretty comfortable that you are already writing clean, consistent and maintainable code, lets see how good your code really is! +Locate the `06_code_quality/todo/` directory and study the `index.js` file. You should be feeling pretty comfortable that you are looking at clean, consistent and maintainable code, lets see how good your code really is! -You should start by ensuring you have installed `eslint` which is considered the industry standard and that you have a copy of the approved configuration file `.eslintrc.json` in the root directory of your project. You can find this in the `TEACHING-MATERIALS` repository but make sure you take a copy of the latest version from the master repository! +You should start by ensuring you have installed `eslint` which is considered the industry standard and that you have a copy of the approved configuration file `.eslintrc.json` in the root directory of your project. -Try running the linter on your `index.js` routes file: +Now navigate to the `06_code_quality/` directory using terminal and run the linter on the `index.js` code in the `todo/` directory: ```shell -$ node_modules/.bin/eslint index.js +$ node_modules/.bin/eslint todo/index.js ``` You will see a list of issues that the linter has flagged in your code. Notice that some of these are flagged as errors (serious) and some as warnings (recommendations). Each message includes: @@ -85,38 +85,38 @@ The latter can be used to quickly look up the rules in the [comprehensive docume Instead of running separate checks on every file, we can specify the directory we want to check and it will automatically scan all the subdirectories. For example to scan all the files in the `modules/` directory we could run: ```shell -$ node_modules/.bin/eslint modules/ +$ node_modules/.bin/eslint todo/ ``` -### 2.1 Test Your Understanding +### 3.1 Test Your Understanding -1. How could you run the linter to scan _all_ the files in your project (HINT: you need to start scanning in the _current directory_)? -2. Now you should locate and fix all the errors and warnings in your code. -3. If you are using VS Code, install `eslint` globally and then install the [eslint extension](https://github.com/Microsoft/vscode-eslint). After restarting your editor you should see any errors and warnings flagged in the editor. +1. Locate and fix all the errors and warnings in the `index.js`. +2. Install `eslint` globally and then install the [eslint extension](https://github.com/Microsoft/vscode-eslint). After restarting your editor you should see any errors and warnings flagged in the editor. +3. Use the `eslint` plugin to locate and fix all the errors in the `modules/list.js` file. -## 3 Documentation +## 4 Documentation In this third and last topic we will be using the [JSDoc](http://usejsdoc.org) tool to build a detailed code documentation website by extracting special comments inserted into our source code. The default set of documentation tools provided in JSDoc are not suitable for documenting Koa routes and so we will be using a plugin called [jsdoc-route-plugin](https://www.npmjs.com/package/jsdoc-route-plugin). This should have been installed by the package manifest however you should check that you are using the current version of the `package.json` file and update if needed, rerunning the `npm install` command to ensure all packages are installed. You should also check that you have the latest version of the `jsdoc.conf` configuration file. -Now everything is installed we can run the `jsdoc` tool to generate our documentation. +Now everything is installed we can run the `jsdoc` tool on the project in the `todo/` directory which will generate our documentation. The `-d` destination flag tells the tool where to save the documentation. ```shell -$ node_modules/.bin/jsdoc +$ ./node_modules/.bin/jsdoc -d ./docs/jsdoc/ modules/* ``` If you run this command you should see a new directory called `docs/` which will contain a `jsdoc/` directory. Inside this you will see some website files, opening the `index.html` file in your browser you should see the documentation pages for your website! -### 3.1 Test Your Understanding +### 4.1 Test Your Understanding You will probably have noticed that only a couple of the functions include complete JSDoc comments and so the documentation website is incomplete. Your task is to use the existing comments for guidance and complete the task of documenting your code. You will find the [JSDoc](http://usejsdoc.org) and [jsdoc-route-plugin](https://www.npmjs.com/package/jsdoc-route-plugin) documentation helpful. -## 4 Improved Async Code +## 5 Improved Async Code Since NodeJS has a single thread that handles all incoming requests it is vital that we push long-running tasks into their own threads, typically through the use of _callback functions_. In this section of the lab you will learn about the limitations of callbacks and explore more powerful ways to handle multi-threading. -## 4.1 Nested Callbacks +## 5.1 Nested Callbacks Because the code to be run after a callback is run needs to be _inside_ the callback code it is very challenging to build a script that contains several long-running tasks you get into a situation where you nest callbacks inside callbacks (inside callbacks) which makes the code very difficult to write, debug and read and means its very difficult to split into separate functions, a situation commonly known as **Callback Hell**. @@ -129,7 +129,7 @@ Open the file `nestedCallbacks.js` which asks for a _base_ currency code then pr Callbacks are the simplest possible mechanism for asynchronous code in JavaScript. Unfortunately, raw callbacks sacrifice the control flow, exception handling, and function semantics familiar from synchronous code. -### 4.1 Test Your Knowledge +### 5.2 Test Your Knowledge The callbacks are already nested 3 deep. To test your knowledge of deeply nested callbacks you are going to create a script that has 6 levels of nested callbacks! diff --git a/exercises/06_code_quality/linter/index.js b/exercises/06_code_quality/linter/index.js index 43c2fcd1..86e1c6e0 100644 --- a/exercises/06_code_quality/linter/index.js +++ b/exercises/06_code_quality/linter/index.js @@ -1,115 +1,56 @@ #!/usr/bin/env node -/** - * Routes File - */ - 'use strict' -/* MODULE IMPORTS */ -const bcrypt = require('bcrypt-promise') const Koa = require('koa') const Router = require('koa-router') -const views = require('koa-views') -const staticDir = require('koa-static') +const stat = require('koa-static') const bodyParser = require('koa-bodyparser') -const koaBody = require('koa-body')({multipart: true, uploadDir: '.'}) -const session = require('koa-session') -const sqlite = require('sqlite-async') -const fs = require('fs-extra') -const mime = require('mime-types') -//const jimp = require('jimp') - -/* IMPORT CUSTOM MODULES */ -const User = require('./modules/accounts') +const handlebars = require('koa-hbs-renderer') const app = new Koa() const router = new Router() - -/* CONFIGURING THE MIDDLEWARE */ -app.keys = ['darkSecret'] -app.use(staticDir('public')) +app.use(stat('public')) app.use(bodyParser()) -app.use(session(app)) -app.use(views(`${__dirname}/views`, { extension: 'handlebars' }, {map: { handlebars: 'handlebars' }})) +app.use(handlebars({ paths: { views: `${__dirname}/views` } })) +app.use(router.routes()) + +const port = 8080 -const defaultPort = 8080 -const port = process.env.PORT || defaultPort -const dbName = 'website.db' -const saltRounds = 10 +const todo = require('./modules/todo') -/** - * The secure home page. - * - * @name Home Page - * @route {GET} / - * @authentication This route requires cookie-based authentication. - */ router.get('/', async ctx => { try { - if(ctx.session.authorised !== true) return ctx.redirect('/login?msg=you need to log in') const data = {} if(ctx.query.msg) data.msg = ctx.query.msg - await ctx.render('index') + data.items = todo.getAll() + ctx.render('home', data) } catch(err) { - await ctx.render('error', {message: err.message}) + console.log(err.message) + ctx.render('home', {msg: err.message}) } }) -/** - * The user registration page. - * - * @name Register Page - * @route {GET} /register - */ -router.get('/register', async ctx => await ctx.render('register')) - -/** - * The script to process new user registrations. - * - * @name Register Script - * @route {POST} /register - */ -router.post('/register', koaBody, async ctx => { +router.post('/', ctx => { try { - // extract the data from the request const body = ctx.request.body - console.log(body) - const {path, type} = ctx.request.files.avatar - // call the functions in the module - const user = await new User(dbName) - await user.register(body.user, body.pass) - // await user.uploadPicture(path, type) - // redirect to the home page - ctx.redirect(`/?msg=new user "${body.name}" added`) + todo.add(body.item, body.qty) + ctx.redirect('/') } catch(err) { - await ctx.render('error', {message: err.message}) + console.log(err.message) + ctx.redirect(`/?msg=${err.message}`) } }) -router.get('/login', async ctx => { - const data = {} - if(ctx.query.msg) data.msg = ctx.query.msg - if(ctx.query.user) data.user = ctx.query.user - await ctx.render('login', data) -}) - -router.post('/login', async ctx => { +router.get('/delete/:key', ctx => { try { - const body = ctx.request.body - const user = await new User(dbName) - await user.login(body.user, body.pass) - ctx.session.authorised = true - return ctx.redirect('/?msg=you are now logged in...') + console.log(`key: ${ctx.params.key}`) + todo.delete(ctx.params.key) + ctx.redirect('/msg=item deleted') } catch(err) { - await ctx.render('error', {message: err.message}) + console.log(err.message) + ctx.redirect(`/${err.message}`) } }) -router.get('/logout', async ctx => { - ctx.session.authorised = null - ctx.redirect('/?msg=you are now logged out') -}) - -app.use(router.routes()) -module.exports = app.listen(port, async() => console.log(`listening on port ${port}`)) +module.exports = app.listen(port, () => console.log(`listening on port ${port}`)) diff --git a/exercises/06_code_quality/linter/jest-test.config.js b/exercises/06_code_quality/linter/jest-test.config.js new file mode 100644 index 00000000..02243478 --- /dev/null +++ b/exercises/06_code_quality/linter/jest-test.config.js @@ -0,0 +1,20 @@ + +'use strict'; + +module.exports = { + displayName: 'test', + verbose: true, + collectCoverage: true, + coverageThreshold: { + global: { + branches: 0, + functions: 0, + lines: 0, + statements: 0 + } + }, + testPathIgnorePatterns: [ + '/node_modules/', + '/__tests__/fixtures/', + ] +} diff --git a/exercises/06_code_quality/linter/jsdoc.conf b/exercises/06_code_quality/linter/jsdoc.conf deleted file mode 100644 index 9fa536f2..00000000 --- a/exercises/06_code_quality/linter/jsdoc.conf +++ /dev/null @@ -1,22 +0,0 @@ - -{ - "tags": { - "allowUnknownTags": true, - "dictionaries": ["jsdoc","closure"] - }, - "source": { - "include": [ "." ], - "exclude": [ "node_modules" ], - "includePattern": ".+\\.js(doc|x)?$", - "excludePattern": "(^|\\/|\\\\)_" - }, - "plugins": ["jsdoc-route-plugin"], - "templates": { - "cleverLinks": false, - "monospaceLinks": false - }, - "opts": { - "destination": "docs/jsdoc", - "recurse": true - } -} diff --git a/exercises/06_code_quality/linter/modules/accounts.js b/exercises/06_code_quality/linter/modules/accounts.js deleted file mode 100644 index fd1c7ec4..00000000 --- a/exercises/06_code_quality/linter/modules/accounts.js +++ /dev/null @@ -1,60 +0,0 @@ - -'use strict' - -const bcrypt = require('bcrypt-promise') -const fs = require('fs-extra') -const mime = require('mime-types') -const sqlite = require('sqlite-async') -const saltRounds = 10 - -module.exports = class User { - - constructor(dbName = ':memory:') { - return (async() => { - this.db = await sqlite.open(dbName) - // we need this table to store the user accounts - const sql = 'CREATE TABLE IF NOT EXISTS users (id INTEGER PRIMARY KEY AUTOINCREMENT, user TEXT, pass TEXT);' - await this.db.run(sql) - return this - })() - } - - async register(user, pass) { - try { - if(user.length === 0) throw new Error('missing username') - if(pass.length === 0) throw new Error('missing password') - let sql = `SELECT COUNT(id) as records FROM users WHERE user="${user}";` - const data = await this.db.get(sql) - if(data.records !== 0) throw new Error(`username "${user}" already in use`) - pass = await bcrypt.hash(pass, saltRounds) - sql = `INSERT INTO users(user, pass) VALUES("${user}", "${pass}")` - await this.db.run(sql) - return true - } catch(err) { - throw err - } - } - - async uploadPicture(path, mimeType) { - const extension = mime.extension(mimeType) - console.log(`path: ${path}`) - console.log(`extension: ${extension}`) - //await fs.copy(path, `public/avatars/${username}.${fileExtension}`) - } - - async login(username, password) { - try { - let sql = `SELECT count(id) AS count FROM users WHERE user="${username}";` - const records = await this.db.get(sql) - if(!records.count) throw new Error(`username "${username}" not found`) - sql = `SELECT pass FROM users WHERE user = "${username}";` - const record = await this.db.get(sql) - const valid = await bcrypt.compare(password, record.pass) - if(valid === false) throw new Error(`invalid password for account "${username}"`) - return true - } catch(err) { - throw err - } - } - -} \ No newline at end of file diff --git a/exercises/06_code_quality/linter/modules/todo.js b/exercises/06_code_quality/linter/modules/todo.js new file mode 100644 index 00000000..f4fdd7b8 --- /dev/null +++ b/exercises/06_code_quality/linter/modules/todo.js @@ -0,0 +1,26 @@ + +'use strict' + +let data = [] + +module.exports.clear = () => { + data = [] +} + +module.exports.add = (item, qty) => { + qty = Number(qty) + if(isNaN(qty)) throw new Error('qty must be a number') + data.push({item: item, qty: qty}) +} + +module.exports.getAll = () => { + for(const key in data) data[key].key = key + return data +} + +module.exports.delete = key => { + console.log(`delete key ${key}`) + return +} + +module.exports.countItems = () => data.length diff --git a/exercises/06_code_quality/linter/package.json b/exercises/06_code_quality/linter/package.json index 6eb0a08d..8b83c896 100644 --- a/exercises/06_code_quality/linter/package.json +++ b/exercises/06_code_quality/linter/package.json @@ -1,50 +1,32 @@ { - "name": "10_auth", + "name": "todo", "version": "1.0.0", "description": "", "main": "index.js", - "engines": { - "node": "12.x" - }, "scripts": { - "start": "node index.js", - "acceptance": "jest --coverage --detectOpenHandles", - "jsdoc": "node_modules/.bin/jsdoc -c jsdoc.conf", "linter": "node_modules/.bin/eslint .", - "test": "jest --coverage --detectOpenHandles", - "unit": "node_modules/.bin/jest --coverage --runInBand tests/unit/" - }, - "jest": { - "projects": [ - "/jest-test.config.js" - ] + "test": "node_modules/.bin/jest --coverage --runInBand" }, "author": "", "license": "ISC", "dependencies": { - "bcrypt": "^3.0.6", - "bcrypt-promise": "^2.0.0", - "fs-extra": "^7.0.1", - "handlebars": "^4.1.2", - "koa": "^2.6.2", - "koa-body": "^4.0.8", + "handlebars": "^4.2.0", + "http-status-codes": "^1.3.2", + "koa": "^2.8.1", "koa-bodyparser": "^4.2.1", + "koa-handlebars": "^1.0.0", + "koa-hbs-renderer": "^1.2.0", "koa-router": "^7.4.0", - "koa-session": "^5.10.1", "koa-static": "^5.0.0", - "koa-views": "^6.1.5", - "mime-types": "^2.1.22", - "readline": "^1.3.0", - "readline-sync": "^1.4.10", - "request": "^2.88.0", - "sqlite-async": "^1.0.11" + "koa-views": "^6.2.1" }, "devDependencies": { - "eslint": "^5.15.2", - "handlebars-validate": "^0.1.2", - "http-status-codes": "^1.3.2", - "jest": "^24.1.0", - "jsdoc": "^3.6.3", - "jsdoc-route-plugin": "^0.1.0" + "jest": "^24.9.0", + "supertest": "^4.0.2" + }, + "jest": { + "projects": [ + "/jest-test.config.js" + ] } } diff --git a/exercises/06_code_quality/linter/public/style.css b/exercises/06_code_quality/linter/public/style.css new file mode 100644 index 00000000..8a5442c3 --- /dev/null +++ b/exercises/06_code_quality/linter/public/style.css @@ -0,0 +1,11 @@ + +body { + font-family: Arial, Helvetica, sans-serif; +} + +.msg { + border: 1px solid red; + font-weight: bold; + color: red; + padding: 1em; +} diff --git a/exercises/06_code_quality/linter/readme.md b/exercises/06_code_quality/linter/readme.md new file mode 100644 index 00000000..915a7e3a --- /dev/null +++ b/exercises/06_code_quality/linter/readme.md @@ -0,0 +1,6 @@ + +# ToDo + +This project is designed to teach you how to write and debug unit tests and employ the Test-Driven Development (TDD) methodology in your software development. + +You should open this directory directly in VS Code, ensuring that this file is in the root of the file tree. diff --git a/exercises/06_code_quality/linter/unit tests/todo.spec.js b/exercises/06_code_quality/linter/unit tests/todo.spec.js new file mode 100644 index 00000000..55eb70db --- /dev/null +++ b/exercises/06_code_quality/linter/unit tests/todo.spec.js @@ -0,0 +1,59 @@ + +'use strict' + +const todo = require('../modules/todo.js') + +beforeAll( async() => { + // stuff to do before any of the tests run +}) + +afterAll( async() => { + // runs after all the tests have completed +}) + +describe('add()', () => { + // block of tests + beforeEach( async() => { + todo.clear() + }) + afterEach( async() => { + // runs after each test completes + }) + test('add a single item', async done => { + expect.assertions(1) + try { + todo.add('bread', 3) + expect(todo.countItems()).toBe(1) + } catch(err) { + done.fail(err) + } finally { + done() + } + }) + test('qty must be a number', async done => { + expect.assertions(1) + try { + todo.add('bread', 'three') + done.fail('test failed') + } catch(err) { + expect(err.message).toBe('qty must be a number') + } finally { + done() + } + }) + + // New test goes HERE! + +}) + +describe('delete()', () => { + // any tests for the delete() function should be written here +}) + +describe('getAll()', () => { + // any tests for the getAll() function should be written here +}) + +describe('clear()', () => { + // any tests for the clear() function should be written here +}) diff --git a/exercises/06_code_quality/linter/views/empty.hbs b/exercises/06_code_quality/linter/views/empty.hbs new file mode 100644 index 00000000..6be9593a --- /dev/null +++ b/exercises/06_code_quality/linter/views/empty.hbs @@ -0,0 +1,19 @@ + + + + + ToDo List + + + +

ToDo List

+

Your list is empty, lets add some items...

+
+ Item: + + Qty: + + +
+ + diff --git a/exercises/06_code_quality/linter/views/home.hbs b/exercises/06_code_quality/linter/views/home.hbs new file mode 100644 index 00000000..1a9495f0 --- /dev/null +++ b/exercises/06_code_quality/linter/views/home.hbs @@ -0,0 +1,33 @@ + + + + + ToDo List + + + +

ToDo List

+

My List

+ {{#if msg}} +

{{msg}}

+ {{/if}} + {{#if items.length}} + + + + {{#each items}} + + {{/each}} +
Shopping List
ItemQtyAction
{{this.item}}{{this.qty}}delete
+ {{else}} +

Your list is empty, lets add some items...

+ {{/if}} +
+ Item: + + Qty: + + +
+ + diff --git a/exercises/06_code_quality/todo/index.js b/exercises/06_code_quality/todo/index.js index 914ec5bf..111255db 100644 --- a/exercises/06_code_quality/todo/index.js +++ b/exercises/06_code_quality/todo/index.js @@ -1,61 +1,57 @@ #!/usr/bin/env node -'use strict' +var Koa = require("koa") +var Router = require("koa-router"); +var stat = require("koa-static"); +var bodyParser = require("koa-bodyparser"); +var handlebars = require("koa-hbs-renderer"); -const Koa = require('koa') -const Router = require('koa-router') -const stat = require('koa-static') -const bodyParser = require('koa-bodyparser') -const handlebars = require('koa-hbs-renderer') +var app = new Koa(); +var router = new Router(); +app.use(stat ("public")); +app.use(bodyParser()); +app.use(handlebars({ paths: { views: __dirname + "/views" } })); +app.use(router.routes()); -const app = new Koa() -const router = new Router() -app.use(stat('public')) -app.use(bodyParser()) -app.use(handlebars({ paths: { views: `${__dirname}/views` } })) -app.use(router.routes()) -const port = 8080 +var port = 8080 -const items = [] +var items = [] // const List = require('./modules/list') // const list = new List() -router.get('/', async ctx => { - try { - const data = {} - if(ctx.query.msg) data.msg = ctx.query.msg - data.items = items.map( (element, index) => ({key: index, item: element.item, qty: element.qty})) - console.log(data.items) - ctx.render('home', data) - } catch(err) { - console.log(err.message) - ctx.render('home', {msg: err.message}) - } -}) - -router.post('/', ctx => { - try { - const body = ctx.request.body - const data = {item: body.item, qty: body.qty} - items.push(data) - ctx.redirect('/') - } catch(err) { - console.log(err.message) - ctx.redirect(`/?msg=${err.message}`) - } -}) - -router.get('/delete/:key', ctx => { - try { - console.log(`key: ${ctx.params.key}`) - items.splice(ctx.params.key, 1) - ctx.redirect('/msg=item deleted') - } catch(err) { - console.log(err.message) - ctx.redirect(`/${err.message}`) - } -}) - -module.exports = app.listen(port, () => console.log(`listening on port ${port}`)) +router.get("/", async function(ctx) { + try { + var data = {} + } catch(err) { + console.log(err.message); + ctx.render('home', {msg: err.message}); + } +}); + +router.post("/", function(ctx) { + try { + var body = ctx.request.body; + var data = {item: body.item, qty: body.qty}; + items.push(data); + ctx.redirect("/"); + } catch(err) { + console.log(err.message); + ctx.redirect("/?msg=" + err.message); + } +}); + +router.get("/delete/:key", function(ctx) { + try { + console.log(`key: ${ctx.params.key}`); + items.splice(ctx.params.key, 1); + ctx.redirect('/msg=item deleted'); + } catch(err) { + console.log(err.message); + ctx.redirect("/" + err.message); + } +}); + +module.exports = app.listen(port, function() { +}); \ No newline at end of file diff --git a/exercises/06_code_quality/todo/modules/list.js b/exercises/06_code_quality/todo/modules/list.js index 0849e064..103f77e6 100644 --- a/exercises/06_code_quality/todo/modules/list.js +++ b/exercises/06_code_quality/todo/modules/list.js @@ -1,27 +1,48 @@ -'use strict' - -module.exports = class List { - - constructor() { - this.items = [] - } - - add(item, qty) { - const data = {item: item, qty: qty} - this.items.push(data) - } - - getAll() { - return this.items.map( (element, index) => ({key: index, item: element.item, qty: element.qty})) - } - - delete(id) { - this.items.splice(id, 1) - } - - count() { - return this.items.count - } - -} +/** + * Class representing a list of items. + * */ +module.exports = class List { + + /** + * Create a list. + */ + constructor(){ + this.items = []; + } + + /** + * Add an item to the list. + * @param {String} item - The name of the eitem. + * @param {Number} qty - The number of items to add. + */ + add(item, qty) { + var data = {item: item, qty: qty}; + this.items.push(data); + } + + /** + * Return the list of items. + * @return {Array.<{item: String, qty: Number}>} An array containing the items. + */ + getAll(){ + return this.items.map( (element, index) => ({key: index, item: element.item, qty: element.qty})); + } + + /** + * Delete a single item. + * @param {Number} id - The index to be deleted. + */ + delete(id){ + this.items.splice(id, 1); + } + + /** + * Return the number of items in the list. + * @return {Number} The number of items. + */ + count(){ + return this.items.count; + } + +} \ No newline at end of file diff --git a/exercises/06_code_quality/todo/package.json b/exercises/06_code_quality/todo/package.json index e3637641..f8b39ff3 100644 --- a/exercises/06_code_quality/todo/package.json +++ b/exercises/06_code_quality/todo/package.json @@ -18,5 +18,8 @@ "koa-static": "^5.0.0", "koa-views": "^6.2.1" }, - "devDependencies": {} + "devDependencies": { + "eslint": "^6.5.1", + "jsdoc": "^3.6.3" + } } diff --git a/exercises/06_code_quality/unit tests/user.spec.js b/exercises/06_code_quality/unit tests/user.spec.js deleted file mode 100644 index 886d3440..00000000 --- a/exercises/06_code_quality/unit tests/user.spec.js +++ /dev/null @@ -1,76 +0,0 @@ - -'use strict' - -const Accounts = require('../modules/user.js') - -describe('register()', () => { - - test('register a valid account', async done => { - expect.assertions(1) - const account = await new Accounts() - const register = await account.register('doej', 'password') - expect(register).toBe(true) - done() - }) - - test('register a duplicate username', async done => { - expect.assertions(1) - const account = await new Accounts() - await account.register('doej', 'password') - await expect( account.register('doej', 'password') ) - .rejects.toEqual( Error('username "doej" already in use') ) - done() - }) - - test('error if blank username', async done => { - expect.assertions(1) - const account = await new Accounts() - await expect( account.register('', 'password') ) - .rejects.toEqual( Error('missing username') ) - done() - }) - - test('error if blank password', async done => { - expect.assertions(1) - const account = await new Accounts() - await expect( account.register('doej', '') ) - .rejects.toEqual( Error('missing password') ) - done() - }) - -}) - -describe('uploadPicture()', () => { - // this would have to be done by mocking the file system - // perhaps using mock-fs? -}) - -describe('login()', () => { - test('log in with valid credentials', async done => { - expect.assertions(1) - const account = await new Accounts() - await account.register('doej', 'password') - const valid = await account.login('doej', 'password') - expect(valid).toBe(true) - done() - }) - - test('invalid username', async done => { - expect.assertions(1) - const account = await new Accounts() - await account.register('doej', 'password') - await expect( account.login('roej', 'password') ) - .rejects.toEqual( Error('username "roej" not found') ) - done() - }) - - test('invalid password', async done => { - expect.assertions(1) - const account = await new Accounts() - await account.register('doej', 'password') - await expect( account.login('doej', 'bad') ) - .rejects.toEqual( Error('invalid password for account "doej"') ) - done() - }) - -}) diff --git a/exercises/06_code_quality/views/error.handlebars b/exercises/06_code_quality/views/error.handlebars deleted file mode 100644 index 11fe16d0..00000000 --- a/exercises/06_code_quality/views/error.handlebars +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - ERROR - - - - - -

An Error Has Occurred

-

{{message}}

- - diff --git a/exercises/06_code_quality/views/index.handlebars b/exercises/06_code_quality/views/index.handlebars deleted file mode 100644 index 5d9be040..00000000 --- a/exercises/06_code_quality/views/index.handlebars +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - Home Page - - - - - -

Home

-

This is a secure page. Users need to have a valid account and be logged in to see it.

-

log out

- diff --git a/exercises/06_code_quality/views/login.handlebars b/exercises/06_code_quality/views/login.handlebars deleted file mode 100644 index e42e65bd..00000000 --- a/exercises/06_code_quality/views/login.handlebars +++ /dev/null @@ -1,24 +0,0 @@ - - - - - - - Log In - - - - - -

Log In

- {{#if msg}} -

{{msg}}

- {{/if}} -
-

Username:

-

Password:

-

-
-

register

- - diff --git a/exercises/06_code_quality/views/register.handlebars b/exercises/06_code_quality/views/register.handlebars deleted file mode 100644 index 2e543b83..00000000 --- a/exercises/06_code_quality/views/register.handlebars +++ /dev/null @@ -1,21 +0,0 @@ - - - - - - - Create an Account - - - - - -

Create an Account

-
-

Username:

-

Password:

-

Profile Picture:

-

-
- - From d1c17c9aa7f731e151244e4918ab7294b879ebed Mon Sep 17 00:00:00 2001 From: Mark Tyers Date: Sat, 12 Oct 2019 10:01:23 +0100 Subject: [PATCH 09/70] Fixed Callback Code There was an issue with the existing code (logical error) Code has been rewritten to allow for multiple input prompts. --- exercises/06_code_quality/nestedCallbacks.js | 76 ++++++++------------ 1 file changed, 30 insertions(+), 46 deletions(-) diff --git a/exercises/06_code_quality/nestedCallbacks.js b/exercises/06_code_quality/nestedCallbacks.js index 6d89b729..6624c19b 100644 --- a/exercises/06_code_quality/nestedCallbacks.js +++ b/exercises/06_code_quality/nestedCallbacks.js @@ -1,61 +1,45 @@ +#!/usr/bin/env node + +/* eslint max-lines-per-function: 0 */ 'use strict' const request = require('request') +const readline = require('readline') + +const io = { input: process.stdin, output: process.stdout } -getInput('enter base currency', (err, base) => { - if (err) { - console.log(err.message) - process.exit() - } +const read = readline.createInterface(io) +read.question('input base currency: ', base => { + console.log(`You entered ${base}`) + read.close() base = base.trim() - checkValidCurrencyCode(base, err => { + // now we need to check the code is valid + request('https://api.exchangeratesapi.io/latest', (err, res, body) => { if (err) { - console.log(err.message) + console.error(err.message) + process.exit() + } + const rates = JSON.parse(body).rates + if (!rates.hasOwnProperty(base)) { + console.error(`invalid currency code ${base}`) process.exit() } - getData(`https://api.exchangeratesapi.io/latest?base=${base}`, (err, data) => { + // now we can get the currency rates + request(`https://api.exchangeratesapi.io/latest?base=${base}`, (err, res, body) => { if (err) { - console.log(err.message) + console.error(err.message) process.exit() } - const obj = JSON.parse(data) - printObject(obj) - process.exit() + body = JSON.parse(body) + console.log(body) + // lets ask another question + const read = readline.createInterface(io) + read.question('convert to: ', curr => { + console.log(curr) + read.close() + process.exit + }) }) }) }) - -function getInput(prompt, callback) { - try { - process.stdin.resume() - process.stdin.setEncoding('utf8') - process.stdout.write(`${prompt}: `) - process.stdin.on('data', text => callback(null, text)) - } catch(err) { - callback(err) - } -} - -function checkValidCurrencyCode(code, callback) { - code = code.trim() - request('https://api.exchangeratesapi.io/latest', (err, res, body) => { - if (err) callback(new Error('invalid API call')) - const rates = JSON.parse(body).rates - if (!rates.hasOwnProperty(code)) callback(new Error(`invalid currency code ${code}`)) - callback(null, true) - }) -} - -function getData(url, callback) { - request(url, (err, res, body) => { - if (err) callback(new Error('invalid API call')) - callback(null, body) - }) -} - -function printObject(data) { - const indent = 2 - const str = JSON.stringify(data, null, indent) - console.log(str) -} From 9629baa4f1a6173590b2c97278d4bb785c965a8a Mon Sep 17 00:00:00 2001 From: Mark Tyers Date: Sat, 12 Oct 2019 10:18:15 +0100 Subject: [PATCH 10/70] Updated Lab Sheet The nested callback exercise did not match the updated code Lab exercise has now been revised to match --- 06 Code Quality.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/06 Code Quality.md b/06 Code Quality.md index 5972de6a..84d837d0 100644 --- a/06 Code Quality.md +++ b/06 Code Quality.md @@ -131,10 +131,10 @@ Callbacks are the simplest possible mechanism for asynchronous code in JavaScrip ### 5.2 Test Your Knowledge -The callbacks are already nested 3 deep. To test your knowledge of deeply nested callbacks you are going to create a script that has 6 levels of nested callbacks! +The callbacks are already nested 4 deep. You are now going to add some additional functionality and, in doing this, are going to have to make use of additional nested callbacks! -1. modify the script to ask for the currency to convert to and display only the one conversion rate. -2. instead of printing the exchange rate, ask for the amount to be converted and them return the equivalent in the chosen currency +1. The deepest callback is a prompt asking the user for the currency they want to convert into. Add the logic to retrieve the correct exchange rate from the data returned from the previous API call. +2. Instead of printing the exchange rate, ask for the amount to be converted and them return the equivalent in the chosen currency 3. The `currencies.json` file contains a map between the currency code and the country name. Load this file into the script using the [`fs`](https://nodejs.org/api/fs.html) module, convert to a JavaScript object using the [`JSON`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON) object and use it to display the full name of the chosen currency. Below is some code to get you started. You will need to import the `fs` module and use the `fs.readFile()` function which takes a callback! From c0aa4ed9f582fc3748e4f3bf7e75b9e14389ab86 Mon Sep 17 00:00:00 2001 From: Mark Tyers Date: Sat, 12 Oct 2019 10:26:02 +0100 Subject: [PATCH 11/70] Completed Lab Sheet Minor amendments were needed --- 06 Code Quality.md | 2 + exercises/.images/jsdoc.png | Bin 0 -> 86935 bytes exercises/05_javascript/nestedcallbacks.js | 61 ------------------ .../06_code_quality/todo/modules/list.js | 15 ++--- 4 files changed, 8 insertions(+), 70 deletions(-) create mode 100644 exercises/.images/jsdoc.png delete mode 100644 exercises/05_javascript/nestedcallbacks.js diff --git a/06 Code Quality.md b/06 Code Quality.md index 84d837d0..4b36f4ad 100644 --- a/06 Code Quality.md +++ b/06 Code Quality.md @@ -108,6 +108,8 @@ $ ./node_modules/.bin/jsdoc -d ./docs/jsdoc/ modules/* If you run this command you should see a new directory called `docs/` which will contain a `jsdoc/` directory. Inside this you will see some website files, opening the `index.html` file in your browser you should see the documentation pages for your website! +![JSDoc Documentation](exercises/.images/jsdoc.png) + ### 4.1 Test Your Understanding You will probably have noticed that only a couple of the functions include complete JSDoc comments and so the documentation website is incomplete. Your task is to use the existing comments for guidance and complete the task of documenting your code. You will find the [JSDoc](http://usejsdoc.org) and [jsdoc-route-plugin](https://www.npmjs.com/package/jsdoc-route-plugin) documentation helpful. diff --git a/exercises/.images/jsdoc.png b/exercises/.images/jsdoc.png new file mode 100644 index 0000000000000000000000000000000000000000..0c066e007aad7378f538bf41e367dfff59bb3773 GIT binary patch literal 86935 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 literal 0 HcmV?d00001 diff --git a/exercises/05_javascript/nestedcallbacks.js b/exercises/05_javascript/nestedcallbacks.js deleted file mode 100644 index cd3fcc12..00000000 --- a/exercises/05_javascript/nestedcallbacks.js +++ /dev/null @@ -1,61 +0,0 @@ - -'use strict' - -const request = require('request') - -getInput('enter base currency', (err, base) => { - if (err) { - console.log(err.message) - process.exit() - } - base = base.trim() - checkValidCurrencyCode(base, err => { - if (err) { - console.log(err.message) - process.exit() - } - getData(`http://api.fixer.io/latest?base=${base}`, (err, data) => { - if (err) { - console.log(err.message) - process.exit() - } - const obj = JSON.parse(data) - printObject(obj) - process.exit() - }) - }) -}) - -function getInput(prompt, callback) { - try { - process.stdin.resume() - process.stdin.setEncoding('utf8') - process.stdout.write(`${prompt}: `) - process.stdin.on('data', text => callback(null, text)) - } catch(err) { - callback(err) - } -} - -function checkValidCurrencyCode(code, callback) { - code = code.trim() - request('http://api.fixer.io/latest', (err, res, body) => { - if (err) callback(new Error('invalid API call')) - const rates = JSON.parse(body).rates - if (!rates.hasOwnProperty(code)) callback(new Error(`invalid currency code ${code}`)) - callback(null, true) - }) -} - -function getData(url, callback) { - request(url, (err, res, body) => { - if (err) callback(new Error('invalid API call')) - callback(null, body) - }) -} - -function printObject(data) { - const indent = 2 - const str = JSON.stringify(data, null, indent) - console.log(str) -} diff --git a/exercises/06_code_quality/todo/modules/list.js b/exercises/06_code_quality/todo/modules/list.js index 103f77e6..330c7497 100644 --- a/exercises/06_code_quality/todo/modules/list.js +++ b/exercises/06_code_quality/todo/modules/list.js @@ -2,7 +2,7 @@ /** * Class representing a list of items. * */ -module.exports = class List { +class List { /** * Create a list. @@ -29,20 +29,17 @@ module.exports = class List { return this.items.map( (element, index) => ({key: index, item: element.item, qty: element.qty})); } - /** - * Delete a single item. - * @param {Number} id - The index to be deleted. - */ delete(id){ this.items.splice(id, 1); } - /** - * Return the number of items in the list. - * @return {Number} The number of items. - */ count(){ return this.items.count; } +} + +// exporting the class by name adds the name to the documentation +module.exports = { + List } \ No newline at end of file From 63ea40ebee002cc405b8a99f7b29c2e2cd79da02 Mon Sep 17 00:00:00 2001 From: "Luke Charles (charle44)" Date: Sat, 12 Oct 2019 15:58:23 +0100 Subject: [PATCH 12/70] grammatical change changed the wording of a specific section --- 04 CSS3.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/04 CSS3.md b/04 CSS3.md index 153ca8e1..4630da37 100644 --- a/04 CSS3.md +++ b/04 CSS3.md @@ -536,7 +536,7 @@ body { The next task is to build a navigation menu bar to the website using CSS. Depending on the number of menu items, the menu bar can contain multi-level menus. -A menu bar is be defined as an HTML unordered list. Each menu in a menu bar is a list item. +A menu bar can be defined as a HTML unordered list. Each menu in a menu bar is a list item. The menus can contain submenus. A submenu is coded as a list that is within the parent menu's list item. From 54e75d85903c7b5643cf9c83ef121b6020edded1 Mon Sep 17 00:00:00 2001 From: Mark Tyers Date: Tue, 15 Oct 2019 11:54:07 +0100 Subject: [PATCH 13/70] Updated the Nested Callback Lab The lab code was fixed in a previous commit however the exercise still referred to the old code. The lab notes have been updated to reflect the new, working, script. --- 06 Code Quality.md | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/06 Code Quality.md b/06 Code Quality.md index 4b36f4ad..b69860c5 100644 --- a/06 Code Quality.md +++ b/06 Code Quality.md @@ -124,10 +124,16 @@ Because the code to be run after a callback is run needs to be _inside_ the call Open the file `nestedCallbacks.js` which asks for a _base_ currency code then prints out all the exchange rates against other currencies. Notice that there are four functions defined, three of which include a callback. Our script is designed to capture user input using `stdin` (needing a callback), identify whether a currency code is valid (requiring a second callback) and then getting the currency conversion rates for the specified currency (requiring a third callback). -1. Notice that the `checkValidCurrencyCode()` function is called by the callback for the `getInput()` function and the `getData()` function is called by the callback for the `checkValidCurrencyCode()` function. -2. Each callback takes two parameters as normal. The first contains the error (if any) and this needs to be handled in each callback. -3. The data from the first callback is needed when calling the third function so needs to be stored in an immutable variable (constant). -4. The fourth, and final, function does not have a callback. +1. The script starts be calling the `read.question()` function (line 13) which takes a callback function as its second parameter. +2. We want the first `request()` function (line 18) to be run after the initial `read.question()` function has completed. + 1. To do this it needs to be called from inside the `read.question()` callback function. +3. The second `request()` function should run after the first one has completed and the data has been processed. + 1. To do this it needs to be called from inside the callback function of the first `request()` call. +4. The final step is to call the `read.question()` function again (line 38)) which should be run once the second request has completed. + 1. Therefore this needs to be in the callback function from the second `request()` function. + +As you can see, each step has to be nested inside the previous step's callback, creating an ever increasing level of nested code sometime referred to as [Callback Hell](http://callbackhell.com/) or the [Pyramid of Doom](https://en.wikipedia.org/wiki/Pyramid_of_doom_(programming)). + Callbacks are the simplest possible mechanism for asynchronous code in JavaScript. Unfortunately, raw callbacks sacrifice the control flow, exception handling, and function semantics familiar from synchronous code. From c3cc178217a629b36787b023f0ba9192412dc5f8 Mon Sep 17 00:00:00 2001 From: Mark Tyers Date: Tue, 15 Oct 2019 12:53:11 +0100 Subject: [PATCH 14/70] Added Promise Working Example The existing promises lab does not work correctly. Added a simple working example that can be used to fix the issues with the lab exercise. --- exercises/06_code_quality/promises2.js | 46 ++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) create mode 100644 exercises/06_code_quality/promises2.js diff --git a/exercises/06_code_quality/promises2.js b/exercises/06_code_quality/promises2.js new file mode 100644 index 00000000..0424d3c6 --- /dev/null +++ b/exercises/06_code_quality/promises2.js @@ -0,0 +1,46 @@ + +'use strict' + +const request = require('request') +const readline = require('readline') +let userDetails + +const getInput = prompt => new Promise( resolve => { + const io = { input: process.stdin, output: process.stdout } + const read = readline.createInterface(io) + read.question(`${prompt}: `, data => { + // console.log(data) + read.close() + return resolve(data) + }) +}) + +const getData = () => new Promise( (resolve, reject) => { + const options = { + url: 'https://api.github.com/users/marktyers', + headers: { + 'User-Agent': 'request' + } + } + // Do async job + request.get(options, (err, resp, body) => { + if (err) reject(err) + else return resolve(JSON.parse(body)) + }) +}) + +function main() { + getData() + .then(result => { + userDetails = result + console.log('Initialized user details') + console.log(userDetails) + }) + .then(() => getInput('enter base currency')) + .then(data => console.log(data)) + .then(() => getInput('convert to')) + .then(data => console.log(data)) + .catch(err => console.log(err)) +} + +main() From a7361248c896813688745bb8245f8b0d4dc89c12 Mon Sep 17 00:00:00 2001 From: Mark Tyers Date: Tue, 15 Oct 2019 16:20:25 +0100 Subject: [PATCH 15/70] bug fix --- exercises/06_code_quality/todo/index.js | 8 +++----- exercises/07_unit_testing/todo/index.js | 2 +- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/exercises/06_code_quality/todo/index.js b/exercises/06_code_quality/todo/index.js index 111255db..a84f62da 100644 --- a/exercises/06_code_quality/todo/index.js +++ b/exercises/06_code_quality/todo/index.js @@ -13,13 +13,11 @@ app.use(bodyParser()); app.use(handlebars({ paths: { views: __dirname + "/views" } })); app.use(router.routes()); - var port = 8080 - var items = [] -// const List = require('./modules/list') -// const list = new List() +const List = require('./modules/list') +const list = new List() router.get("/", async function(ctx) { try { @@ -46,7 +44,7 @@ router.get("/delete/:key", function(ctx) { try { console.log(`key: ${ctx.params.key}`); items.splice(ctx.params.key, 1); - ctx.redirect('/msg=item deleted'); + ctx.redirect('/?msg=item deleted'); } catch(err) { console.log(err.message); ctx.redirect("/" + err.message); diff --git a/exercises/07_unit_testing/todo/index.js b/exercises/07_unit_testing/todo/index.js index 86e1c6e0..429e15b2 100644 --- a/exercises/07_unit_testing/todo/index.js +++ b/exercises/07_unit_testing/todo/index.js @@ -46,7 +46,7 @@ router.get('/delete/:key', ctx => { try { console.log(`key: ${ctx.params.key}`) todo.delete(ctx.params.key) - ctx.redirect('/msg=item deleted') + ctx.redirect('/?msg=item deleted') } catch(err) { console.log(err.message) ctx.redirect(`/${err.message}`) From 6d5c6a9d08a32f014820dab6dc30e8455c29b95b Mon Sep 17 00:00:00 2001 From: Mark Tyers Date: Tue, 15 Oct 2019 19:43:40 +0100 Subject: [PATCH 16/70] Fixed Promise Bug Promises were not resolving in order due to missing returns on resolve. This has now been fixed. --- exercises/06_code_quality/promises.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/exercises/06_code_quality/promises.js b/exercises/06_code_quality/promises.js index 30397aea..00d9ca6d 100644 --- a/exercises/06_code_quality/promises.js +++ b/exercises/06_code_quality/promises.js @@ -11,7 +11,7 @@ const getInput = prompt => new Promise(resolve => { read.question(`${prompt}: `, value => { console.log(`You entered ${value}`) read.close() - resolve(value) + return resolve(value) }) }) @@ -21,14 +21,14 @@ const checkValidCurrencyCode = code => new Promise( (resolve, reject) => { if (err) reject(new Error('invalid API call')) const rates = JSON.parse(body).rates if (!rates.hasOwnProperty(code)) reject(new Error(`invalid currency code ${code}`)) - resolve(code) + return resolve(code) }) }) const getData = code => new Promise( (resolve, reject) => { request(`${baseURL}?base=${code}`, (err, res, body) => { if (err) reject(new Error('invalid API call')) - resolve(body) + return resolve(body) }) }) @@ -37,7 +37,7 @@ const printObject = data => new Promise( resolve => { data = JSON.parse(data) const str = JSON.stringify(data, null, indent) console.log(str) - resolve() + return resolve() }) const exit = () => new Promise( () => { @@ -50,4 +50,4 @@ getInput('enter base currency') .then(printObject) .then(exit) .catch( err => console.error(`error: ${err.message}`)) - .then(exit) + .then(exit) From edceed43818cd202eae3e14985d791d15136ce1c Mon Sep 17 00:00:00 2001 From: Mark Tyers Date: Fri, 18 Oct 2019 07:50:54 +0100 Subject: [PATCH 17/70] Modified the Modularity Exercise There was some confusion over the impelmentation and the existing import didn't work. The new version resolves the import issue and clarifies the task requirements --- 06 Code Quality.md | 29 +++++++++++++++---------- exercises/06_code_quality/todo/index.js | 15 ++++++++----- 2 files changed, 26 insertions(+), 18 deletions(-) diff --git a/06 Code Quality.md b/06 Code Quality.md index b69860c5..19a20628 100644 --- a/06 Code Quality.md +++ b/06 Code Quality.md @@ -32,29 +32,34 @@ Next you will need to do is to split your code up to make it easier to understan Lets examine this module: -1. The `module.exports` object is used to define what functionality will be made available to our `index.js` file. In this case we are exporting the Object Prototype. Notice we are using the new `Class` constructor. -2. Lines 6-8 are the constructor where we define our array that can be accessed by the object. -3. The rest of the file defines a series of functions that form part of the object prototype. +1. We define an object prototype called `List`. +2. This contains an object prototype definition using the modern `class` syntax. If you are not familiar with the concept refer back to the **JavaScript** lab sheet. +3. On lines 43-45 we create an object containing all the functionality we want to export and pass this to the `module.exports` object. This uses the new **Object Property Value Shorthand** syntax (see below). -Now look at the top of the `index.js` file. Lines 22-23 import our module into the `List` variable. This can then be used to create a new object using our `List` object prototype. This object is called `list` and provides access to all the functionality defined in the object prototype. Foe example to add an item we can use: +The object property value shorthand notation is useful if the keys have the same name as the variables passed-in as properties. For example the code in the module could be written as: + +```javascript +module.exports = { + List: List +} +``` + +Now look at the top of the `index.js` file. Lines 18-19 import the module and create an instance of the List prototype. Notice that we are only importing the `List` prototype from the module. This `List` object prototype is then used to create a new object. This object is called `list` and provides access to all the functionality defined in the object prototype. Foe example to add an item we can use: ```javascript list.add('bread', 42) ``` -This will call the `add()` function that is part of our `todo` object prototype. +This will call the `add()` function that is part of our `todo` object prototype. If you try and run this you will find that there is no functionality at all! ### 2.1 Test Your Understanding The custom object prototype defined in the `list.js` module already contains the functionality needed by your app. -1. Uncomment lines 22-23 to import the module and create a custom object. -2. In the `router.post('/')` function call replace lines 41-42 with a call to `list.add()`, passing the item name and quantity as parameters. -3. Now modify the `router.get('/')` function callback by replacing lines 29-30 with a call to the `list.getAll()` function. -4. To test the functionality so far, comment out the array declaration on line 20 and try starting the web server. You should be able to add items, the data is now stored in the custom object. -5. Finally replace line 53 with a call to the appropriate function in the custom object. - -Now much of the business logic has been moved to the separate module, are there any module imports in `index.js` that are no longer needed? Locate these and delete. +1. Modify the callback function in the `router.post('/')` function, inserting a call to `list.add()`, passing the item name and quantity as parameters. +2. Now modify the callback function in the `router.get('/')` function, replacing the empty array declaration with a call to the `list.getAll()` function. +3. Test the base functionality so far, you should be able to add items to the list. +4. Finally implement the delete functionality. ## 3 Linting diff --git a/exercises/06_code_quality/todo/index.js b/exercises/06_code_quality/todo/index.js index a84f62da..fa386094 100644 --- a/exercises/06_code_quality/todo/index.js +++ b/exercises/06_code_quality/todo/index.js @@ -14,14 +14,17 @@ app.use(handlebars({ paths: { views: __dirname + "/views" } })); app.use(router.routes()); var port = 8080 -var items = [] -const List = require('./modules/list') +const List = require('./modules/list').List const list = new List() router.get("/", async function(ctx) { try { - var data = {} + var items = [] // you will need to add a call to the 'list' object!!! + const items = list.getAll() + console.log(items) + var data = {items} + ctx.render('home', data); } catch(err) { console.log(err.message); ctx.render('home', {msg: err.message}); @@ -31,8 +34,8 @@ router.get("/", async function(ctx) { router.post("/", function(ctx) { try { var body = ctx.request.body; - var data = {item: body.item, qty: body.qty}; - items.push(data); + console.log(body) + // you will need to add a call to the 'list' object!!! ctx.redirect("/"); } catch(err) { console.log(err.message); @@ -43,7 +46,7 @@ router.post("/", function(ctx) { router.get("/delete/:key", function(ctx) { try { console.log(`key: ${ctx.params.key}`); - items.splice(ctx.params.key, 1); + // you will need to add a call to the 'list' object!!! ctx.redirect('/?msg=item deleted'); } catch(err) { console.log(err.message); From dd1f05ffa1afd988969a08c0891bb76d7ed8350a Mon Sep 17 00:00:00 2001 From: Mark Tyers Date: Fri, 18 Oct 2019 07:55:24 +0100 Subject: [PATCH 18/70] Fixed Some Spelling Errors --- 06 Code Quality.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/06 Code Quality.md b/06 Code Quality.md index 19a20628..47d21c4b 100644 --- a/06 Code Quality.md +++ b/06 Code Quality.md @@ -50,7 +50,9 @@ Now look at the top of the `index.js` file. Lines 18-19 import the module and cr list.add('bread', 42) ``` -This will call the `add()` function that is part of our `todo` object prototype. If you try and run this you will find that there is no functionality at all! +This will call the `add()` function that is part of our `todo` object prototype. + +Try running the server and adding an item to the list. Currently there is no functionality implemented at all! All the functionality is in the module we have imported. ### 2.1 Test Your Understanding @@ -81,7 +83,7 @@ $ node_modules/.bin/eslint todo/index.js You will see a list of issues that the linter has flagged in your code. Notice that some of these are flagged as errors (serious) and some as warnings (recommendations). Each message includes: -1. The line and comumn number where the error was found. +1. The line and column number where the error was found. 2. A description of the error. 3. The rule that is being broken. @@ -96,7 +98,7 @@ $ node_modules/.bin/eslint todo/ ### 3.1 Test Your Understanding 1. Locate and fix all the errors and warnings in the `index.js`. -2. Install `eslint` globally and then install the [eslint extension](https://github.com/Microsoft/vscode-eslint). After restarting your editor you should see any errors and warnings flagged in the editor. +2. Install the [eslint extension](https://github.com/Microsoft/vscode-eslint). After restarting your editor you should see any errors and warnings flagged in the editor. 3. Use the `eslint` plugin to locate and fix all the errors in the `modules/list.js` file. ## 4 Documentation From 96e8e4bef57dfe918d74eee83018c52f248f100e Mon Sep 17 00:00:00 2001 From: Mark Tyers Date: Sun, 20 Oct 2019 10:28:25 +0100 Subject: [PATCH 19/70] Added More Exercises Some of the sections didn't have an exercise. Now all sections include one or more tasks to be complete. --- 05 JavaScript.md | 134 ++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 110 insertions(+), 24 deletions(-) diff --git a/05 JavaScript.md b/05 JavaScript.md index a52e42fb..27afe040 100644 --- a/05 JavaScript.md +++ b/05 JavaScript.md @@ -42,10 +42,7 @@ Start by running the `maths.js` script and map the output it generates against t 1. Create a new function called `multiply()` that takes two parameters, `a` and `b` and returns the _product_ of the two. - what happens if you call it with only a single parameter? -2. Modify the function so it uses a default parameter to multiply by 1 if the second parameter is missing. - - What happens if you don't supply _any_ parameters? - - Add a second default parameter to prevent this. -3. Write an _arrow function expression_ stored in a constant called `squareRoot` which calculates and returns the square root of the supplied number. You will need to use the `sqrt()` method which is part of the `Math` object. +2. Write an _arrow function expression_ stored in a constant called `squareRoot` which calculates and returns the square root of the supplied number. You will need to use the `sqrt()` method which is part of the `Math` object. Open the `contact.js` script, implement the `validateEmail()` function and thoroughly test it, you should avoid using regular expressions at this stage: @@ -53,6 +50,87 @@ Open the `contact.js` script, implement the `validateEmail()` function and thoro 2. Check that there is a `@` character and that it is not at the start of the string (HINT: use the [indexOf](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/String/indexOf) String prototype method. 3. Check that there is a period (.) character after the `@` character but before the end of the string. +#### 1.1.2 Function Parameters + +In the JavaScript language although we define a function with a set of specified _parameters_, when we call the function we don't need to pass these arguments: + +We can choose to pass fewer arguments than are specified in the function parameters. Any parameters that don't have a matching argument are set to `undefined`. For example, the following code will print `undefined`. + +```javascript +function sqr(num) { + return num * num +} +sql() // returns NaN (not a number) +``` + +This can cause issues in your code so to prevent this we provide [Default Parameters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Default_parameters). If an arguement is missing when a function is called this specified a default value to use. For example consider this version of the function: + +```javascript +function sqr(num = null) { + return num * num +} +sqr() // returns 0 +``` + +In JavaScript: + +- A value of `undefined` means a value has not been assigned to a variable. +- A value of `null` is a value assigned to a variable and means _no value_. + +It is also possible to pass in more arguements than there are parameters in the function declaration. The following is quite valid: + +```javascript +function add(num1, num2) { + return num1 + num2 +} +add(4, 2, 1) // returns 6 +``` + +As you can see, if there are too many arguments, the extra ones are ignored however JavaScript provides a mechanism to access all the arguments passed to a function regardless of whether they match the parameter list by using the _array-like_ `arguments` object, for example: + +```javascript +function add() { + let total = 0 + for(arg of arguments) total += arg + return total +} +add(4, 2, 1) // returns 7 +``` + +Using _hidden_ or _magic_ variables that magically come into existence can make your code hard to understand so ECMA6 introduced [Rest Parameters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters), parameters that can hold any arguments that don't match the parameters in the function declaration. Take the following code: + +```javascript +function add(num1, num2, ...others) { + let total = num1 + num2 + for(arg of others) total += arg + return total +} +add(4, 2,1) // returns 7 +``` + +This demonstrates how the rest parameter _mops up_ any surplus arguments and could be written as: + +```javascript +function add(...numbers) { + let total = 0 + for(arg of numbers) total += arg + return total +} + +console.log(add(4, 2, 1)) // returns 7 +``` + +#### 1.1.3 Test Your Understanding + +1. create a function called `divideThis()` that takes two arguments, a number to be divided, `dividend` and the number to divide by, `divisor`. The function should return the _quotient_. +2. What happens if you don't pass a parameter for the `divisor` parameter? Can you fix this by supplying a suitable _default parameter_? +3. Call the `multiply()` function from the previous task omitting the second parameter. Can you modify the function so it uses a default parameter to multiply by 1 if the second parameter is missing. + - What happens if you don't supply _any_ parameters? + - Add a second default parameter to prevent this. +4. Create a new function called `average()` that takes one or more numerical parameters to return the average of these: + - Write this to make use of the `arguments` construct. + - Rewrite this to use an ECMA6 rest parameter. + ### 1.2 Function Expressions Functions are a data type in JavaScript (they are objects but more on that later). As such they can be stored in variables for later execution. Prior to ECMA6 they were declared using the `function` keyword like this: @@ -99,7 +177,7 @@ const sqr = num => num * num 2. Compare this to the original version: which is more _readable_? 3. Create a function expression that takes two string parameters and returns the longest string and assign this to a constant called `longest. check this works correctly. 4. Modify the function expression so that it can handle any number of string parameters (use a _rest parameter_). (hint: you will need to use a [`for...in`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in) statement to loop through the strings. How does this differ from a [`for...of`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of) statement?) -5. Use a [ternary operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator) instead of the `if` statement in the loop. +5. Use a [ternary operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator) instead of the `if` statement in the loop. 6. Finally use the [`reduce()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce) method to replace the `for...in` loop to reduce the function to a single line. ## 2 Callbacks @@ -235,6 +313,13 @@ const grade = employee.grade || 'A' This will retrieve the value of the grade property if defined and store it in the `const` variable. If this property is missing the `const` variable will contain the string `'A'`. +#### 3.2.1 Test Your Understanding + +1. Create a new object called `university` which should contain three properties, `year1`, `year2` and `year3`. Each of these properties should store an object whos keys are the module codes and values the titles of the modules. +2. Create a variable called `study01` containing the `year1` object. +3. Use the `for...in` statement to iterate over this `study01` object printing out all of the _module codes_. +4. Use the `for...of` statement to print out all of the _module names_. + ### 3.3 JSON Data JSON (JavaScript Object Notation) is a standard text-based format to represent structured data. This is very useful as it means we can take any JavaScript object and convert it into a text string. This can then be saved to disk or posted to a web server, etc. It also means that you can take a JSON-formatted text string and convert it into a complex JavaScript object! @@ -289,10 +374,24 @@ Lets apply our knowledge of callbacks to implement a simple quotes tool. 3. The contents of the file is a utf8 string, use `JSON.parse()` to convert this into a JavaScript object (array) and print this to the terminal instead. 4. Create a loop to iterate through the array, printing the contents of each index. 5. Modify the code so that it only prints the quotes string (not the entire object). +6. Convert the `university` object from the previous exercise into a JSON string and save it to the filesystem as `university.json`. ### 3.3 ECMA6 Object Destructuring -In ECMA6 is is possible to extract multiple pieces of data into separate variables by destructuring using an _object pattern_. This is syntactically similar to creating object literals (see the example below). +There are situations where we want to retrieve multiple object properties and store then in different variables, for example: + +```javascript +const employee = { + firstName: 'Colin', + 'last name': 'Stephen', + 'department': 'Computing' +} +const first = employee.firstName +const last = employee['last name'] +console.log(`${first} ${last}`) +``` + +In ECMA6 is is possible to extract multiple pieces of data into separate variables by destructuring using a [Desctructuring Assignment](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#Object_destructuring). This is syntactically similar to creating object literals (see the example below). ```javascript const employee = { @@ -301,11 +400,15 @@ const employee = { 'department': 'Computing' } -let {firstName: first, 'last name': last, department: dept} = employee +const {firstName: first, 'last name': last, department: dept} = employee console.log(first) // prints 'Colin' console.log(dept) // prints 'Computing' ``` +#### 3.3.1 Test Your Understanding + +1. Take the `university` object you created in an earlier exercise and use a single line destructuring assignment to create three variables, `year1`, `year2` and `year3`. + ### 3.4 Getters and Setters Most object properties are simple values and you can simply assign a value. Sometimes however properties need to be calculated. One solution is to store a function as one of the properties however we would need to call a function to retrieve the value: @@ -601,20 +704,3 @@ You should take time to understand the [pros and cons](https://2ality.com/2016/0 2. Use this to create a second **constructor function** class called `OldPickup` that includes `payload` and `seats` fields and use this to create two pickup objects. 3. Now use the same information to create a class called `NewVehicle` and extend this to create a class called `NewPickup` and use this to create two or more pickup objects. 4. Add a static member to capture the total value of all the pickup sales and print this to the terminal. - - - -Show how objects can be turned into strings and saved. text data loaded and converted into a JavaScript object. - -### 5.1.1 Test Your Understanding - -### 5.2 RESTful APIs - -Show how data can be retrieved from an API in JSON format. - -//TODO: use the OMDB API in this section - -OMDB key: 220d2590 - -First task is for students to get an OMDB API key and paste it into the provided script. - From b385bb0ffe06a79460eef52f44bb52af36c5f0c8 Mon Sep 17 00:00:00 2001 From: Mark Tyers Date: Tue, 22 Oct 2019 09:17:01 +0100 Subject: [PATCH 20/70] Removed Module Call The todo script would not run because there was a conflict between the imported object and the local array. The object call was removed and added to the lab activity and the comment on the array clarified. --- exercises/06_code_quality/todo/index.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/exercises/06_code_quality/todo/index.js b/exercises/06_code_quality/todo/index.js index fa386094..ac002167 100644 --- a/exercises/06_code_quality/todo/index.js +++ b/exercises/06_code_quality/todo/index.js @@ -20,8 +20,7 @@ const list = new List() router.get("/", async function(ctx) { try { - var items = [] // you will need to add a call to the 'list' object!!! - const items = list.getAll() + var items = [] // you will need to REPLACE this with a call to the 'list' object!!! console.log(items) var data = {items} ctx.render('home', data); From 93cc6815377e803dc28da0b8c3cbd6158224618a Mon Sep 17 00:00:00 2001 From: Mark Tyers Date: Tue, 22 Oct 2019 09:26:44 +0100 Subject: [PATCH 21/70] Added Code to Callback Currently there is no message to state that the server is running. Added a message to the callback function to display the message with port number. --- exercises/06_code_quality/todo/index.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/exercises/06_code_quality/todo/index.js b/exercises/06_code_quality/todo/index.js index ac002167..ee1f2aaa 100644 --- a/exercises/06_code_quality/todo/index.js +++ b/exercises/06_code_quality/todo/index.js @@ -53,5 +53,6 @@ router.get("/delete/:key", function(ctx) { } }); -module.exports = app.listen(port, function() { +module.exports = app.listen(port, async function() { + console.log('listening on port ' + port); }); \ No newline at end of file From 648ead1fb7d520b43443a76a4bce92e97814c7c1 Mon Sep 17 00:00:00 2001 From: Mark Tyers Date: Tue, 22 Oct 2019 21:04:03 +0100 Subject: [PATCH 22/70] added instructions for Win10 Users --- 01 Setup Win10.md | 58 ++++++++++++++++++++++++++++++++++++ exercises/.images/store.png | Bin 0 -> 317892 bytes 2 files changed, 58 insertions(+) create mode 100644 01 Setup Win10.md create mode 100644 exercises/.images/store.png diff --git a/01 Setup Win10.md b/01 Setup Win10.md new file mode 100644 index 00000000..33202f93 --- /dev/null +++ b/01 Setup Win10.md @@ -0,0 +1,58 @@ + +# Setup for Windows 10 Users + +The tools used in this module are designed to be used in a Unix or Linux environment. Whilst this will create challenges for Windows 10 user there are some steps you will need to take. Please read and follow the steps below carefully: + +Install the Windows Subsystem for Linux (WSL). Open PowerShell as Administrator and run: + +``` shell +Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-Linux +``` + +Restart your computer when prompted. + +Now install Visual Studio Code and once launched install the **WSL** component by Microsoft. + +Now you need to install Ubuntu. This can be found by searching for `run linux on windows` in the Microsoft Store. You will be presented with the following screen. + +![Microsoft Store](exercises/.images/store.png) + +Choose the Ubuntu operating system (v18.04 LTS) and install. Once installed, click on the **Launch** button, this will open a console window and you will need to wait for a few minutes for the installation to complete. + +## Cloning the Forked Repository + +You will now need to fork the foundation lab by clicking on the Fork button. This will create a copy of the repository. See the standard setup instructions for more details. + +Now you can clone your forked repository by running the following command in the Ubuntu console, replacing xxx with the URL of your repository. + +```shell +git clone xxx +``` + +This will create a directory called `foundation` in the Ubuntu console. The final step is to launch VS Code from within the WSL environment by running the following command: + +```shell +code foundation +``` + +This will launch VS Code from within the WSL with the contents of the `foundation/` directory. If you open the integrated terminal (using the **Terminal** menu) you will see that you have the full ubuntu bash shell. You can now run all the remaining steps from this integrated terminal, just as you would for a standard Linux install. + +## Installing NodeJS + +These steps are identical to those used on a full Ubuntu installation. Start by installing the Node Version Manager (NVM) tool: + +```shell +curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.0/install.sh | bash +nvm --version +nvm install node +``` + +If the `nvm` command is not found you will need to reload the shell: + +```shell +source ~/.profile +``` + +Now try to install again. + +Now you can go directly to step 4 in the standard setup instructions. diff --git a/exercises/.images/store.png b/exercises/.images/store.png new file mode 100644 index 0000000000000000000000000000000000000000..e34853d0c6327e8c46e9f4bbe64cfa3f6eb95f37 GIT binary patch literal 317892 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%0A) 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 literal 0 HcmV?d00001 From ba038cbaba7e1a7714fe8ee43f1e50c54a1d623f Mon Sep 17 00:00:00 2001 From: Mark Tyers Date: Wed, 23 Oct 2019 07:37:34 +0100 Subject: [PATCH 23/70] Added Component Notes --- 01 Setup Win10.md | 4 +++- exercises/.images/remote-wsl.png | Bin 0 -> 32798 bytes 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 exercises/.images/remote-wsl.png diff --git a/01 Setup Win10.md b/01 Setup Win10.md index 33202f93..b518f381 100644 --- a/01 Setup Win10.md +++ b/01 Setup Win10.md @@ -11,7 +11,9 @@ Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-L Restart your computer when prompted. -Now install Visual Studio Code and once launched install the **WSL** component by Microsoft. +Now install Visual Studio Code and once launched install the [remote-wsl](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-wsl) component by Microsoft. + +![remote-wsl](exercises/.images/remote-wsl.png) Now you need to install Ubuntu. This can be found by searching for `run linux on windows` in the Microsoft Store. You will be presented with the following screen. diff --git a/exercises/.images/remote-wsl.png b/exercises/.images/remote-wsl.png new file mode 100644 index 0000000000000000000000000000000000000000..e6679da24c621af0f4ceec894caf2cadc477894f GIT binary patch literal 32798 zcmeFYbz2{ z`^U@k6t%jR^;$J+)|_LEj#5^XLW0MI2Ll5`l93iy1p|XD1C`4GFrfdGcc`dfVDN1= zVq(fNVq(O~u1=OV_7-4Z(ord?uIDkCyA%r;TY-q3w{3|?$G4zpEOcMh2MY*xk0?WrUd6*PIUX>+hkb56Z%2rwOttGNaq8fijS0uw$GEn@NX_&V&!seMxY z(96>=Uy50~W9ocnjjoG;3|5K!R9QKs2jzy8NEcKIpJ!Lv-Va=WPGiz(iWesE=18AI zNzK_@Em3AuBZhU-*_rG!q1Q$pW%lJl3raJ{Oep2q($26+jj{xp+%uD)!RdW+={4us zZ^+-i&e0pG3z#vNPzOAKYkP1ATyH%Qll(1LIkiGP>r&@`!5Z*m7jM zcQ;|d-E1!~!@g4qz+xkCxo*xFB24m&904^UrQ!4uny93up}nW4sR8k^9SNQ8>n`!5 zt!r2K|$CVqd&rooyYxIH?_Eahr42?&jydWxy%e%VD1b5br;U=1VoZSGQ)`br0>%hs2 zVz>r=3~DxyQ_mLI6B`R)9u^8BRfg6TM)?TtW{iX%gm4KaD4o(vj3^%LUH8!$jK~~} zMH}Y27grfd_J?I1fqGDvu}~SfRIkf4lx{DyGxQo*&Tm3*#81LP-jESL03Sn%0kA5> zv_;TIVw4G(yI?aUOv6O*;iUQA)M&E7VF@2bBNs&}lxft#&q8g#8RgGSLm%SKLkom` z`X+J+d5bC8Yp#vC7_MNVmyXQ#8H-ze3vunC$0A)4{vu{G>g-4kvG>BT z-wJ2&-6=m&e1dF;FbH)NHxk_xc_@gS-emdk1$hX5C(guVo0%rvBArworv%px-VMhM zWiB44*R=jvo2`nD6Mz@5Fv$4R@yGcPr}30oN1gw&2|jXZcw?W>cAvAoK2{B&1;Y!< z3)u^ADgNaP)z;k=@*|iZgyCnVA8A`CJ5$?EJFu5#P!u6>y*a3oztLUcvH-9EhA_Rb zfWD6^8P<}w%!AV!j>=l_6RTde}VmH9AB#x6a zk;{$XjYJL~jG&AV(R_%e8H`L69x1Rdnpb61%~cVkQ^vIapbf7dt^uC{9}C}txj}>e zLE!^VbPVRrhp`Vz)ElaPmEy{*8m6@MDVnqzv^ko`nz))Jw7=*gX{@N7lm)B&6rNJx z6$jM^jlwHc%NmUK3S@~eB{&LL%khtOkHL>EYJ^P{?&nvsGo>QD#(=GGb`s{yKi`$Nih?G0@DfUzBFWkb+Ms|O8pUlBbq|68Q z9^08F;P=_4W@`=`fdxrBJ=>`z!;&tkmxlXaIu(ulmM)fRa_p zD&&|L2&@Ymd_7lOk7;+ho4@nBRlRFI%2~jhFFp1>Lbz=?%9{&RP%C7yK5BAZrC3b} zjuS};o;S`DiR?}PmSNIl5^NH>rAAhOwobibou!gBlThD%rN861!@DCz35C%Pw`m?J z(=k$3o?%mU#5+ehr)8OGN#Drd$lFM@|G~}aM*fEOrUOeGp!TP^FFXU zpt~2?;~RCisxi)e5PO1t#(eR3tbCMu(Rvg@U`CXND?|7Q?~bfb=q(7q_<-I-QI=Ia zwq0kdBi38fOBccvo*+glMk|^dsT&b3rnlec7JA^A^J1Pm!oSs7!i+iu{|on?eT|-< z4Y>5Q{IqpLchK{tE`B)PI=)DfF^V6b2YnCkJI%36lTQO{}*xL+z%^H_}E4o|qbjMZ@gw$8q#Qic<TD<-G3_s-~aHd?c&ks~X;KK*xFjyuTL{65881t#2E`dVmN1{z{Do{Go0#xWmQ)>xcBuLXAob%u`3 zjPZ>9x<y zq_=cor|d+{0~03`-}OdumG<&eEUqOdKd(&4#?^I+=D2)YvW%t0r7UW5ehzUKw#c>TGvPNY`mm#pfTKvYH}|JPmqcC{a$o5yt|pgA)aZ-pwrjptvGIs zB(2sEuGO_ZXC~mh;$UIX?tDqnsMN@*eap4*s^n%ut%v8`v!cJa@GAABdS9_+GPQ=s zz{<&Yv)lRS#bioHRR`DkM8}ec(DPg9dHA{jN-K(?fPCQNo63D*{m;rg&!b^Z2u z$D7HjZ;=S3ey=~tdFn_CdCLE4-yKm)Bj9F&v<{^$$7 zN}wO!%Lyo!)wIx-u~bk1qXm@#VBnE9U{IhEIOxCy9iXr`F#-%0bVdgq;`tE&RSQ{` z5BXnZu<}0*MbyM(WI$&%Ggk`>M>lIH_hH&V&=}y0HtO2$+6wZ#W=;-_Cgx727L48w z&VRaq@q6=viVha;CdA$j_Kt46-U6h5wcrJn|6FDwCH||4yPW{3wt_OTn3JmoF$W_% zBQvQWJTWmbzpJ?=ud2A@Kixr}1W2vj-JN-vn7q8a7`@mSom{P$Sa^7Nn3!3aSXmiB zEg0N<9NkU4864fn{vPDN#u2x0Gjp|ZcDHeIB>pq5iK&x^y8tQapNana@9*zv;cfFj zGda5bvn2Q-Hu4;v@{U+w>`=6`1V zyQhYmg{zp81E{0B;Q#FJKb`-z^8a@HYf7E}nUaN*=U=D%mzsZi@-zKe`M>PM-`o7x zRnR^Q!t*oz_dOGYr=6o~0s|8UlMxqD_Xa=Bfz4K5xcfPE-ZxuJO-ubbpLiKO)>Qpe z^3=dIwrePafs_i<<%m8(Onnz7Mo4EKrExVn0xs|IZ2cWAH3Y+-3pS|GEB8V|)ln z}eg1TIvTdhKqKDA;mrpQ(2vcOWYP^(^3{$ZPQ|$FaSh#p-wEI( zI*$@&X#_kfr?~da_WxKI$Y6w%#Pf@MAI>!tSPm#A^yGAeCH35Y$&QBhxEHZ5ebm5M z9BH^cSt=$auBQACX2{L~m5DFn&}?aBvts8gEDOt1DM|9d z7aTV9hvyxwp63*O@2&9j=7IvzINswj=@4%7VN{;C$DN#xa0Kj8mY?`)q0XKsiwcab zzaez2ay-}%ahKZM4o2^mjF|HL?{#7i>}tE3*F1kYL|Ki@W;iEop$yX?FiOg^K}}|J z;Xn~ruvx+A>6#|04mpQYZp^A3w zC7m>*l|yubv2&ik)QbIbf*Y*Y1QcB3X))e6x_mo?06!p6_?00GhdkYuO(I8*D{Idi z?)ngzhL?;24W@N~*JDf;BZ(BV6&iGDicNVcP#%pFoN~K`I*pdIwMIfBe7IPE+R>jx zf%>7@jxFn+uFprMd`QLZa7Hsf41M-eT$c>I;2!tnrn7N*Ca_nrlvqfGU-EOta|QS` zuV=EcG8frtw~D?t89tdg$i-7X+>ih5`h|-?CYl#*v*5*K^L?dPp`CuL12%6I?kyF{ zvPX_mkWPaRi;I_^`5l+VRGic(-NAII?Pih>VU=k&KNQ*3(o{*{PQA~-?1ja8npi~c zvvGv(Ar$7#iIU)xc=M_)UD|%P|I6q}ZO?hY%e!C5=*)yW@iV#g1gYH5~1J=UFqK z!Zc~7IvJRX(~O;z&gH#B>^U*TJx&}BTZyKM5NIOT367=V2t3Eb4UsThHj!#*VKn|A zXzOb&*)45%?4rk_+gcu?TKb5&vSpGbos)-P$g*p`DTz6MnlAIaEE;Q~9 zI`UJ0p&kN?m$d1)!D&`j7%|koi&)WdoikY^31XEGpMsSRH?4^M9qR;Z13qAiSk%(& zjy07WjWt^sKYv-d=)|tIzx7q~FM!|)uM!s2nEs^if44B(?eFWK+=@)Vt6tM}zpA@m z)N$GngZPp8M;nl69x zqWK(ti|j0IdwqI+*zEAPphpzW))5cttfUs%OZYJE%JT^D;txEjZkg9X^7B8VLG~jZ zv-x3yUKLzN+-oF;u$wM{dJTTG^;TKiok$e$*qg!Sb-FyWX9Ik^f@AH4kclT0fKnjz zK)=~lr$TCs$0ps&V!?nJAOfy5BAI|!<^{g#EHjOh!inDb(Da&l0Z|eBc2IIi9N{TT`Nd zMEZb-*_Sk%=Mz<_#Nxc`qA6NXE`p$iI?uJ~H&@K)_{>3fTl$;DagF=o^R+R_=~>IB z;=B~rJT>g<9%YvO_FAL0v_NzP3a%$-jhs@C{AhOuxdymQ^>J$i`^%vL&CBl`URZ;L z`bKpQrZjZ2GLNBYevroqB1xcukZ6o5v@mX8H5vAhRAi$z`Ro@-5@>U~YDwAG&Ag&% zQsDEnmqs;AlSEEAcN!^{-kKBm_Vm?Uu|G(fn#Urs5+aKGe%Wk2&-MZMV6D&Cb*tK& z!-UF|m%SYsmGvARl4nATlVQ*&>-qTj8D1_mmw_HB{erZZy-gA-_b`#Jo6${t;ApA@ zIZ!Q7r*7u8KXdUC(-k@+B)RAP?S;{hLTf-m*XAObPn0i2T4cC4iStJR#?udhO#h7} z!LV?GYj8M915~wp(VYlE2{@Vo#I*$VD?Zqb9{IUE8v>b>0L3B7_0{(y2o=hsr7C5u zA7P(D>Hxw9GyT8HU{NiGX|&a*${Pnp3cx*>tyHn9+F;Eap2}d0fFmzOPdD*0gUubo zqe#yq4TY1*#n?a%O~eg7T3>r=xv6f+R73Ajb;Q*L3ab@3?9a(9&OJUozyypU*E5e| z*NGa{2J^27R!2`uaDgc&4#XPOzecacl&U;?COo3}_a*q1kJlQMG# zJ-6)_maI>Fzk?umTY6rrv(gP+M<`rJX-dUyU8ec@Z^qfK^WK3!6+X>a(wZzdd4Y(l z#_ItLC2rAyfZ+9CL-s;c)HRV@ z5{Lx*-I6Rv*@QSer_TDtZhgVt0-L_%Gz_~tb$QBP>7r~ZLj>ASx-8ftac?5jGyEj- z(Hg|cvcE|_T6dH{?a%r3&r_BCUM8DfCPCGf&S6T|Yb^Z`2p~VIsH|}{hrAvo!Z2^* zs$jTz<(hXICc^L;{T#)oHH!DmkGL3+b*^w?UuhJ)@GNpL%P&iHxtPauv~2>RuE z^8|JMv9`nCl`L7v*F~XR<~3+LJkw^&lQ1^49C?*xOZ{k4)_tJ~r0M`JuM$>Ym5+#cbVam>uU#6M6pPv`Yp?vionR0EfZU(4xIf z#*~Wt9P^d0R?=g7wTTtTl^w0L%}B>yW5-FOTF7f6qk@E4(xI>aWaz{A!Il}mBY7zI zSv8#A+DR{d@{FkaV8so{CnJ4cj!dI!0VD9h|Pq-8V1Ld$Do44<67if zn`r>ZKvy58OEQEKb$&T(p^^qm5;)I5W&1irfbjx)i%Eql`tBtgg+)4Ec0pf!TDBmS+!UaHu zjMOQ1ulN7X>v^HY*8M1OJJ3tgX1idZ$KdrRQEig(b!wi zWER;=tuW5BJ*rfKUR{M&t$)o`4R~j`n}~S&3v10EAyamaB*)>I@Xt|CgkKyamG@TU z-U=Jo{ESA1E@LG+K+aF!edP3LFz-)k&O92JZPhKw#($;pF1T{Je)3|zB!7dT6Vo?= zLPR>*OFQ!BH<5n9bj(Gr9zMb_pn|ffa$~rGQIe=k*<_vRzDb+OWrR?*MbW|fRkAYf zh<(4u`dFRW2+?l-&fuE?$u+9|Lc7SuO!EtFTN(Qe;f=9;HVL$@p|zUVroUGUAV}yK zX8^&EBsBpZs4Qe{WL!*nf+{^4H;6UcPa@X-o*)4uO;5F9+c7UNlPL%^s|LfNRFp=F zkrIs3XeqB52#-i_l@_ug(I4MV2`j!P3V>B9MKMMTuOqGuD-FYu|AB%p?bZHRuGj8Q zjF0_r1eAJ`xuZ9DzCxfGbk7AYPz7KmT*mvfB`U1q-a*7xEXoNM4hA@fv3~0cHDfHQ z&=5WhWnUmJ6%ltdI&Qi^S4mX>Dp#yFA>Ds7q!?4|QkTVIa=(xzuED!a*=KtFxo$S3 z$6C6o-u858Rb(336%v|Ile`B@NL74OfwEl*KkT#;_E7N(yOj(Cs*!ezhu!!8jh_&k zLBY$0+U~ONTvs;2Qj`xC$XKxMW|I~}33iDmHU;73gK~O=AtL6^Q09(psMz(!a zreQ-5DpCa@jQFFV$X@QPnJ2uBNg@J?*fJZQVq+rQ0rBHcaUR*}rba296F7|hx)ryjYR3+hOu(>vE`3wM#^s$V5Zedc>oNNrJnYs?Ag zD~u-&Og=$i>P%pLJ=!jnC%M(NYAxkYsoTy2s>GKC0{p!x5#%S;#sjmPeqBFjnt>Ve zkeBm6%1P(LIb2=fRVba_btgqXIiB3a%W~6Y2(T^7J!5+rv09}zbzW`j2I#)MHiW(G z2bb4H{f+1fd!kZ*3<2FNKIlvt>Oo1>*G`tJ!7z;x7`g|1)PVy;bs!uMEJ}D3(s{a{ zm~(<3s=EAsa(-e7^;KTwJ>{suBTkalwQw$TVazB~z%5v&-|mu9p{>wNbivtznm-A6 zw+wNBU*D*ei@F~}l^~gr_527|NSjxKe??I*HigDpqdsuab*7HQV+$HX&|w<^!~eCL z;b>og{L6D@mA(J_GoC7HT+FR7w+?Zzdf0<#A&FTai^~?L{NwWbDADrE{`r8+scb9mU7)VyhygkEn(ZJl>uGzqY>7!q3;<-B$dZ-tyKH(Evc_Ec}?`o zmg@!WBQGKY?`L19%v$Zh)`0+ zuXVM4GoBYzd9S_B`pp6&x{eCfK~I~TSo&tHMe~NiT3wy_OuT^d9Dlj+Wpkduu|LT) zS7Za&uMYxTxUD`7^BFO(@PmLV^!Oj}v7UkhLOjiaS1i3#Vc8`y2%@NzrQJl*kxH~c zFW~)&*`on(PwSMXp|n{=Q`lVUxuAiz38}{BZI4F2fI8M|Ri)LY~x-459vWBqPu`2?PcbRQvF!9#w1)KFWYU>CEc`Ogiz|OFXZW1fopwNUabG(RuE{Q;$NfH z^pF8C$4)Xh&PQ92Phe|_B>-P#f92R^Uno%i7|E2TFy^39iDxz+C{(BH;$l zL-F5~)D@bwa>%M};ihzDP(D`H>0D3aDM-$R(;9HcMU_+>s4J}gQ!$r`%rJv??qG54 zC3Rd$Oweh?i>W;Qrkeg`|1Lsaa>%6-`wm2nB;EWR$xq0PBr^0chNfyYWgRUq?$k07 zh2r_ct=Qsk7hJe`NECYg0k>zQh!{X~)ScPC>HX7BOQdii$9-XC+U}GU7BEwmPp*BrT68jtco0vKV{$8q8 zn8$hB0k8f_QdMd7b({?I%gwORs^)tT<;HB)uU2d8QehPfVzVggdiQNI2ck`KXv9UN5 z1;bNs#uhbDVCsgZ1GEq1aa9DxDgew(s$IdVjK7@tCpvJu};Rg0+Ig9{CMvy(T96yYIuNpFuF5y$vbXSM$dx zp-X%}@S%e=JBsKZ1-EYFT|b0E+x-V3)B)=HEhEFy?mi_I?@WV_0{Xeg?k5(jeJ!Dm z9D(jKBTgp3is2d&!c>UX!ou`F4A6}_OeeCZmjz-*7>s=|PJjYw6-3+_ap*9_LIX;L^?EvKHQvR2}$=la#)gi0y?eLB2BG|Bcq zO(}>vj3=@;zhU}PG#-c#@%^^6yK96@YCx(8xB9p3`Hnh_ATlW5^s!hejgv=?(^olWi`@u1 ze_}uKP^sfDnD~F|9}+O2TosjPazAQ z7Z=8U732}G&yHAafl6CiQ7>q<@+kzh0Y=Y8*Kr-Ld9v+Ty${N-w^>*VQvCsV5Kkh; zAedoHNgONYUukOSAYsKGk6HVPZi#XMq%?%x+kp>L;eiIK}lu z_Va@nmL?=-fy94XBD*M*YlVmdJ#Nbkh83S{1+EfBZh-$sj)0O53#X$Wzi-&vd)#-^ zaUgVJ6FnKm3J9@p8%=5EJeCZ!6nXYO=(tUAAmC1MN9mcxa+nV%khspuP|3t#t#Al% zo#|(zTW33Zp0tU3p0$AjyT-a>*uwAq&s$nXn-PKjXzcHQS)@63a5kEHcTUt$HOsJF z-b5-L%Bpa#U{4PsN)75HXz7#<5fLd?r!@YT;}g4a7@Vn*A#|H6drxI93%eX!TWLfI zE2bEuO;!D$d}Qt!J5EWJ_^-nLaCtO4AP6QY@cm_TlEEB#<3!5{j|kMpinzyK?rsfh)o1j0YL z!XLX9CbmK>Uw+6H<<%h0c)7heb$mdoL5a(tOe$f3Ybs(`i0TlP))<3-8fbbb`oZo! z`$d9d?MUGlDcjY8dz#m#Z0h){rjuL1x@DGw`S%6Qq^Fw$sUc87PbLzXz_t^Q!#3IP zZb9q%s5EcU+t8j1L{jEd>9?s)a_=DObb6;WpA3`5yRUA!P4bj3H<%wWfI;y#S0#fR zRKBz}@1-<2`>Zd~GE_lOE6auamw`=xMlE}(B1Zy%G#lKpF@1qZEE4SzpRF&x|ANX? zxp&f#>(E>%Y4;B~=%&`On6foX)WkbWSvt)pSqE|Zi9=B(O%)XtLob+gn!{mm82D|K zR|Uh4oXf_LPg{{hwh42lBM|$;E6g&W81%axgRptD2&GAr;@2`GdkZyWZACUAvL}EGNcRk-3UL zJbjDRjZ@%DmLCW$J!c6Ejp_ptti@gz8?0tSh&Vz4o&49sWN@Uupp0-7lt@!0Q7R<< z(FJg>Ig9a}R5k8`2>#?|hhL*0>Xs_YvAx{*6Q9erxDUwsEN%~HaH~65(RlXL&Ghl* zQt4e>I`3EQSbeT{!#dnezIM+k@+t6oozqWbawLHW-ix@fP4_tk*ZUQ#CGR-PJCwjj zG1AkBxBBPf%8n*A#<4V}G!U(>|MoN$II1K>Aq37xJ7FCk_|UQ0#!MWG>T#{46J`Ng z2zJwmvEPQz0fnIzI*jh~=KI@2!`t)8Sb;=L_Tn2T`c7!s4EPl;^(x{v5%AsTW*_d! z4-|9l8ofWK(d%he#|}(f{Ul=QdAqB%=na9MEmxxg2^O?=bA8Wc=Ih0`uW!u`OAsu2 z1Uag?Ke=l!P#M&%>+{&}gmb9g>=tpdUhgz>cC#YSujR-yjF@*om>pu7vup5zI!^iADF0pIs+@r_}ysBM$Qxha8EPYB0KXQ}k zPB(P;#B&^)5jT!}xU!M)teC0!>i5$KV2@_Ofp<35TR&Y*W+_909Ph3zs0KE(imH&fRj z{-1~8*YDoY92oFzcK>I0Dek#&Xz-AaXCUf+wnQNdN~Uj|2Z)cZ4G3vY7+JpD>fZx7 zxV$ycKE)*yIR5~z0WQnob5$o#fIJ7ImVrkKS?g}R%;O(X0f5?aiq@Jh9+YVLfXu1b zX|wxzImKy>`O+P3WrzF%V#XdL{pxLN$*uT9ij8!8lK~Bogbq?H%x?1-RYuWg zbH2a*q0sYsu7FjC@5jld0#?Z&!uU1CZLF5QOL$Bi1B!O4avBf4FmQ^SqBUMf-BKb!$OgB=4?^El zmC$_A2yW1?)qL{m#EU~Q9fxVcKlr?pJ0LA6p6L`DWA)~=kE`6VFXQT*7 z_Q_2HD#?9oE^hq8r``IPGc7(7aBqNoNR)a0pokr-^>n`O>V8<^bUZjDOsn&BcSXKP zDdNm{!IR{)b^*^Gb9J#?+9Gk8OaJtx(DNbL(`7%30ipMh04|OE2a=+&NXqO@fG#Z- zFERAPhHtI0=42nt(adWfJ#`V^?ih6HPM}wuo`T?OxxVD7fSjhCO0@-o6i=W|c{cDC zm(|kNbr&t)v&6F~XqIm3kJZC%zmjAVmnJKmP_U`PmI*fi*_^mwZ*!+6nEq zvvL>%S%dW;36kL-8tjkY>I{fED}=Q=jPXm68W!tUGl;ga+3fDZA|7?T5lFxkxq1Cn{$=l_ z+y#gggE#Is##@utvdcQnIwL|>+-DvRE*NJC&&D>Kq?8RfC@;-*#pM|;hEIaX%f7~k z7>gE4;x#(&c@OYvaLg0*Uo&Gb1=v`K23>xUNlC0|HQ||pev6MH!4<7DF^z$v$B=+( z)Nkqm3?MgJVZly|mS7B1zWLLDBo*3haB3oQ1G&mgr6y5$5zk_37g;1u%`29QJC!9X zsHzk3&m^(QY^733jK|s%65(@I8-6zvllWP1RwRG{w<*}g)bbmXhCzj!&HpbrP@UV-OHW!5=n2@n4Nl2-vqPDc$e3dsqSY8@^7#^jENG z;Q&&47}Glu0jm!1T?{tQRX$OpanntPmbL9?$kh?hOI7ay*$zv(Ux`zaY(764=UxMS2lH8@XUmi``xi{155qm-73 zaoHZWnGi5~Q$`aAvZQrcLAop2Q)qLr_|>E`$6I)r9|Rb9M$-u*!rDh#CbJ)~?kSGN zrviWGlCmQT_};t6vv5eBL`q)W|8nxG1ln)yv@gLL|D)gp8dB6F|lpm-^5 z?svldA8<**lO=HIbdf4U#YfC62upZ`p4|Cx`db|Hanyu-NIds8fNN{9%PTZe-ABN$sb0tIjd; zOjGT^6^G`|JA*OatrWOs50|lR0t7SQS>u#oU%)4C8nXpe^QXtLI3!t9F zt+mqk=1L0)y3U$^tp(U&eLLK=j;9wikwxs?6$rz6pLb&amY@VcC%^v|Nm!ABv@s)j z$YxD;n-d0}(bo=LO+$|5Wgn}&B_9NGAir$z>J^RoiSuYt%>j(BN+dCQFVrhu~w>fQi{(5dvQHSj%(a8oUG%wKlHMaPU)-6)7yq$X%pc!lp!Uf7z`nKc-=@~+% zCg=&hoD3Vlj!aY`Xa?so&cI4?E2`zv0QU(cY>>M69>ntSOJeCdsmpWX< z)pQ_BRG&LiEdB165uLRL67 zZ&^@5*_{5us-rn~>I}MRfS0Y@_K+ja)sOGSi~)r-R;EH8$Ldn*GGs4_D?2}TQ5^u8 zXaJr*aiVHe1Ui$mF1Lh(z%DH#l9L)uf8p80Xxoa_3Y`?+W|LBoCinEQ6q#$V?j8v_ zYqk4D^=P$5ly#79NkZY(tOFusC=nW$Jq~a&{ky)@U<5fVqP-@DioW^DSHs5c)<3?p;0?jGGWu+?sKEFw02nanMA+k*Z2e4tw9m_R30@j)t_5p)@nya z2nOw*XUC(x7meIbU~0Bu{ARKfTh6rf0e6QpVorAS$*lLvjP#i-Lv>4OSFqPH-%%nT z>%B{_DCypryQ79rBma7VBZUcT!r9tnaTHaF#lwusdKTV&&pM?-O0~2YsJx=uE`ovJ z1?D56m%c}+eU3--=|Ntv)!YP$H@W z3~WW6!LFhc_|Wt2;j1}=Y)px?C2j|4vd2uz-jt5pkcJ>K7OI)jrIVn81*sbTmEIAV zTa>OhfYXSqUmT^8m-1HrBaIuff1iBf2)75q%&RGINC-oU1N=ZoEIL5d@_NnEwNEX_ zK=pjptE7r3`*^HF9$>46jPU!GK8Eux+HCzuY>vH=U;;GyT|# z6FT-#?~(Ccdbowu#;>FPY3P6zuU#fGm!??IN6ApclTk;Navuo|yDGYt^e&1G5ZFto zswJOFj&#H%5webW_3Z(AUp%NJQz1Zo;YrZ1Qe?)AQ+o^h8%q-YMy#AU5ypNpPnOlo zVXe(~XV4`H6l*!z7UWUeF^SIF2!1*zpt8?S&aTixHm0?tL1`*`LZ>9h59;LIJ%8-BWNg>)UOw`jCc~aYRz|Y#avJ~$WE{N%oV~%ppL@mUBCe7 zT=Ym}$D@K$(zv*B5g*votqqy&_AW6r-;>~0CB_k5BA;|ZmA^c>~g3W+-HZk=`yTPW#rrSw{CX;?+(mzC^W7K15wxP z<^bjp?>%axv9NYJ(odTA)~zhQzc9z^U|~@APWhCoc?Pn-&C%V|J|E^igm!YyDr@T~5bLMEk!HruWug zPtv}F!j9wNLPF!B^M0-Flu_}xschrXh*Yo%oK4xiAVP{VR4UCHp6n1AfO%vT!~jx3 z_y7`JHq1Mr>M&F?dp?e%bnh3`B!1^XC_IQ!Dv$JWROy`P36Z724(c9Nk1h?~<4t&NfN^0&m zR6k}a?VWXMaLNl8!HT(@GSoueFv%0}$BkjbFJbq4yoBntK!Di@`TZ_vtfuYZ)zD|xkGt(yL@9e1xm4W;pd*wvuCkKmnPRA(jvhWH~6a{o|>dBlR` zOZVsQBnj|I)_fxcsxML6$%k7iw|ZZsZqr=GgbeWS|NhB=A4tl>!;Zkhd9h4}@QvLM zHT1>f%Y3RRr4fSS^}=>?5XA`6S)|VmikVqK8-B!v9sat_Y(CDz`MeKwSpKe z)ze;x9Ef#g)bl_TZ4rPlS(*Jr5DI{&JFM|z}WJ0-RmFM4#kSIfHQEHipi{j#{ zjgH~h)S5o7Vg!1_aQ~6^dK{1AX8bmb9`~gzLN#Qzw$5m5Qa^vI+waTDEAb6+@*BcL zpkt1o0IO|nwVWgH$5_PIjx|0;p4qz5y7i)eu1oLVPQ3TmF3Ue!nsPSDoczWM*oCWv z0IKC(iRE;Ibm!~7tAd+hLjxcB;Auo-a48aGumCGwGQW1%Oi+2SzFYHYlR6*!@FLNM zWw492mO^FzjKF&49Tc1EdlU`aLU?RI{gEyl7z&d)l{WLUz7A$zJM4GFTWHs_akAp_ zwdl$rm)23_Rq3vP!BZ*1<_6v$>1cuylq>{WP8EUg($RDvN3_y7zkk4c*!|7g3l$H< z%0Ze~(%%TJA5p@*MBjnAx1jOseZy1`hb`J%>CjZN%1)pw71$<@wT2qn62`@I6ZJ!Z zCWsAbB+~K77Zap&^4~U9?T4c3%%f6FPls>3j(u0}Gee8^imK?2)6(BaL@{OF26lI8!ey{`<2s%zU-x>GSbN_#?L&eN(g% zNNO-En80 z#~Y_%FmmM>tE4;xo}gm7C$5#8&T}o!{sSr!7o+MZV^xT_0a=<|KR|`=1p)fCPDotV z)puH}#^nYHbZL%IOlUk_v=d}^& zIMqy5ty%A<-*76B7Vwbs(~a=iZ-gWk1bNkjHgWl;!v24vDpVA37F~U?^^=Suca7B#j10#u zQnu2F50@1}EyFpOg0!mP;YZVy>UK!}hA%Uwh;c>>Q=pqqb*WD_NdbyEY@P<>t!A zG2wrHh|F2f>n}Cfg3LO=9|TA)=O?ZRzIG%;=os<1axgszP<^MUDteQOd7JIBkf)9H9j9#hw|_?A3{=YLHnZ&Wg&)d0 zOSPnrF^@2(S91e3eJS$1s-ZI^P!fW;2^#w}oVW?kBYykq(TB;T!X-(m9U(A&$dK}RL$2R+b(Ib>h<@Mgv(yB0qbq0?j^4@c;GXDL-MvHTq= zj1j#=v5il7!Bw0wwm%GHrKi7az>YX?gji4nV{&GNSVwKToVo`?Noh)ML>K?bLii7~ zj6?)Zho+<#MZ;sQbSJ_$6!YkuQ|1v< zJg!9gW7RVV#}~iH+d>#q`aEk9a|HQH67p48HPdAdiMn;!G@st=v>mf*BmI?h*0HxE%&bRD^&$VbxV;Hc`te*nP$p_sIO zgTf{Ixkb&GC(_e_1NxJ$DJW7Rb*$ZAweGi_5PduRoKfYRi}!znZvU*-Ogu*xZ|3as zD83Hk9^Y3@prT(MOFqISulim52${~>@;_FP|ETLpy=N+&Gl;9sRlKg|eJ>uw6_drc z?4S5`ZC*rBs%X@Jknt`c0BN?qq&9~``tR^(0SXuY=Pz>j;ZWuR_G|#Wv#HIOPr6(P zNd1@0=)WpMdl689I|Hmb=v(xNx#_5eIC$xKB*-O zfS)mw7wP?k%(?@O%l3?dN6ltS1%cxZerKdzN*wFH%Z(o(?PI?^A0O^5rWJTc2b4Ja z?J66RpJZZ#hP!v3Px`Jk-z$Z1gBD41{AE|CLa)v~61#yVyXwp#*~*Vjdy33TQrDk4 z@{KzE>Ht!lyp7FVNQVqZ<$qBb45kKyp3m_OS#(`D(d-aO~>v>mp13RN44%ho_7bbcO$(EX~On zqQK*1I6W$|r$@x?>pn^rP!T;vfT*Z^1?{wybM5ovWZk~i?--E`976r!>wHI?0Y1}B zlfbmCHf%S){>0#1=NxaXyN?h z00e9B{zLP62&%|a4w&XH9C!*rvuo2jei)z#TP$1qeE5=A(Nw1Ksuvf|81M_8z6z% z0{A{|o6(J^C{$Z@9lr4~LiLN(5+O1`X0&^vr=|b#34!|f(=A0G0G^%u$v+N6^R8;| z{^6QZKUDqsJLzQqNmjht*HOn7yaoswIW@C60YR$?R$xK8e?eJfE&g@n4;7Cj~bGl@RQ1g zN-CV$`Mm%I;1)0il7LkFkZpP84w9n`3WC|rNcY@Ie=pksRvkjPAke%P>)pZY^O%0) zK@C-P0ID~rByvw{EoF6NU2g2Om-mdexao&xIaR>C*_8X^N$dt`i7=6}h zSzdb#X>UF2GF+!*Wq&Z86M=cg1@@V~0Re&eRKeacqXccLIRHOkp8_xyp*f+m4t5>~ zhL}n2K0qgn^vayI!qh3o;@`r#0gyg=m)$WpUu3sz*?j=G)u+&@5#y9={q(79Vr|MV z?&rrf10YdM$`2@($S1cK0r-|K#lSr+!?7DRys`J}^$mcHn$K0})Ggb$4g%CNqHWsh z@d3_@L!c=K?b?D#bf`Du?GL=~FXqX=c>t1TyYH<)Og@}IC$BG5T~YCVLOAnM%75hg z6u6i9LWtDGdY9>Ko9Ee<$m31ySGiC69YB6xRYgUGhSlwx&Nt^myK1+SVGlqaPSk?< zen&rQ9LI`KxVi&oE5`5#PzcV^{cgL?b)XdTs=vEkdmOX%f$o_W#ou2xb-LX%_?qR) zcl7VRehchl=!-o>XRGRKJRfA7<#LTTh7D)bZO+lF0X_)FUSK!1Wm2T`^a7Ba74ZZx zQUm(xn`{yPjuim7jj5?4xd7UC7|@r~r)G2j%UeuaUBVCoW;7mzGiVmfMS(E_&eFbr zyxxrc*=h#QyaddS-{3GEopcV1h$s?nxx^7Z=~a<1Oi*rW*u*3bAykrTtiT44t~)XQ zG3$?UgP*xt^FKy`Ux(pu0m;|pcr<^!{+>S{J8v`5v7`IwvwdDQt$LMD-^FQylC574 zY!1ZJ6qc0@eY<$9l?z=Swv6< zEuP-bnERQIm0MI zX`?vD_@UXV>0&BIM1uPb^3D~Mib+B^aQc&4FgCytwY;M$go45-wHN7m;rvOC0v1mJ**7BrLsj7P)v9YuANbBHa(9wi8xND=8|)Ka6S0t{_zfwcdDAm4 zIAGI!Pq!aB)gaVunKz~%$R7BBKe_=Rm&KFs3@2lz8t)#w#xnSwp@k^|n3QHe8HzJD z?(%RccBVu)5t z`XjREpVVQIqD90hOAVJj*jHn3hcSV0$(hM*J2? zJ@@qxnADhR#B~LSgeLz2cmOg7?51@wo}}cQUv!a#!r(I%w10D@fv4CFoO%hW;CBtL z?%7fMz&j1|hAunoE9DI2ehXjo;BW&Ag3ku-0R{%^E(Sg|3L80@jpZj(oWKbjLUK)Q zNAwfXWw4b3GP2GIVx8hjoN^dKPo^sk_+4ra2deR(lflrCu3z%kGN9|)ZrMe#De5&j zVU$?eXEz{4Pz=U~Ov|ZDjNeT^Rj(xW2OKz56DmY_O^Ml_G*rQ*cVXlnDt@jDGG!c5 zfy@wl5I06qBIPyP%k`8yJl^hAB_yM@^EfXI6?i=mr!}f}d(jbF4emSbmjfl`L`FWf zdR&t}qAc12qJZ?+f?(xrqbh4j%obeFiWBNs! zGH@=rC8%Iu&6@YxDmSPX8Kzp_pz@g%^l7?C!R6x9WkMC@)ejX6?Yn1z>b}Ltv1{Nt zS;l)3H;r4u)mjvB@}8jpm||xkI;5?b2??7*zx;!k*Hod=W;jXc-sk?>=lm9@{($0M zAVH}`TV~of0=mR0;`0_(7P>X`;P;v0|+Syeu~s zKcL(O>}Q%AE4OC6w+HZ+WP>^adr1hlpe|{Q0il-~&?So&FL9&(x0nISQ&+|fV*c3i z5d!6(ZzwLrc3(tg&mfcU8yI(q_>bj{s~Y6*nYMhBskB&5ARN1!t9;qbrqbnPRIXEI8VH69#01cmn zB){r?Ru~1n$8`INa7nGMbYRpMzWOrt-D#xin%@$H|BA{a1Q+Wz%_A+0! z$7ZwdU6qQasPG9vY=cth+(0V12aWaCTzh?544)U6dgguc&DZfpQ{$q)mGX$yiGwDL zIh-snAOv8fOup^i;&@bkKU~lv_%{mCAtF4}65(3LOk&isRIGp5IT-D{CwYQMqOnnL;3oe-#lsZy zYRO^3VXENSMujBaK20;z>YF%+YeahlZtR&k2szlw(d36Qu))uW z7V%XEMdkENQKdBt??fcOy&5sHZZdh^U&1f7U{G`wM9e~iwII)(0-js7seX7V`O+y^ zAm77`zlU;&2xePfeU4tQl<8vI9Jgq`>E7bUWa~5Mc;;DYu;dm+j%ho4Dy6ErS`kW0+`o=$l#{1#{46q%eMo z#6KCRrD*Ws32Irj;<7Yb=DeC>)NK!YT#P2Jmv1@-u}*-2u+WW=G{{0u#25@NLP@Fr zT}HQlV=~FW9zZXQWI8n>88t{9`g|g{7xy$LGo*z+)^(wR1IC!0%Dk>Q$Z&M;Ghq{N z2tq5HEaaT7aZM=8{MwhYx3|kr;5XQ9j3=2^E*kgpJPw#8WDlp$1Ti z<4FM#z1UOI?WTFpYOPGS=Hb_ruA34>v&_(>h;b;K@@IR{0@mUzL3r96RCgf7J>J95 z!O!;iPb?FVhtgU$o79eMioft^_G?h_3gcRAL|>DjxRG`g*(tdJ`wd_B)!?4`g29YX zq?I+!#7@ql=D`npXrzzxkT*yI9G3QrqZUbij|lxWpeM>ff7NCTZ(`alu{fnUp;@~z zmPc|y6=N+RqxM3qaP=#WRBD{|#>p)iWwm3rc)Pl@oURP3?hDu=A6_wKF=o6lN(f$} zt8a0(<&>D9F_}ph#;L4Pr5WPI7aoNrjo-ydISE#Otf&b;4<&I-U+T|04e&9`oF#!$x0GCUd2Fm>~wt#fuoUVcg2PDH*Co?{^qg77LF(@V%grf34J4 z>?+PL@_2W~oqa1!_h}Jl;X-$5ci<&GN^voUIo3pl^hBS=4cqA z0mBHE)U{vIBt$RAJ*vBWcN8JS5;VFhT#PDlc3MA(JU`R0CXp8T@T6}rb6%PtF%r2a za4EWO(zzXtz{i9nwZG1#IoFbR6EC&5$+*kqHtv?&9WmE@O!Z-3)I?RfzLO1XS&y(m zWbDM?0dMHYYI4fC?S^hY?g#}X4!+$&J(SY_EGOLUi9j=&-#1FoYz3DGN3o?; z`wLA>QlbbVw*vYh`s1W}-N$kx#ZmPpR?W{(SKG+~um3v|_3Yp?a~#!@OnwBWv}@>z zfANpxtF52?>3pvRSL1p7I8}lZ6F>??Ur3O=SMiY~5ttEm+3Wu}frnEo#M-EfW@62Y zM3`2C==3|eMw|2PbEHhWkpk}eMIPeWa`Ujtx#6`cr_*)D8yk$ZbjKUii`|*!@(_2PAwk3Q&e}YhSM#KEB6>dsA0X~xe66yuf`;y45w9D^; zvoSXh9&$Xk;IHyIxWr*-V3fntBonQ1T{lUZ2*o=3A ziXvDsGeY$PZ=7xw-NqkO!6y^C5E1_kA`Rppp2kjZ%0BeUcE)A{H?U)*7F_K2!)=Q9 zXUw!axA02Hne07MtRvYTy-y*gsIInguWev&v^heO7ev-*uQ))MB$BYvP*nJ?J$apr zt~Ip8)O73;e#r!sje9zcr?LBEGpgu$)0W^J#fm2pVIL-nhd`G@^FeblIKG4nNUWFA zGmTA%eB$4^O@zPKl0bth0ZZoW>Sob0tIOT>J;llNG4y&Mi65Sj$Hf0yfyW*nYaO;O zIrX9L@9H_eqPjDfWM7l7TP_?!TG`cEq=NA!`GWO)62y7 zNLn;ZTpXz^HCBDRjAk`fQg~+~1O{n+QRtHzMj(VZ8IXzBvoKh=?F5Wvk)V=dNf)H` zCe^ox0CWsKXG=Hd=Cb7$e8V)r_k}mC5=%gCbueEM>10?al;+z0epY3}Vk+Pr?tAs` zfr^o{^ZMwFr%r_|+x?QC#4s^l`ry`BvOnjftM~Eir{raJs+pDTRI~(qJ-oQ-wK$DH znoQj}_d65t^u{9<*5fwKqt5hQVLM2ym0Imck_@@9u`9DS%VsrdyfmEE#lJV7;oBSb?w- zT>dU|SINH7>a6O8_LnZ#6M;i*%&gx}Uu3RdYY+6ys1Xe=SXFz|LsMkFvaWl>7zj%| z6mK`85NH))_m25~{k?&`@O@;2>}-PXO3I_Yy-BM#SfaR3Wj*Kq1?XZis4Z%v1Y&n| zmSZTZ9u()WRjyPUgoenYsge7rRql)W){XeBKEdbzM(0-2uQfETu4GLNjDemb4#J?W zX0eo@3$CAhTdh{qA%1~~qcx?kcb`pQ)okQs{5Zs_d}R?)V3(3MgWqkY5>u&jXCfqS zRQMtMY7l`ejUEP9RZuM~4l6BJagiNj*YKYAxDU>B6hM{efA4l|6rSyDx~{oTaI6*$ zQQ73NTq@o9L{hva{rjtr;ny-T1O8&KSE=I|J>hl_2^#QjiMQ^|n@Y*~ck|negRQPE zMeR;XM;Dtf1;3e$lHJv-->J9rj`$~6u4Nd?0Gy`y=OlFjNKq1IY^YQ1awL@LSHvUG zFusM)_^#9y6+N|ZLkQ7-sL;We5c0CzbtwZK%z{lCEX@Ue{qQbNxLNMAu9zk&e#D=O9pG&&RZRM8%fSUnIP4%OkrOAO*5l*oDr_Q(}qE?$%iv$g%p z@3N%ib^@jHH|)TgNklQyy!%b0R)MJVQJB0DjP^n=Ot>dLAnEiwD_riAtrA|bj2dNX z&n;AZIHoAeD@0VWq*VpNMhGqm1^cDFR|%PM10~w7j(l$%W@&BygA%E95)>?j2_ijE zleFs*MNuSU=@PaY`G`C4`k0Fu!!>oKRx1*<0WZeY6J;JAlu;1bsAw1->#=Ej(0wBd zWJkT_2(TC@6Tdzp3#Xw(!r_QqTCEeQ=?|#}yNi?O34cP4ba?P~>rbjF2{ieD;ug~Z zX~aHyvqa%heGh+J0_i~wFNjv9|1I&_4rWLIQuABAsf0tdP-8l2^Z{tZ1jR@C?iRUK=dKTkR1XCb$pG;dW-y%Cm01yDFp|wQJHg_# zq`R@M(DvxR)034i^Aq^Fuvttu1`P916!C88kHv9$U-JWj%Y{9)F}EtXvG?dXcaA?& zKWjofQ4*>QELD}XUv?)F99WB-a|`TT+r+{!W6q_l7oe0cv7uV~jHNrTpi6>I(^pgT z0p#KWiyNXpb7E9FRZ-0$h{S}K3)y2nDa=Hv;-Pf2&E&=LbM)KqI zRB_QH)VfAMq-T;aOfA8yI{JEk))N#e@I2QTFI;aA{mAVYq^pEAleba|n760PJCVGC z$5|4r2l*5jTw!fwwR@lheQwN$5N4?qcM()VS z*KRqLr5Zfg^J)cY(%fpQX(AQ}DbhAhy{6cI3jYIx)*gmG@X$;wx$78q^rdF!zF?RQ z?;G%e_2zoJRgkR6-n`VEXb^QFS&Njf>E{7)6bpFwH!AovKj+cD6=F%ELMX8`Olso? z`Jv)!1an@JH`~NZ;7b*DezUwjaSVDliHQ85KZ7(7!#{x-y@&nO2?yJ+DsjGoVTyaK z_bi$`sne6f+9=}I`)yWCIR^|Mr*@9J`Z61tg>b^GF33YUfR)@7M$Hv5qg5fMZLT(0 zaG2M-;pzg~+)5V!`&u!LO3EPnqR`5sswO_V-Yb_i_CKhM1U`AG&HGPdhj8bpI8A+Y z0zKPIw@3bL9WN~ug?kza!m4|oR%lu zo)yL&_UiDNvt*`4lq#lei+h@^kO`2fO>{!c9piY{i@W07jPn3({Y}YX@GLxn{--{z zhBy7&DFi6UAFXNdB`%uZH0HKK>M|pCEMsQpmeovs)dlui8`WS)*K>BIX!`QXX zA@3q6>;ETe^fTA&AsfS#`#tB{P|3-O(r#4JjR2o6aq88W?`59A^~eg~Pyu2E*ZG*r z$s9m`#RedJbd|wbd~LEZj37kzE^%3XJoN&b(wwY>xJ^@@NX|v!fncG657q4y`s=mm`25?T0*%{rGH@} zV*Nbz?K&u}WkOWgCJc`N&>Yx@wtjhIMeUHrXI$@upq+rvRC zyzt}ohedmKFVf!|0AJ^I-wp2ZZA*|xa_)po51Z276PvRPi8w)c9t~Rlxc~-mjJcBK zjjB;X*2S(%hgb|+M+&lVup?=3VBlaM&Q4jLEDMsXV__X)YXiC2)gNXQkpWw*khfEp zX(GKRkoPMf5h#pZq;hMNGSug-^GPd{Hal_F=qLGQ_v9VB8Kb1EXfBg?t^Jm>-Zdx= zfR5N1U=|FUJ>E{*Xv`n4l)d9hcef*IHj*$z?~rX_lg`c(%lDq6DA)9qZsQ<;cV71- zvze>_eCmi&6OsJ-xNAy}Pi-g%BaZX61~#|ofHc%Zf?M)I_^;Sm{*}U4Lawfham@&m zvFI+kBVV*VEfJZ0UWXm?%sL>|HD^i!9j=vu#iHT02a9RuOme*$@ z!sj&!LN$8h52jMX>48f!T z0$#Fisp&peD-QLUm0 zCh3$!%(BTW$Zr4&@Vnk*`*cpEop$i8TbVrW7X7sI>qBrcM)|cc*hP;)XxU*3VW|xa ztRe5hAWJAZqey*GkPk+>IC=>sh=w+CrVJ$N$iv|+bF7EJCufm}a9T+U;HpGWM)s}J zBt=>lI>u*ff!Wx7&lQ$V@m(xyYqD|9s7CVhK&NTJmQ|PmA=00coJSre@*EulWlgBQ z8?u3Vp`h?@a?B(?iaH+#1{JDK=U)7_HQL?7p?aLql#0hC=4Q z-DidK98=KG@ZjU z>EHe@M-osmz!l1_&72_iSS-%mrTW5Tdor$|XHAKK6g&rM9W14I;(yOM+i!Mjazcvd zVI^wl-M`XFa+!V5@o`?mTd6bE&=-xu{F+uega~ozXJG*J=&f{2sK|rH=L|dwPbW}U zCqfKQW3Kt)%oXVy+sOHUQtAGaa>W3rBh;(Ku6ud$`}@d8>GshZ0+%Po8o7f~P+Uj6 zgHlSondJJekvQP@+lDePN4HvDpQ3v=isx^q9CXHui=r zeLnqIJitHuIL2ok&Xq9lGaPXoowGyg5;^{t`mGO8%nbt3j0r>(63ezHi$yI-Csv=! zqC=+l;lC~bE&^+5oqf~}84>9tGD{x%DQ*LJUy9xpAq&(?kwFSEuV7OpQ-Km=g#YL!iv9_j0;HkXSOlxrJZ0I zg>Ij*Rrl>cKLX4HQQQw}_S87g_fCk@RW_~YxH@oLFV}X|lEEHK*^@f@f8%6LNa73- z17C4=^-5oJDCk`)zv{$d(pP=-%`#|n$OM$SAMt8}X`>H*itnCn%MSCtd$4|%H^*$H~fGeqLoq9K+)RMu}v zW*l4cSBkv|=dKMs9jkkGtyFKyk6U{^Ur)n|Chz{i`2C-@1o(HNPOswBJ`b75ew)i< z!N@e;2g*x%g^Di{wzbZygd+T?dP`cC79x^kbsIz^Os{4nwpre7)3NwK8xvBgg(aN_ z{+y?*`m`{)?^lw~Gd{$;o>~5SyKBIBPky2_KO_}cdL>jR$PAP!6&T&VSInGFVj2MqF-9YZ zo$G>_0h^#Yt;?0aOoAsmUj>!&v@j2&*c_H*L&@mep4P2}Q1_9ZLPl-WZ$#9{iPFUod z2n!O2QRUcv8RqP+KK>}psjxP2*fLPl?uFwkz7qbU+An+J6lA#dE7bRj3pqzO?r-HP zqX)D-`CJTA3s&+9Hfz4xJ2N(sF&pwz;mWQ?zGW{)q~G4zV9SFQ@TztG2sw|-4Q!!p z+lHj#F<4lx2`PMc5c%&e23}Exq5$Uf3897AB8<%5N3RP%2wE}ADOYN|6tozfw<+`;zZ6TS%9lgn` zlbZH+*SMe%KYO@Ger~18>0n6*opJv8Xp8r|s{EQif1x)9fC5ByZZ8i*cbSVBwPbn^ z7@qdY3Mqbzxdc(Q7BCFKTLls?n`QQ;)#l3B!TOQ=r_u2*2opfiO$e6HzpB`H2%+JX zBLUGmU3PDuO5q@ZT47qMs+kRhqY2p}4Q+WGhgm8kVX@05GM%m@J@4)*5j$@Z zZt|;Bh7hMu2@Ik=bR8xe`+TX_m>wKWsOiV2EdOE#^8yo&?q}=A>YV8+IY21aiO?O!nU)-U@+V zdb{g${?c~=uf%f1P;6yA?VvUDZaUl-3cLVZ`k~bic}shk5~F#Oj_0)?Sc{t!s$k6=Q-u<4eytEUpR%bFOQd~ z^{s-41+KB9b8%wrf_w_)NHII-ss4T$b1$@iTJ7sL_{5KRKX8=ls_3<*SMqHHK}LF- zG&~tSk58KdPwzB49-!%bVzZ8%)`1@^9M{M#x@ThT-eRwzG&_t%7}MOlm{_GS5W&P-xd)r#UI7dHynAkTN?S9Z^fxk4583@qTn`;6WZxYy{xn1Ny51T7Va>v=Zf2`q{qOCFl{Q?ORb()3Kj!9 zi@dDkNSA~mf7$u~y8ggELx)LCitkxVqMI%&{jJImC#j$LlUqtsS5cO*Ow|j@-JyoSXdHj}qvE5c6ybfD5k)V*cLtz=Ag5ub_WFlKh*dcn47{Dt6EoL+2)&XMQ7 zA-`p7zWH3Y&S`9lJ?14rECh3Ik1plt78$ze>3ib?qx}Z$)kC-nwf7CHf4{1l#ka4* zzZ0`2o6XX`UC>1@v&KR?$jeDT{O8e-4q~OqK#0PW`Pb&k7tawxeIvtyRbOHOC@Vdi zDoMz+M{I9~8**ev`?BWV7r6jIlZC9Pa-{5+6z-G;O+7VO#ZPG#k1bPv@2js{LFE3s zD0@1snbaa9X`td2-vHGtf;aqmQNDryT{qH{O z->j8yN8GbQrrr6a#{7ThnSSn?`s+zSTqFo2BR%udj_ZO=!$bUPchZ-Fu_%tOr}Eez zN6exYqxZT#QYI*MJgR4<|7m+)H`d4UhtW=Jo9KaQ z_)YR)0kM&cg+<|Xg<`g#ggdn9YhrSuT*{?ET{<87U&-uj2&Od3I0y~4H>PPKFr!?-FmI4ocel-SB)nKN-&CKb}R#N+FHCF84lq zWMpPel2-Irj#=1Y)1e?+X|UEgG5xhW40u5OcVF~Ih>GE;f8U&-4NHihxznJdD>hzR z*y`!(M=qvoiYw2CLGJdWA0eYHANJ~+jiIk}z8YBRv>)!-``cd4whnf#HS4|e{ZsGy zemb|d%lPK6Cxb0rkvpcCjJ{)DATIa}SrfqR@+%OVE4*u8b@g2u{2_@0>c(uK3 zg6cIUmV#~P^0w+yqf0JbrAk5Z%K<1!f0cnlg}j`cd4p#8U|a8*ZE!GyqlHGH_gIrg zN~LykbM-dgXrRu=ahc6-!@ssoh$z{UKWiB(aJ12@`1}1K{x!{XRbKJ0t8BU&8XECi zFFwjC-n5(FB#>Oa<^1cDV+7pMD90fXyre31$!=FpM$Q&tAH;(5k+WQl>=IrBi7I{# zOb!0K)7gz=4wZt>k7xBu2gWw!cWE=^0d)A;Nxhp#mEO;GrvK6cPw@*G%>+~bx)t3u z9X*S_IMbGc{rPmcWajMu?tS2uaskSVU?h#&h98g@ z;U4p*d>9OdiX%yXS#pd~xDXK{B64g4>M1zAxq+Z*f<;8M?7(*887S8BgFnWOl> z1Z>J4C@<*55c{5-=75uqzA8-y?Y+>Q27(+2a8_5y>O$q;>Ujwl94$JDr*6#5;K0lb zuTVywqi!%ri0ti_qUbYLUljavhso`4PZ5U@kOwOHLVsD*NZ}Dx|C>jdlDl+2f>Hz$ zY-Zmy-p^I4+BEW4=e20;fOlfb4cbHSfJfYSc7?tJBGZ=ZeCg2)EyhmWBiHbpVDo@!){m9>>G2dBHxa2;U6%LEZ0VnWCeyN^Sq9nMO z4YN@p%BK5=BJ-b-^FwEQtCbCHME5hFXp%{FmdKgZq6G-$T? zy_2-7#G0w5lX5~{SwrmbgZ$%qfCYfWr)SUM98i4rKf~(0y<_)I$ErChq%O)0G%~q2 zo&C>SxvWAhoV{Un37rTiI8>rfZwLOkc86m?vlVH$6rSz9_<4k!v=fs5P|DW-fx(yW zQH>(z>ZcJ2h#>HPKS1?o6%LAKOId%9_GfC&Q0KZq@xHpoerC6#W1L{_5)EqZqd~#?FvsCF zMKHa%*(?%c_H=XqzRLo9Wo4sqAHRm=ncgH_ZQfzydd*{_dmW^P`Y}wcz5RTS$7~~1 z`{CXCZ~Lomy7JcE7Ot9)*)goGyNSXE*S6qMt-{pCfXAI47k4cWVJfh%y1!G%1Rx|MS}af8YP3b_uY$VLQ<@Gf4jV QbY7{fl%iynxbf%z1J#d&c>n+a literal 0 HcmV?d00001 From 8b1f989b0c83fe7332bdd0897d0fafcc790354c6 Mon Sep 17 00:00:00 2001 From: "Luke Charles (charle44)" Date: Wed, 23 Oct 2019 15:06:47 +0100 Subject: [PATCH 24/70] fixed typo in 3.3 amended type "is is" in 3.3 --- 05 JavaScript.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/05 JavaScript.md b/05 JavaScript.md index 27afe040..9604dce5 100644 --- a/05 JavaScript.md +++ b/05 JavaScript.md @@ -391,7 +391,7 @@ const last = employee['last name'] console.log(`${first} ${last}`) ``` -In ECMA6 is is possible to extract multiple pieces of data into separate variables by destructuring using a [Desctructuring Assignment](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#Object_destructuring). This is syntactically similar to creating object literals (see the example below). +In ECMA6 it is possible to extract multiple pieces of data into separate variables by destructuring using a [Desctructuring Assignment](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#Object_destructuring). This is syntactically similar to creating object literals (see the example below). ```javascript const employee = { From 0e7ec413483c89b70724e3c805b647707c61b672 Mon Sep 17 00:00:00 2001 From: "Luke Charles (charle44)" Date: Wed, 23 Oct 2019 18:11:25 +0100 Subject: [PATCH 25/70] typo ammendment changed "vsriable" to "variable" --- 05 JavaScript.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/05 JavaScript.md b/05 JavaScript.md index 27afe040..440d30ea 100644 --- a/05 JavaScript.md +++ b/05 JavaScript.md @@ -685,7 +685,7 @@ const matt = new ECMA6Student('matt') console.log(ECMA6Student.studentCount()) // prints '2' ``` -Notice that the static vsriable `count` is public (so the `studentCount()` method is somewhat superfluous in this example!). This highlights one of the limitations of JavaScript, the lack of a simple way to define private attributes (variables and methods). The next section goes into this in more detail and explains some workarounds (hacks) to get around this. +Notice that the static variable `count` is public (so the `studentCount()` method is somewhat superfluous in this example!). This highlights one of the limitations of JavaScript, the lack of a simple way to define private attributes (variables and methods). The next section goes into this in more detail and explains some workarounds (hacks) to get around this. ### 4.5 Handling Data Encapsulation From 210ae9237f14c22395a2022f48754345f6159fdd Mon Sep 17 00:00:00 2001 From: "Mark Tyers (aa7401)" Date: Fri, 25 Oct 2019 08:56:42 +0100 Subject: [PATCH 26/70] Added Notes on Installing the Browser Preview --- 01 Setup Win10.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/01 Setup Win10.md b/01 Setup Win10.md index b518f381..5b478f49 100644 --- a/01 Setup Win10.md +++ b/01 Setup Win10.md @@ -11,7 +11,7 @@ Enable-WindowsOptionalFeature -Online -FeatureName Microsoft-Windows-Subsystem-L Restart your computer when prompted. -Now install Visual Studio Code and once launched install the [remote-wsl](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-wsl) component by Microsoft. +Now install Visual Studio Code and once launched install the [remote-wsl](https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-wsl) component by Microsoft. You should also install the [browser-preview](https://marketplace.visualstudio.com/items?itemName=auchenberg.vscode-browser-preview) component which will allow you to open html web pages. ![remote-wsl](exercises/.images/remote-wsl.png) From 48310c0c4da0ea6059619a57e781587cc89eb4b0 Mon Sep 17 00:00:00 2001 From: "Balazs Bordas (bordasb)" Date: Fri, 25 Oct 2019 12:03:20 +0100 Subject: [PATCH 27/70] resolved Issue #25 resolved Issue #25, promses.js now does the same as asyncFunctions.js and nestedCallbacks.js --- exercises/06_code_quality/promises.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/exercises/06_code_quality/promises.js b/exercises/06_code_quality/promises.js index 00d9ca6d..671a3dd0 100644 --- a/exercises/06_code_quality/promises.js +++ b/exercises/06_code_quality/promises.js @@ -48,6 +48,7 @@ getInput('enter base currency') .then(checkValidCurrencyCode) .then(getData) .then(printObject) + .then(() => getInput('convert to')) .then(exit) - .catch( err => console.error(`error: ${err.message}`)) + .catch(err => console.error(`error: ${err.message}`)) .then(exit) From a4ffe9c0608937ed09f3ec72b9e2eef69b96de7c Mon Sep 17 00:00:00 2001 From: Mark Tyers Date: Sat, 2 Nov 2019 19:52:58 +0000 Subject: [PATCH 28/70] Added Notes on Script Explorer --- 06 Code Quality.md | 58 ++++++++++++++++++++++--- exercises/.images/npm_scripts.png | Bin 0 -> 18576 bytes exercises/.images/scripts-explorer.png | Bin 0 -> 56986 bytes 3 files changed, 52 insertions(+), 6 deletions(-) create mode 100644 exercises/.images/npm_scripts.png create mode 100644 exercises/.images/scripts-explorer.png diff --git a/06 Code Quality.md b/06 Code Quality.md index 47d21c4b..81cdda6f 100644 --- a/06 Code Quality.md +++ b/06 Code Quality.md @@ -26,6 +26,36 @@ Notice that this has installed all these listed packages. The manifest also spec $ npm install --save http-status-codes ``` +### 1.1 Scripts + +As you continue your development in NodeJS you will need to run a number of scripts in the terminal. Many of these include a number of options and flags. Rather then trying to remember all of these you can store these scripts using easy to remember aliases. + +The package manifest includes a `scripts` object which can be used to store your custom scripts. Take a look at the `package.json` manifest file in the `exercises/06_code_quality/todo/` directory. The `scripts` object looks like this: + +```json +"scripts": { + "linter": "./node_modules/.bin/eslint ." + } +``` + +Don't wory about understanding what a linter is for the moment. Since you have already installed all the module dependencies in the previous section you can run the script using: + +```shell +$ npm run linter +``` + +This will execute the `eslint` command located in the `./node_modules/.bin/` directory. The `.` indicated it should run on the files in the current directory: + +```shell +./node_modules/.bin/eslint . +``` + +#### 1.1.1 Running Scripts in VS Code + +In the previous example you ran the script from the terminal. If you open a project directory in VS Code that includes a `package.json` file in its root directory you will see a section in the explorer sidebar listing all the script aliases. next to each is a _play_ button which can be clicked to run the script! + +![Scripts Explorer](exercises/.images/npm_scripts.png) + ## 2 Modularisation Next you will need to do is to split your code up to make it easier to understand. Take a look at the `06_code_quality/todo/` project. If you run this you will see that it is a simple shopping list app where you can add multiple items and quantities. Currently all the functionality is contained in the `index.js` file. Locate the `modules/list.js` file. This declares a new Object Prototype called `List` which includes all the necessary functionality for the app. At the moment this is not being used by the app. @@ -56,7 +86,7 @@ Try running the server and adding an item to the list. Currently there is no fun ### 2.1 Test Your Understanding -The custom object prototype defined in the `list.js` module already contains the functionality needed by your app. +The custom object prototype defined in the `list.js` module already contains the functionality needed by your app. 1. Modify the callback function in the `router.post('/')` function, inserting a call to `list.add()`, passing the item name and quantity as parameters. 2. Now modify the callback function in the `router.get('/')` function, replacing the empty array declaration with a call to the `list.getAll()` function. @@ -141,7 +171,6 @@ Open the file `nestedCallbacks.js` which asks for a _base_ currency code then pr As you can see, each step has to be nested inside the previous step's callback, creating an ever increasing level of nested code sometime referred to as [Callback Hell](http://callbackhell.com/) or the [Pyramid of Doom](https://en.wikipedia.org/wiki/Pyramid_of_doom_(programming)). - Callbacks are the simplest possible mechanism for asynchronous code in JavaScript. Unfortunately, raw callbacks sacrifice the control flow, exception handling, and function semantics familiar from synchronous code. ### 5.2 Test Your Knowledge @@ -178,6 +207,7 @@ A promise represents the result of an asynchronous operation. As such it can be ### 6.1 Creating a Promise Promises are created using the `new` keyword. This function is called immediately with two arguments. The first argument resolves the promise and the second one rejects it. Once the appropriate argument is called the promise state changes. + ```javascript const url = 'https://api.exchangeratesapi.io/latest?base=GBP' const getData = url => new Promise( (resolve, reject) => { @@ -187,6 +217,7 @@ const getData = url => new Promise( (resolve, reject) => { }) }) ``` + This example creates a `Promise` that wraps a standard callback used to handle an API call. Notice that there are two possible cases handled here. 1. If the API call throws an error we set the promise state to _rejected_. @@ -196,7 +227,8 @@ As you can see it it simple to wrap any async callbacks in promises but how are ### 6.2 Consuming a Promise -To use promises we need a mechanism that gets triggered as soon as a promise changes state. A promise includes a `then()` method which gets called if the state changes to _fulfilled_ and a `catch()` method that gets called if the state changes to _rejected_. +To use promises we need a mechanism that gets triggered as soon as a promise changes state. A promise includes a `then()` method which gets called if the state changes to _fulfilled_ and a `catch()` method that gets called if the state changes to _rejected_. + ```javascript const aPromise = getData('https://api.exchangeratesapi.io/latest?base=GBP') @@ -204,21 +236,25 @@ aPromise.then( data => console.log(data)) aPromise.catch( err => console.error(`error: ${err.message}`) ) ``` + In this example we create a _new Promise_ and store it in a variable. It get executed _immediately_. The second line calls its `then()` method which will get executed if the promise state becomes _fulfilled_ (the API call is successful). The parameter will be assigned the value passed when the `resolve()` function is called in the promise, in this case it will contain the JSON data returned by the API call. If the state of the promise changes to _rejected_, the `catch()` method is called. The parameter will be set to the value passed to the `reject()` function inside the promise. In this example it will contain an `Error` object. This code can be written in a more concise way by _chaining_ the promise methods. + ```javascript getData('https://api.exchangeratesapi.io/latest?base=GBP') .then( data => console.log(data)) .catch( err => console.error(`error: ${err.message}`)) ``` + Because the Promise is executed immediately we don't need to store it in a variable. The `.then()` and `.catch()` methods are simply chained onto the promise. This form is much more compact and allows us to chain multiple promises together to solve more complex tasks. ### 6.3 Chaining Promises The real power of promises comes from their ability to be _chained_. This allows the results from a promise to be passed to another promise. All you need to do is pass another promise to the `next()` method. + ```javascript const getData = url => new Promise( (resolve, reject) => { request(url, (err, res, body) => { @@ -245,11 +281,12 @@ getData('https://api.exchangeratesapi.io/latest?base=GBP') .catch(err => console.error(`error: ${err.message}`)) .then( () => exit()) ``` + Notice that we pass the `printObject` promise to the `then()` method. The data passed back from the `getData` promise is passed to the `printObject` promise. Because we can chain `then()` and `catch()` methods in any order we can add additional steps after the error has been handled. In the example above we want to exit the script whether or not an error has occurred. -Despite the code in the `printObject` promise being _synchronous_ it is better to wrap this in a promise object to allow the steps to be chained. +Despite the code in the `printObject` promise being _synchronous_ it is better to wrap this in a promise object to allow the steps to be chained. If a promise only takes a single parameter and this matches the data passed back when the previous promise _fulfills_ there is a more concise way to write this. @@ -261,7 +298,6 @@ getData('https://api.exchangeratesapi.io/latest?base=GBP') .then(exit) ``` - There are some situations where you can't simply pass the output from one promise to the input of the next one. Sometimes you need to store data for use further down the promise chain. This can be achieved by storing the data in the `this` object. ```javascript @@ -288,10 +324,12 @@ Study the code carefully. Notice that it defines 5 promises and chains them toge ### 6.5 Executing Code Concurrently In the async examples we have seen so far, each async function needs to complete before the next async call is run. The diagram below shows how this looks. + ``` - 1 2 3 + 1 2 3 ───⬤─────⬤─────⬤ ``` + The program flow is. 1. The first async call `getData` is executed. @@ -301,6 +339,7 @@ The program flow is. There are many situations where two steps can run at the _same time_. This would be impossible to build using standard callbacks but this can be written using promises. The first stage is to create an array of promises. Typically this is done by looping through an array of data and using this to return an array of promises. + ```javascript const dataArray = ['USD', 'EUR'] const promiseArray = [] @@ -314,6 +353,7 @@ dataArray.forEach( curr => { })) }) ``` + In the example above we loop through the `dataArray`, creating a new promise object that we push onto our `promiseArray`. Once we have an array of promises there are two possible scenarios. @@ -330,16 +370,19 @@ Promise.all(itemPromises) .then( results => results.forEach( item => console.log(item))) .catch( err => console.log(`error: ${err.message}`)) ``` + When the `Promise.all()` method fulfills it returns an array of results. In the example above we loop through these and print each to the terminal. #### 6.5.2 Promises Race The alternative is that once one of the promises in the array has fulfilled we want to take its returned value and continue the promise chain. In this scenario we use `Promise.race()`. + ```javascript Promise.race(promiseArray) .then( result => console.log(result)) .catch( err => console.log(`error: ${err.message}`)) ``` + As you can see, only a single value is returned by `Promise.race()`. In the example above you won't be able to predict which conversion rate will be returned but you will only get the one. A good application of this would be if you can get your data from multiple APIs but you don't know which ones are working. ## 7 Async Functions @@ -382,6 +425,7 @@ async function main() { } main() ``` + Async functions are declared using the `async` keyword in the function declaration, all errors are handled using the standard `try-catch` block. Because the main block of code needs to be in an _async function_, this has to be explicitly executed at the end of the script. The `getData()` function returns a _promise_. it is called using the `await` keyword, this pauses the execution of the `main()` function until `getData()` is either _fulfilled_ or _rejected_. If it is _fulfilled_, the data returned is stored in the `data` variable and control moves to the next line, if it is _rejected_ code execution jumps to the `catch()` block. @@ -389,6 +433,7 @@ The `getData()` function returns a _promise_. it is called using the `await` key ### 7.2 Simplified Promises Async functions are implicitly wrapped in a `Promise.resolve()` and any uncaught errors are wrapped in a `Promise.reject()`. This means that an _async function_ can be substituted for a _promise_. let's look at a simple example. + ```javascript const printObjectPromise = data => new Promise( (resolve) => { const indent = 2 @@ -405,6 +450,7 @@ const printObjectAsync = async data => { console.log(str) } ``` + both `printObjectPromise` and `printObjectAsync` behave in exactly the same manner. They both return a `Promise.resolve()` and so can be used in either a _promise chain_ or an _async function_. ### 7.3 Test Your Knowledge diff --git a/exercises/.images/npm_scripts.png b/exercises/.images/npm_scripts.png new file mode 100644 index 0000000000000000000000000000000000000000..7575a28af50b2201f9861e86fd455294eb130ab4 GIT binary patch literal 18576 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 Ls?t@G=3)OAX2e1- literal 0 HcmV?d00001 diff --git a/exercises/.images/scripts-explorer.png b/exercises/.images/scripts-explorer.png new file mode 100644 index 0000000000000000000000000000000000000000..34eb60bce75e3992a56d1aad474ed4fd08f342c2 GIT binary patch literal 56986 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 Date: Mon, 4 Nov 2019 04:20:28 +0000 Subject: [PATCH 29/70] #28 mock-fs example created I couldn't make mock-fs work properly, so the unit tests using it don't run. The web server also fails to receive the POST request with the image upload. --- .../07_unit_testing/file_system/index.js | 39 + .../file_system/jest-test.config.js | 20 + .../file_system/modules/file.js | 25 + .../file_system/package-lock.json | 5536 +++++++++++++++++ .../07_unit_testing/file_system/package.json | 24 + .../07_unit_testing/file_system/pictures.html | 22 + .../file_system/unit tests/file.spec.js | 131 + .../file_system/views/pictures.html | 20 + 8 files changed, 5817 insertions(+) create mode 100644 exercises/07_unit_testing/file_system/index.js create mode 100644 exercises/07_unit_testing/file_system/jest-test.config.js create mode 100644 exercises/07_unit_testing/file_system/modules/file.js create mode 100644 exercises/07_unit_testing/file_system/package-lock.json create mode 100644 exercises/07_unit_testing/file_system/package.json create mode 100644 exercises/07_unit_testing/file_system/pictures.html create mode 100644 exercises/07_unit_testing/file_system/unit tests/file.spec.js create mode 100644 exercises/07_unit_testing/file_system/views/pictures.html diff --git a/exercises/07_unit_testing/file_system/index.js b/exercises/07_unit_testing/file_system/index.js new file mode 100644 index 00000000..6677cf0b --- /dev/null +++ b/exercises/07_unit_testing/file_system/index.js @@ -0,0 +1,39 @@ +#!/usr/bin/env node + +'use strict' + +const File = require('./modules/file') + +const Koa = require('koa') +const Router = require('koa-router') +const BodyParser = require('koa-bodyparser') +const views = require('koa-views') +const status = require('http-status-codes') + +const port = 8080 +const file = new File() + +const app = new Koa() +app.use(views(`${__dirname}/views`, { extension: 'html' }, {map: { handlebars: 'handlebars' }})) +app.use(BodyParser({ + encoding: 'multipart/form-data' +})) + +const router = new Router() + +router.get('/', async ctx => { + await ctx.render('pictures.html') +}) +router.post('/', ctx => { + try { + console.log('processing the post request') + const body = ctx.request.body + console.log(body.fileUpload) + } catch(err) { + ctx.status = status.UNPROCESSABLE_ENTITY + ctx.body = err.message + } +}) + +app.use(router.routes()) +module.exports = app.listen(port, () => console.log(`listening on port ${port}`)) diff --git a/exercises/07_unit_testing/file_system/jest-test.config.js b/exercises/07_unit_testing/file_system/jest-test.config.js new file mode 100644 index 00000000..a758c709 --- /dev/null +++ b/exercises/07_unit_testing/file_system/jest-test.config.js @@ -0,0 +1,20 @@ + +'use strict'; + +module.exports = { + displayName: 'test', + verbose: true, + collectCoverage: true, + coverageThreshold: { + global: { + branches: 0, + functions: 0, + lines: 0, + statements: 0 + } + }, + testPathIgnorePatterns: [ + '/node_modules/', + '/__tests__/fixtures/', + ] +} diff --git a/exercises/07_unit_testing/file_system/modules/file.js b/exercises/07_unit_testing/file_system/modules/file.js new file mode 100644 index 00000000..7b18a962 --- /dev/null +++ b/exercises/07_unit_testing/file_system/modules/file.js @@ -0,0 +1,25 @@ +'use strict' + +const fs = require('fs') + +module.exports = class File { + constructor() {} + + async savePicture(filename, imageData) { + if (filename === undefined || filename === '') throw new Error(`filename can't be empty`) + if (imageData === undefined || imageData === '') throw new Error(`imageData can't be empty`) + fs.writeFile(filename, imageData, 'binary', (err) => { + if (err) throw new Error(err) + console.log('File saved.') + }) + } + + readPicture(filename) { + if (filename === undefined || filename === '') throw new Error(`filename can't be empty`) + try { + fs.readFileSync(filename, 'binary') + } catch(err) { + throw new Error(`file doesn't exist`) + } + } +} diff --git a/exercises/07_unit_testing/file_system/package-lock.json b/exercises/07_unit_testing/file_system/package-lock.json new file mode 100644 index 00000000..139ea16a --- /dev/null +++ b/exercises/07_unit_testing/file_system/package-lock.json @@ -0,0 +1,5536 @@ +{ + "name": "file_system", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@babel/code-frame": { + "version": "7.5.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz", + "integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==", + "dev": true, + "requires": { + "@babel/highlight": "^7.0.0" + } + }, + "@babel/core": { + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.6.4.tgz", + "integrity": "sha512-Rm0HGw101GY8FTzpWSyRbki/jzq+/PkNQJ+nSulrdY6gFGOsNseCqD6KHRYe2E+EdzuBdr2pxCp6s4Uk6eJ+XQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.5.5", + "@babel/generator": "^7.6.4", + "@babel/helpers": "^7.6.2", + "@babel/parser": "^7.6.4", + "@babel/template": "^7.6.0", + "@babel/traverse": "^7.6.3", + "@babel/types": "^7.6.3", + "convert-source-map": "^1.1.0", + "debug": "^4.1.0", + "json5": "^2.1.0", + "lodash": "^4.17.13", + "resolve": "^1.3.2", + "semver": "^5.4.1", + "source-map": "^0.5.0" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "@babel/generator": { + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.6.4.tgz", + "integrity": "sha512-jsBuXkFoZxk0yWLyGI9llT9oiQ2FeTASmRFE32U+aaDTfoE92t78eroO7PTpU/OrYq38hlcDM6vbfLDaOLy+7w==", + "dev": true, + "requires": { + "@babel/types": "^7.6.3", + "jsesc": "^2.5.1", + "lodash": "^4.17.13", + "source-map": "^0.5.0" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "@babel/helper-function-name": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz", + "integrity": "sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.0.0", + "@babel/template": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz", + "integrity": "sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz", + "integrity": "sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA==", + "dev": true + }, + "@babel/helper-split-export-declaration": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz", + "integrity": "sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q==", + "dev": true, + "requires": { + "@babel/types": "^7.4.4" + } + }, + "@babel/helpers": { + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.6.2.tgz", + "integrity": "sha512-3/bAUL8zZxYs1cdX2ilEE0WobqbCmKWr/889lf2SS0PpDcpEIY8pb1CCyz0pEcX3pEb+MCbks1jIokz2xLtGTA==", + "dev": true, + "requires": { + "@babel/template": "^7.6.0", + "@babel/traverse": "^7.6.2", + "@babel/types": "^7.6.0" + } + }, + "@babel/highlight": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz", + "integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==", + "dev": true, + "requires": { + "chalk": "^2.0.0", + "esutils": "^2.0.2", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.6.4.tgz", + "integrity": "sha512-D8RHPW5qd0Vbyo3qb+YjO5nvUVRTXFLQ/FsDxJU2Nqz4uB5EnUN0ZQSEYpvTIbRuttig1XbHWU5oMeQwQSAA+A==", + "dev": true + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.2.0.tgz", + "integrity": "sha512-t0JKGgqk2We+9may3t0xDdmneaXmyxq0xieYcKHxIsrJO64n1OiMWNUtc5gQK1PA0NpdCRrtZp4z+IUaKugrSA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0" + } + }, + "@babel/template": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.6.0.tgz", + "integrity": "sha512-5AEH2EXD8euCk446b7edmgFdub/qfH1SN6Nii3+fyXP807QRx9Q73A2N5hNwRRslC2H9sNzaFhsPubkS4L8oNQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.6.0", + "@babel/types": "^7.6.0" + } + }, + "@babel/traverse": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.6.3.tgz", + "integrity": "sha512-unn7P4LGsijIxaAJo/wpoU11zN+2IaClkQAxcJWBNCMS6cmVh802IyLHNkAjQ0iYnRS3nnxk5O3fuXW28IMxTw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.5.5", + "@babel/generator": "^7.6.3", + "@babel/helper-function-name": "^7.1.0", + "@babel/helper-split-export-declaration": "^7.4.4", + "@babel/parser": "^7.6.3", + "@babel/types": "^7.6.3", + "debug": "^4.1.0", + "globals": "^11.1.0", + "lodash": "^4.17.13" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "@babel/types": { + "version": "7.6.3", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.6.3.tgz", + "integrity": "sha512-CqbcpTxMcpuQTMhjI37ZHVgjBkysg5icREQIEZ0eG1yCNwg3oy+5AaLiOKmjsCj6nqOsa6Hf0ObjRVwokb7srA==", + "dev": true, + "requires": { + "esutils": "^2.0.2", + "lodash": "^4.17.13", + "to-fast-properties": "^2.0.0" + } + }, + "@cnakazawa/watch": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.3.tgz", + "integrity": "sha512-r5160ogAvGyHsal38Kux7YYtodEKOj89RGb28ht1jh3SJb08VwRwAKKJL0bGb04Zd/3r9FL3BFIc3bBidYffCA==", + "dev": true, + "requires": { + "exec-sh": "^0.3.2", + "minimist": "^1.2.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, + "@jest/console": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-24.9.0.tgz", + "integrity": "sha512-Zuj6b8TnKXi3q4ymac8EQfc3ea/uhLeCGThFqXeC8H9/raaH8ARPUTdId+XyGd03Z4In0/VjD2OYFcBF09fNLQ==", + "dev": true, + "requires": { + "@jest/source-map": "^24.9.0", + "chalk": "^2.0.1", + "slash": "^2.0.0" + } + }, + "@jest/core": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-24.9.0.tgz", + "integrity": "sha512-Fogg3s4wlAr1VX7q+rhV9RVnUv5tD7VuWfYy1+whMiWUrvl7U3QJSJyWcDio9Lq2prqYsZaeTv2Rz24pWGkJ2A==", + "dev": true, + "requires": { + "@jest/console": "^24.7.1", + "@jest/reporters": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/transform": "^24.9.0", + "@jest/types": "^24.9.0", + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.1", + "exit": "^0.1.2", + "graceful-fs": "^4.1.15", + "jest-changed-files": "^24.9.0", + "jest-config": "^24.9.0", + "jest-haste-map": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-regex-util": "^24.3.0", + "jest-resolve": "^24.9.0", + "jest-resolve-dependencies": "^24.9.0", + "jest-runner": "^24.9.0", + "jest-runtime": "^24.9.0", + "jest-snapshot": "^24.9.0", + "jest-util": "^24.9.0", + "jest-validate": "^24.9.0", + "jest-watcher": "^24.9.0", + "micromatch": "^3.1.10", + "p-each-series": "^1.0.0", + "realpath-native": "^1.1.0", + "rimraf": "^2.5.4", + "slash": "^2.0.0", + "strip-ansi": "^5.0.0" + } + }, + "@jest/environment": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-24.9.0.tgz", + "integrity": "sha512-5A1QluTPhvdIPFYnO3sZC3smkNeXPVELz7ikPbhUj0bQjB07EoE9qtLrem14ZUYWdVayYbsjVwIiL4WBIMV4aQ==", + "dev": true, + "requires": { + "@jest/fake-timers": "^24.9.0", + "@jest/transform": "^24.9.0", + "@jest/types": "^24.9.0", + "jest-mock": "^24.9.0" + } + }, + "@jest/fake-timers": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-24.9.0.tgz", + "integrity": "sha512-eWQcNa2YSwzXWIMC5KufBh3oWRIijrQFROsIqt6v/NS9Io/gknw1jsAC9c+ih/RQX4A3O7SeWAhQeN0goKhT9A==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-mock": "^24.9.0" + } + }, + "@jest/reporters": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-24.9.0.tgz", + "integrity": "sha512-mu4X0yjaHrffOsWmVLzitKmmmWSQ3GGuefgNscUSWNiUNcEOSEQk9k3pERKEQVBb0Cnn88+UESIsZEMH3o88Gw==", + "dev": true, + "requires": { + "@jest/environment": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/transform": "^24.9.0", + "@jest/types": "^24.9.0", + "chalk": "^2.0.1", + "exit": "^0.1.2", + "glob": "^7.1.2", + "istanbul-lib-coverage": "^2.0.2", + "istanbul-lib-instrument": "^3.0.1", + "istanbul-lib-report": "^2.0.4", + "istanbul-lib-source-maps": "^3.0.1", + "istanbul-reports": "^2.2.6", + "jest-haste-map": "^24.9.0", + "jest-resolve": "^24.9.0", + "jest-runtime": "^24.9.0", + "jest-util": "^24.9.0", + "jest-worker": "^24.6.0", + "node-notifier": "^5.4.2", + "slash": "^2.0.0", + "source-map": "^0.6.0", + "string-length": "^2.0.0" + } + }, + "@jest/source-map": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-24.9.0.tgz", + "integrity": "sha512-/Xw7xGlsZb4MJzNDgB7PW5crou5JqWiBQaz6xyPd3ArOg2nfn/PunV8+olXbbEZzNl591o5rWKE9BRDaFAuIBg==", + "dev": true, + "requires": { + "callsites": "^3.0.0", + "graceful-fs": "^4.1.15", + "source-map": "^0.6.0" + } + }, + "@jest/test-result": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-24.9.0.tgz", + "integrity": "sha512-XEFrHbBonBJ8dGp2JmF8kP/nQI/ImPpygKHwQ/SY+es59Z3L5PI4Qb9TQQMAEeYsThG1xF0k6tmG0tIKATNiiA==", + "dev": true, + "requires": { + "@jest/console": "^24.9.0", + "@jest/types": "^24.9.0", + "@types/istanbul-lib-coverage": "^2.0.0" + } + }, + "@jest/test-sequencer": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-24.9.0.tgz", + "integrity": "sha512-6qqsU4o0kW1dvA95qfNog8v8gkRN9ph6Lz7r96IvZpHdNipP2cBcb07J1Z45mz/VIS01OHJ3pY8T5fUY38tg4A==", + "dev": true, + "requires": { + "@jest/test-result": "^24.9.0", + "jest-haste-map": "^24.9.0", + "jest-runner": "^24.9.0", + "jest-runtime": "^24.9.0" + } + }, + "@jest/transform": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-24.9.0.tgz", + "integrity": "sha512-TcQUmyNRxV94S0QpMOnZl0++6RMiqpbH/ZMccFB/amku6Uwvyb1cjYX7xkp5nGNkbX4QPH/FcB6q1HBTHynLmQ==", + "dev": true, + "requires": { + "@babel/core": "^7.1.0", + "@jest/types": "^24.9.0", + "babel-plugin-istanbul": "^5.1.0", + "chalk": "^2.0.1", + "convert-source-map": "^1.4.0", + "fast-json-stable-stringify": "^2.0.0", + "graceful-fs": "^4.1.15", + "jest-haste-map": "^24.9.0", + "jest-regex-util": "^24.9.0", + "jest-util": "^24.9.0", + "micromatch": "^3.1.10", + "pirates": "^4.0.1", + "realpath-native": "^1.1.0", + "slash": "^2.0.0", + "source-map": "^0.6.1", + "write-file-atomic": "2.4.1" + } + }, + "@jest/types": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", + "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^1.1.1", + "@types/yargs": "^13.0.0" + } + }, + "@types/babel__core": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.3.tgz", + "integrity": "sha512-8fBo0UR2CcwWxeX7WIIgJ7lXjasFxoYgRnFHUj+hRvKkpiBJbxhdAPTCY6/ZKM0uxANFVzt4yObSLuTiTnazDA==", + "dev": true, + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "@types/babel__generator": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.0.tgz", + "integrity": "sha512-c1mZUu4up5cp9KROs/QAw0gTeHrw/x7m52LcnvMxxOZ03DmLwPV0MlGmlgzV3cnSdjhJOZsj7E7FHeioai+egw==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@types/babel__template": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.0.2.tgz", + "integrity": "sha512-/K6zCpeW7Imzgab2bLkLEbz0+1JlFSrUMdw7KoIIu+IUdu51GWaBZpd3y1VXGVXzynvGa4DaIaxNZHiON3GXUg==", + "dev": true, + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@types/babel__traverse": { + "version": "7.0.7", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.0.7.tgz", + "integrity": "sha512-CeBpmX1J8kWLcDEnI3Cl2Eo6RfbGvzUctA+CjZUhOKDFbLfcr7fc4usEqLNWetrlJd7RhAkyYe2czXop4fICpw==", + "dev": true, + "requires": { + "@babel/types": "^7.3.0" + } + }, + "@types/istanbul-lib-coverage": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz", + "integrity": "sha512-hRJD2ahnnpLgsj6KWMYSrmXkM3rm2Dl1qkx6IOFD5FnuNPXJIG5L0dhgKXCYTRMGzU4n0wImQ/xfmRc4POUFlg==", + "dev": true + }, + "@types/istanbul-lib-report": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-1.1.1.tgz", + "integrity": "sha512-3BUTyMzbZa2DtDI2BkERNC6jJw2Mr2Y0oGI7mRxYNBPxppbtEK1F66u3bKwU2g+wxwWI7PAoRpJnOY1grJqzHg==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "*" + } + }, + "@types/istanbul-reports": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-1.1.1.tgz", + "integrity": "sha512-UpYjBi8xefVChsCoBpKShdxTllC9pwISirfoZsUa2AAdQg/Jd2KQGtSbw+ya7GPo7x/wAPlH6JBhKhAsXUEZNA==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "*", + "@types/istanbul-lib-report": "*" + } + }, + "@types/stack-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz", + "integrity": "sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==", + "dev": true + }, + "@types/yargs": { + "version": "13.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.3.tgz", + "integrity": "sha512-K8/LfZq2duW33XW/tFwEAfnZlqIfVsoyRB3kfXdPXYhl0nfM8mmh7GS0jg7WrX2Dgq/0Ha/pR1PaR+BvmWwjiQ==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "@types/yargs-parser": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-13.1.0.tgz", + "integrity": "sha512-gCubfBUZ6KxzoibJ+SCUc/57Ms1jz5NjHe4+dI2krNmU5zCPAphyLJYyTOg06ueIyfj+SaCUqmzun7ImlxDcKg==", + "dev": true + }, + "abab": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.2.tgz", + "integrity": "sha512-2scffjvioEmNz0OyDSLGWDfKCVwaKc6l9Pm9kOIREU13ClXZvHpg/nRL5xyjSSSLhOnXqft2HpsAzNEEA8cFFg==", + "dev": true + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" + }, + "accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "requires": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + } + }, + "acorn": { + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", + "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==", + "dev": true + }, + "acorn-globals": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.4.tgz", + "integrity": "sha512-clfQEh21R+D0leSbUdWf3OcfqyaCSAQ8Ryq00bofSekfr9W8u1jyYZo6ir0xu9Gtcf7BjcHJpnbZH7JOCpP60A==", + "dev": true, + "requires": { + "acorn": "^6.0.1", + "acorn-walk": "^6.0.1" + }, + "dependencies": { + "acorn": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.3.0.tgz", + "integrity": "sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA==", + "dev": true + } + } + }, + "acorn-walk": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.2.0.tgz", + "integrity": "sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA==", + "dev": true + }, + "ajv": { + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", + "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", + "dev": true, + "requires": { + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-escapes": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", + "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", + "dev": true + }, + "ansi-regex": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", + "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "any-promise": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", + "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=" + }, + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + } + }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "dev": true + }, + "array-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", + "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=", + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "dev": true, + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "dev": true + }, + "astral-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", + "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", + "dev": true + }, + "async-limiter": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", + "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", + "dev": true + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true + }, + "aws4": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", + "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==", + "dev": true + }, + "babel-jest": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-24.9.0.tgz", + "integrity": "sha512-ntuddfyiN+EhMw58PTNL1ph4C9rECiQXjI4nMMBKBaNjXvqLdkXpPRcMSr4iyBrJg/+wz9brFUD6RhOAT6r4Iw==", + "dev": true, + "requires": { + "@jest/transform": "^24.9.0", + "@jest/types": "^24.9.0", + "@types/babel__core": "^7.1.0", + "babel-plugin-istanbul": "^5.1.0", + "babel-preset-jest": "^24.9.0", + "chalk": "^2.4.2", + "slash": "^2.0.0" + } + }, + "babel-plugin-istanbul": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-5.2.0.tgz", + "integrity": "sha512-5LphC0USA8t4i1zCtjbbNb6jJj/9+X6P37Qfirc/70EQ34xKlMW+a1RHGwxGI+SwWpNwZ27HqvzAobeqaXwiZw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "find-up": "^3.0.0", + "istanbul-lib-instrument": "^3.3.0", + "test-exclude": "^5.2.3" + } + }, + "babel-plugin-jest-hoist": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-24.9.0.tgz", + "integrity": "sha512-2EMA2P8Vp7lG0RAzr4HXqtYwacfMErOuv1U3wrvxHX6rD1sV6xS3WXG3r8TRQ2r6w8OhvSdWt+z41hQNwNm3Xw==", + "dev": true, + "requires": { + "@types/babel__traverse": "^7.0.6" + } + }, + "babel-preset-jest": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-24.9.0.tgz", + "integrity": "sha512-izTUuhE4TMfTRPF92fFwD2QfdXaZW08qvWTFCI51V8rW5x00UuPgc3ajRoWofXOuxjfcOM5zzSYsQS3H8KGCAg==", + "dev": true, + "requires": { + "@babel/plugin-syntax-object-rest-spread": "^7.0.0", + "babel-plugin-jest-hoist": "^24.9.0" + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + } + } + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "dev": true, + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "bluebird": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.1.tgz", + "integrity": "sha512-DdmyoGCleJnkbp3nkbxTLJ18rjDsE4yCggEwKNXkeV123sPNfOCYeDoeuOY+F2FrSjO1YXcTU+dsy96KMy+gcg==" + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + } + }, + "browser-process-hrtime": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-0.1.3.tgz", + "integrity": "sha512-bRFnI4NnjO6cnyLmOV/7PVoDEMJChlcfN0z4s1YMBY989/SvlfMI1lgCnkFUs53e9gQF+w7qu7XdllSTiSl8Aw==", + "dev": true + }, + "browser-resolve": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.3.tgz", + "integrity": "sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ==", + "dev": true, + "requires": { + "resolve": "1.1.7" + }, + "dependencies": { + "resolve": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", + "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", + "dev": true + } + } + }, + "bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "requires": { + "node-int64": "^0.4.0" + } + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "bytes": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", + "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" + }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + } + }, + "cache-content-type": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-content-type/-/cache-content-type-1.0.1.tgz", + "integrity": "sha512-IKufZ1o4Ut42YUrZSo8+qnMTrFuKkvyoLXUywKz9GJ5BrhOFGhLdkx9sG4KAnVvbY6kEcSFjLQul+DVmBm2bgA==", + "requires": { + "mime-types": "^2.1.18", + "ylru": "^1.2.0" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "capture-exit": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz", + "integrity": "sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g==", + "dev": true, + "requires": { + "rsvp": "^4.8.4" + } + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "dev": true + }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "requires": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" + }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "dev": true, + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, + "component-emitter": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", + "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "condense-newlines": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/condense-newlines/-/condense-newlines-0.2.1.tgz", + "integrity": "sha1-PemFVTE5R10yUCyDsC9gaE0kxV8=", + "requires": { + "extend-shallow": "^2.0.1", + "is-whitespace": "^0.3.0", + "kind-of": "^3.0.2" + } + }, + "config-chain": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz", + "integrity": "sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA==", + "requires": { + "ini": "^1.3.4", + "proto-list": "~1.2.1" + } + }, + "consolidate": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/consolidate/-/consolidate-0.15.1.tgz", + "integrity": "sha512-DW46nrsMJgy9kqAbPt5rKaCr7uFtpo4mSUvLHIUbJEjm0vo+aY5QLwBUq3FK4tRnJr/X0Psc0C4jf/h+HtXSMw==", + "requires": { + "bluebird": "^3.1.1" + } + }, + "content-disposition": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", + "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", + "requires": { + "safe-buffer": "5.1.2" + } + }, + "content-type": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", + "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" + }, + "convert-source-map": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", + "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "cookiejar": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.2.tgz", + "integrity": "sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA==", + "dev": true + }, + "cookies": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/cookies/-/cookies-0.8.0.tgz", + "integrity": "sha512-8aPsApQfebXnuI+537McwYsDtjVxGm8gTIzQI3FDW6t5t/DAhERxtnbEPN/8RX+uZthoz4eCOgloXaE5cYyNow==", + "requires": { + "depd": "~2.0.0", + "keygrip": "~1.1.0" + }, + "dependencies": { + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" + } + } + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "dev": true + }, + "copy-to": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/copy-to/-/copy-to-2.0.1.tgz", + "integrity": "sha1-JoD7uAaKSNCGVrYJgJK9r8kG9KU=" + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "cross-spawn": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", + "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", + "dev": true, + "requires": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + } + }, + "cssom": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", + "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", + "dev": true + }, + "cssstyle": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.4.0.tgz", + "integrity": "sha512-GBrLZYZ4X4x6/QEoBnIrqb8B/f5l4+8me2dkom/j1Gtbxy0kBv6OGzKuAsGM75bkGwGAFkt56Iwg28S3XTZgSA==", + "dev": true, + "requires": { + "cssom": "0.3.x" + } + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "data-urls": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-1.1.0.tgz", + "integrity": "sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ==", + "dev": true, + "requires": { + "abab": "^2.0.0", + "whatwg-mimetype": "^2.2.0", + "whatwg-url": "^7.0.0" + }, + "dependencies": { + "whatwg-url": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", + "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", + "dev": true, + "requires": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + } + } + }, + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "requires": { + "ms": "2.0.0" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "dev": true + }, + "deep-equal": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", + "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=" + }, + "deep-is": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", + "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", + "dev": true + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + } + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" + }, + "detect-newline": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz", + "integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=", + "dev": true + }, + "diff-sequences": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-24.9.0.tgz", + "integrity": "sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew==", + "dev": true + }, + "domexception": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz", + "integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==", + "dev": true, + "requires": { + "webidl-conversions": "^4.0.2" + } + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "dev": true, + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "editorconfig": { + "version": "0.15.3", + "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.15.3.tgz", + "integrity": "sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g==", + "requires": { + "commander": "^2.19.0", + "lru-cache": "^4.1.5", + "semver": "^5.6.0", + "sigmund": "^1.0.1" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "error-inject": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/error-inject/-/error-inject-1.0.0.tgz", + "integrity": "sha1-4rPZG1Su1nLzCdlQ0VSFD6EdTzc=" + }, + "es-abstract": { + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.16.0.tgz", + "integrity": "sha512-xdQnfykZ9JMEiasTAJZJdMWCQ1Vm00NBw79/AWi7ELfZuuPCSOMDZbT9mkOfSctVtfhb+sAAzrm+j//GjjLHLg==", + "dev": true, + "requires": { + "es-to-primitive": "^1.2.0", + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.0", + "is-callable": "^1.1.4", + "is-regex": "^1.0.4", + "object-inspect": "^1.6.0", + "object-keys": "^1.1.1", + "string.prototype.trimleft": "^2.1.0", + "string.prototype.trimright": "^2.1.0" + } + }, + "es-to-primitive": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", + "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "escodegen": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.12.0.tgz", + "integrity": "sha512-TuA+EhsanGcme5T3R0L80u4t8CpbXQjegRmf7+FPTJrtCTErXFeelblRgHQa1FofEzqYYJmJ/OqjTwREp9qgmg==", + "dev": true, + "requires": { + "esprima": "^3.1.3", + "estraverse": "^4.2.0", + "esutils": "^2.0.2", + "optionator": "^0.8.1", + "source-map": "~0.6.1" + } + }, + "esprima": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", + "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", + "dev": true + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "exec-sh": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.2.tgz", + "integrity": "sha512-9sLAvzhI5nc8TpuQUh4ahMdCrWT00wPWz7j47/emR5+2qEfoZP5zzUXvx+vdx+H6ohhnsYC31iX04QLYJK8zTg==", + "dev": true + }, + "execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "requires": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + } + }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "dev": true + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "expect": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-24.9.0.tgz", + "integrity": "sha512-wvVAx8XIol3Z5m9zvZXiyZOQ+sRJqNTIm6sGjdWlaZIeupQGO3WbYI+15D/AmEwZywL6wtJkbAbJtzkOfBuR0Q==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0", + "ansi-styles": "^3.2.0", + "jest-get-type": "^24.9.0", + "jest-matcher-utils": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-regex-util": "^24.9.0" + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "requires": { + "is-extendable": "^0.1.0" + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + } + } + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true + }, + "fast-deep-equal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, + "fb-watchman": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.0.tgz", + "integrity": "sha1-VOmr99+i8mzZsWNsWIwa/AXeXVg=", + "dev": true, + "requires": { + "bser": "^2.0.0" + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + } + }, + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true + }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "formidable": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.1.tgz", + "integrity": "sha512-Fs9VRguL0gqGHkXS5GQiMCr1VhZBxz0JnJs4JmMp/2jL18Fmbzvv7vOFRU+U8TBkHEE/CX1qDXzJplVULgsLeg==", + "dev": true + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dev": true, + "requires": { + "map-cache": "^0.2.2" + } + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" + }, + "fs": { + "version": "0.0.1-security", + "resolved": "https://registry.npmjs.org/fs/-/fs-0.0.1-security.tgz", + "integrity": "sha1-invTcYa23d84E/I4WLV+yq9eQdQ=" + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "fsevents": { + "version": "1.2.9", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", + "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==", + "dev": true, + "optional": true, + "requires": { + "nan": "^2.12.1", + "node-pre-gyp": "^0.12.0" + }, + "dependencies": { + "abbrev": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "ansi-regex": { + "version": "2.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "aproba": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + }, + "are-we-there-yet": { + "version": "1.1.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "balanced-match": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "brace-expansion": { + "version": "1.1.11", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "chownr": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "code-point-at": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "concat-map": { + "version": "0.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true, + "dev": true, + "optional": true + }, + "core-util-is": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "debug": { + "version": "4.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ms": "^2.1.1" + } + }, + "deep-extend": { + "version": "0.6.0", + "bundled": true, + "dev": true, + "optional": true + }, + "delegates": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "detect-libc": { + "version": "1.0.3", + "bundled": true, + "dev": true, + "optional": true + }, + "fs-minipass": { + "version": "1.2.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "fs.realpath": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "gauge": { + "version": "2.7.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "glob": { + "version": "7.1.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "iconv-lite": { + "version": "0.4.24", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ignore-walk": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "inflight": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "bundled": true, + "dev": true, + "optional": true + }, + "ini": { + "version": "1.3.5", + "bundled": true, + "dev": true, + "optional": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "minimatch": { + "version": "3.0.4", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "bundled": true, + "dev": true, + "optional": true + }, + "minipass": { + "version": "2.3.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.2.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "needle": { + "version": "2.3.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "debug": "^4.1.0", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + } + }, + "node-pre-gyp": { + "version": "0.12.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4" + } + }, + "nopt": { + "version": "4.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, + "npm-bundled": { + "version": "1.0.6", + "bundled": true, + "dev": true, + "optional": true + }, + "npm-packlist": { + "version": "1.4.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" + } + }, + "npmlog": { + "version": "4.1.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "object-assign": { + "version": "4.1.1", + "bundled": true, + "dev": true, + "optional": true + }, + "once": { + "version": "1.4.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "wrappy": "1" + } + }, + "os-homedir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "os-tmpdir": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "osenv": { + "version": "0.1.5", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "process-nextick-args": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "rc": { + "version": "1.2.8", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "readable-stream": { + "version": "2.3.6", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "rimraf": { + "version": "2.6.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "safer-buffer": { + "version": "2.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "sax": { + "version": "1.2.4", + "bundled": true, + "dev": true, + "optional": true + }, + "semver": { + "version": "5.7.0", + "bundled": true, + "dev": true, + "optional": true + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true, + "dev": true, + "optional": true + }, + "signal-exit": { + "version": "3.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "string-width": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "tar": { + "version": "4.4.8", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.3.4", + "minizlib": "^1.1.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.2" + } + }, + "util-deprecate": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "wide-align": { + "version": "1.1.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "wrappy": { + "version": "1.0.2", + "bundled": true, + "dev": true, + "optional": true + }, + "yallist": { + "version": "3.0.3", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-paths": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/get-paths/-/get-paths-0.0.7.tgz", + "integrity": "sha512-0wdJt7C1XKQxuCgouqd+ZvLJ56FQixKoki9MrFaO4EriqzXOiH9gbukaDE1ou08S8Ns3/yDzoBAISNPqj6e6tA==", + "requires": { + "pify": "^4.0.1" + } + }, + "get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "requires": { + "pump": "^3.0.0" + } + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "dev": true + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "glob": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.5.tgz", + "integrity": "sha512-J9dlskqUXK1OeTOYBEn5s8aMukWMwWfs+rPTn/jn50Ux4MNXVhubL1wu/j2t+H4NVI+cXEcCaYellqaPVGXNqQ==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "graceful-fs": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", + "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", + "dev": true + }, + "growly": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", + "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", + "dev": true + }, + "handlebars": { + "version": "4.5.1", + "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.5.1.tgz", + "integrity": "sha512-C29UoFzHe9yM61lOsIlCE5/mQVGrnIOrOq7maQl76L7tYPCgC1og0Ajt6uWnX4ZTxBPnjw+CUvawphwCfJgUnA==", + "dev": true, + "requires": { + "neo-async": "^2.6.0", + "optimist": "^0.6.1", + "source-map": "^0.6.1", + "uglify-js": "^3.1.4" + } + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true + }, + "har-validator": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", + "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", + "dev": true, + "requires": { + "ajv": "^6.5.5", + "har-schema": "^2.0.0" + } + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", + "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", + "dev": true + }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "dev": true, + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "hosted-git-info": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.5.tgz", + "integrity": "sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg==", + "dev": true + }, + "html-encoding-sniffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz", + "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==", + "dev": true, + "requires": { + "whatwg-encoding": "^1.0.1" + } + }, + "http-assert": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/http-assert/-/http-assert-1.4.1.tgz", + "integrity": "sha512-rdw7q6GTlibqVVbXr0CKelfV5iY8G2HqEUkhSk297BMbSpSL8crXC+9rjKoMcZZEsksX30le6f/4ul4E28gegw==", + "requires": { + "deep-equal": "~1.0.1", + "http-errors": "~1.7.2" + } + }, + "http-errors": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz", + "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.1.1", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.0" + } + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "http-status-codes": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/http-status-codes/-/http-status-codes-1.4.0.tgz", + "integrity": "sha512-JrT3ua+WgH8zBD3HEJYbeEgnuQaAnUeRRko/YojPAJjGmIfGD3KPU/asLdsLwKjfxOmQe5nXMQ0pt/7MyapVbQ==" + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "import-local": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", + "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", + "dev": true, + "requires": { + "pkg-dir": "^3.0.0", + "resolve-cwd": "^2.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "inflation": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/inflation/-/inflation-2.0.0.tgz", + "integrity": "sha1-i0F+R8KPklpFEz2RTKH9OJEH8w8=" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ini": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" + }, + "invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "dev": true, + "requires": { + "loose-envify": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "is-callable": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", + "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", + "dev": true + }, + "is-ci": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", + "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", + "dev": true, + "requires": { + "ci-info": "^2.0.0" + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-date-object": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", + "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", + "dev": true + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" + }, + "is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", + "dev": true + }, + "is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true + }, + "is-generator-function": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.7.tgz", + "integrity": "sha512-YZc5EwyO4f2kWCax7oegfuSr9mFz1ZvieNYBEjmukLxgXfBUbxAWGVF7GZf0zidYtoBl3WvC07YK0wT76a+Rtw==" + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "is-regex": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", + "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", + "dev": true, + "requires": { + "has": "^1.0.1" + } + }, + "is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", + "dev": true + }, + "is-symbol": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", + "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", + "dev": true, + "requires": { + "has-symbols": "^1.0.0" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "is-whitespace": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/is-whitespace/-/is-whitespace-0.3.0.tgz", + "integrity": "sha1-Fjnssb4DauxppUy7QBz77XEUq38=" + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true + }, + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "dev": true + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true + }, + "istanbul-lib-coverage": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", + "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", + "dev": true + }, + "istanbul-lib-instrument": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz", + "integrity": "sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA==", + "dev": true, + "requires": { + "@babel/generator": "^7.4.0", + "@babel/parser": "^7.4.3", + "@babel/template": "^7.4.0", + "@babel/traverse": "^7.4.3", + "@babel/types": "^7.4.0", + "istanbul-lib-coverage": "^2.0.5", + "semver": "^6.0.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "istanbul-lib-report": { + "version": "2.0.8", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz", + "integrity": "sha512-fHBeG573EIihhAblwgxrSenp0Dby6tJMFR/HvlerBsrCTD5bkUuoNtn3gVh29ZCS824cGGBPn7Sg7cNk+2xUsQ==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^2.0.5", + "make-dir": "^2.1.0", + "supports-color": "^6.1.0" + }, + "dependencies": { + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "istanbul-lib-source-maps": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz", + "integrity": "sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^2.0.5", + "make-dir": "^2.1.0", + "rimraf": "^2.6.3", + "source-map": "^0.6.1" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "istanbul-reports": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.2.6.tgz", + "integrity": "sha512-SKi4rnMyLBKe0Jy2uUdx28h8oG7ph2PPuQPvIAh31d+Ci+lSiEu4C+h3oBPuJ9+mPKhOyW0M8gY4U5NM1WLeXA==", + "dev": true, + "requires": { + "handlebars": "^4.1.2" + } + }, + "jest": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-24.9.0.tgz", + "integrity": "sha512-YvkBL1Zm7d2B1+h5fHEOdyjCG+sGMz4f8D86/0HiqJ6MB4MnDc8FgP5vdWsGnemOQro7lnYo8UakZ3+5A0jxGw==", + "dev": true, + "requires": { + "import-local": "^2.0.0", + "jest-cli": "^24.9.0" + }, + "dependencies": { + "jest-cli": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-24.9.0.tgz", + "integrity": "sha512-+VLRKyitT3BWoMeSUIHRxV/2g8y9gw91Jh5z2UmXZzkZKpbC08CSehVxgHUwTpy+HwGcns/tqafQDJW7imYvGg==", + "dev": true, + "requires": { + "@jest/core": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "chalk": "^2.0.1", + "exit": "^0.1.2", + "import-local": "^2.0.0", + "is-ci": "^2.0.0", + "jest-config": "^24.9.0", + "jest-util": "^24.9.0", + "jest-validate": "^24.9.0", + "prompts": "^2.0.1", + "realpath-native": "^1.1.0", + "yargs": "^13.3.0" + } + } + } + }, + "jest-changed-files": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-24.9.0.tgz", + "integrity": "sha512-6aTWpe2mHF0DhL28WjdkO8LyGjs3zItPET4bMSeXU6T3ub4FPMw+mcOcbdGXQOAfmLcxofD23/5Bl9Z4AkFwqg==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0", + "execa": "^1.0.0", + "throat": "^4.0.0" + } + }, + "jest-config": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-24.9.0.tgz", + "integrity": "sha512-RATtQJtVYQrp7fvWg6f5y3pEFj9I+H8sWw4aKxnDZ96mob5i5SD6ZEGWgMLXQ4LE8UurrjbdlLWdUeo+28QpfQ==", + "dev": true, + "requires": { + "@babel/core": "^7.1.0", + "@jest/test-sequencer": "^24.9.0", + "@jest/types": "^24.9.0", + "babel-jest": "^24.9.0", + "chalk": "^2.0.1", + "glob": "^7.1.1", + "jest-environment-jsdom": "^24.9.0", + "jest-environment-node": "^24.9.0", + "jest-get-type": "^24.9.0", + "jest-jasmine2": "^24.9.0", + "jest-regex-util": "^24.3.0", + "jest-resolve": "^24.9.0", + "jest-util": "^24.9.0", + "jest-validate": "^24.9.0", + "micromatch": "^3.1.10", + "pretty-format": "^24.9.0", + "realpath-native": "^1.1.0" + } + }, + "jest-diff": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-24.9.0.tgz", + "integrity": "sha512-qMfrTs8AdJE2iqrTp0hzh7kTd2PQWrsFyj9tORoKmu32xjPjeE4NyjVRDz8ybYwqS2ik8N4hsIpiVTyFeo2lBQ==", + "dev": true, + "requires": { + "chalk": "^2.0.1", + "diff-sequences": "^24.9.0", + "jest-get-type": "^24.9.0", + "pretty-format": "^24.9.0" + } + }, + "jest-docblock": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-24.9.0.tgz", + "integrity": "sha512-F1DjdpDMJMA1cN6He0FNYNZlo3yYmOtRUnktrT9Q37njYzC5WEaDdmbynIgy0L/IvXvvgsG8OsqhLPXTpfmZAA==", + "dev": true, + "requires": { + "detect-newline": "^2.1.0" + } + }, + "jest-each": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-24.9.0.tgz", + "integrity": "sha512-ONi0R4BvW45cw8s2Lrx8YgbeXL1oCQ/wIDwmsM3CqM/nlblNCPmnC3IPQlMbRFZu3wKdQ2U8BqM6lh3LJ5Bsog==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0", + "chalk": "^2.0.1", + "jest-get-type": "^24.9.0", + "jest-util": "^24.9.0", + "pretty-format": "^24.9.0" + } + }, + "jest-environment-jsdom": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-24.9.0.tgz", + "integrity": "sha512-Zv9FV9NBRzLuALXjvRijO2351DRQeLYXtpD4xNvfoVFw21IOKNhZAEUKcbiEtjTkm2GsJ3boMVgkaR7rN8qetA==", + "dev": true, + "requires": { + "@jest/environment": "^24.9.0", + "@jest/fake-timers": "^24.9.0", + "@jest/types": "^24.9.0", + "jest-mock": "^24.9.0", + "jest-util": "^24.9.0", + "jsdom": "^11.5.1" + } + }, + "jest-environment-node": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-24.9.0.tgz", + "integrity": "sha512-6d4V2f4nxzIzwendo27Tr0aFm+IXWa0XEUnaH6nU0FMaozxovt+sfRvh4J47wL1OvF83I3SSTu0XK+i4Bqe7uA==", + "dev": true, + "requires": { + "@jest/environment": "^24.9.0", + "@jest/fake-timers": "^24.9.0", + "@jest/types": "^24.9.0", + "jest-mock": "^24.9.0", + "jest-util": "^24.9.0" + } + }, + "jest-get-type": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-24.9.0.tgz", + "integrity": "sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q==", + "dev": true + }, + "jest-haste-map": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-24.9.0.tgz", + "integrity": "sha512-kfVFmsuWui2Sj1Rp1AJ4D9HqJwE4uwTlS/vO+eRUaMmd54BFpli2XhMQnPC2k4cHFVbB2Q2C+jtI1AGLgEnCjQ==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0", + "anymatch": "^2.0.0", + "fb-watchman": "^2.0.0", + "fsevents": "^1.2.7", + "graceful-fs": "^4.1.15", + "invariant": "^2.2.4", + "jest-serializer": "^24.9.0", + "jest-util": "^24.9.0", + "jest-worker": "^24.9.0", + "micromatch": "^3.1.10", + "sane": "^4.0.3", + "walker": "^1.0.7" + } + }, + "jest-jasmine2": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-24.9.0.tgz", + "integrity": "sha512-Cq7vkAgaYKp+PsX+2/JbTarrk0DmNhsEtqBXNwUHkdlbrTBLtMJINADf2mf5FkowNsq8evbPc07/qFO0AdKTzw==", + "dev": true, + "requires": { + "@babel/traverse": "^7.1.0", + "@jest/environment": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "chalk": "^2.0.1", + "co": "^4.6.0", + "expect": "^24.9.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^24.9.0", + "jest-matcher-utils": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-runtime": "^24.9.0", + "jest-snapshot": "^24.9.0", + "jest-util": "^24.9.0", + "pretty-format": "^24.9.0", + "throat": "^4.0.0" + } + }, + "jest-leak-detector": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-24.9.0.tgz", + "integrity": "sha512-tYkFIDsiKTGwb2FG1w8hX9V0aUb2ot8zY/2nFg087dUageonw1zrLMP4W6zsRO59dPkTSKie+D4rhMuP9nRmrA==", + "dev": true, + "requires": { + "jest-get-type": "^24.9.0", + "pretty-format": "^24.9.0" + } + }, + "jest-matcher-utils": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-24.9.0.tgz", + "integrity": "sha512-OZz2IXsu6eaiMAwe67c1T+5tUAtQyQx27/EMEkbFAGiw52tB9em+uGbzpcgYVpA8wl0hlxKPZxrly4CXU/GjHA==", + "dev": true, + "requires": { + "chalk": "^2.0.1", + "jest-diff": "^24.9.0", + "jest-get-type": "^24.9.0", + "pretty-format": "^24.9.0" + } + }, + "jest-message-util": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-24.9.0.tgz", + "integrity": "sha512-oCj8FiZ3U0hTP4aSui87P4L4jC37BtQwUMqk+zk/b11FR19BJDeZsZAvIHutWnmtw7r85UmR3CEWZ0HWU2mAlw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "@types/stack-utils": "^1.0.1", + "chalk": "^2.0.1", + "micromatch": "^3.1.10", + "slash": "^2.0.0", + "stack-utils": "^1.0.1" + } + }, + "jest-mock": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-24.9.0.tgz", + "integrity": "sha512-3BEYN5WbSq9wd+SyLDES7AHnjH9A/ROBwmz7l2y+ol+NtSFO8DYiEBzoO1CeFc9a8DYy10EO4dDFVv/wN3zl1w==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0" + } + }, + "jest-pnp-resolver": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.1.tgz", + "integrity": "sha512-pgFw2tm54fzgYvc/OHrnysABEObZCUNFnhjoRjaVOCN8NYc032/gVjPaHD4Aq6ApkSieWtfKAFQtmDKAmhupnQ==", + "dev": true + }, + "jest-regex-util": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-24.9.0.tgz", + "integrity": "sha512-05Cmb6CuxaA+Ys6fjr3PhvV3bGQmO+2p2La4hFbU+W5uOc479f7FdLXUWXw4pYMAhhSZIuKHwSXSu6CsSBAXQA==", + "dev": true + }, + "jest-resolve": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-24.9.0.tgz", + "integrity": "sha512-TaLeLVL1l08YFZAt3zaPtjiVvyy4oSA6CRe+0AFPPVX3Q/VI0giIWWoAvoS5L96vj9Dqxj4fB5p2qrHCmTU/MQ==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0", + "browser-resolve": "^1.11.3", + "chalk": "^2.0.1", + "jest-pnp-resolver": "^1.2.1", + "realpath-native": "^1.1.0" + } + }, + "jest-resolve-dependencies": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-24.9.0.tgz", + "integrity": "sha512-Fm7b6AlWnYhT0BXy4hXpactHIqER7erNgIsIozDXWl5dVm+k8XdGVe1oTg1JyaFnOxarMEbax3wyRJqGP2Pq+g==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0", + "jest-regex-util": "^24.3.0", + "jest-snapshot": "^24.9.0" + } + }, + "jest-runner": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-24.9.0.tgz", + "integrity": "sha512-KksJQyI3/0mhcfspnxxEOBueGrd5E4vV7ADQLT9ESaCzz02WnbdbKWIf5Mkaucoaj7obQckYPVX6JJhgUcoWWg==", + "dev": true, + "requires": { + "@jest/console": "^24.7.1", + "@jest/environment": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "chalk": "^2.4.2", + "exit": "^0.1.2", + "graceful-fs": "^4.1.15", + "jest-config": "^24.9.0", + "jest-docblock": "^24.3.0", + "jest-haste-map": "^24.9.0", + "jest-jasmine2": "^24.9.0", + "jest-leak-detector": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-resolve": "^24.9.0", + "jest-runtime": "^24.9.0", + "jest-util": "^24.9.0", + "jest-worker": "^24.6.0", + "source-map-support": "^0.5.6", + "throat": "^4.0.0" + } + }, + "jest-runtime": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-24.9.0.tgz", + "integrity": "sha512-8oNqgnmF3v2J6PVRM2Jfuj8oX3syKmaynlDMMKQ4iyzbQzIG6th5ub/lM2bCMTmoTKM3ykcUYI2Pw9xwNtjMnw==", + "dev": true, + "requires": { + "@jest/console": "^24.7.1", + "@jest/environment": "^24.9.0", + "@jest/source-map": "^24.3.0", + "@jest/transform": "^24.9.0", + "@jest/types": "^24.9.0", + "@types/yargs": "^13.0.0", + "chalk": "^2.0.1", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.1.15", + "jest-config": "^24.9.0", + "jest-haste-map": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-mock": "^24.9.0", + "jest-regex-util": "^24.3.0", + "jest-resolve": "^24.9.0", + "jest-snapshot": "^24.9.0", + "jest-util": "^24.9.0", + "jest-validate": "^24.9.0", + "realpath-native": "^1.1.0", + "slash": "^2.0.0", + "strip-bom": "^3.0.0", + "yargs": "^13.3.0" + } + }, + "jest-serializer": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-24.9.0.tgz", + "integrity": "sha512-DxYipDr8OvfrKH3Kel6NdED3OXxjvxXZ1uIY2I9OFbGg+vUkkg7AGvi65qbhbWNPvDckXmzMPbK3u3HaDO49bQ==", + "dev": true + }, + "jest-snapshot": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-24.9.0.tgz", + "integrity": "sha512-uI/rszGSs73xCM0l+up7O7a40o90cnrk429LOiK3aeTvfC0HHmldbd81/B7Ix81KSFe1lwkbl7GnBGG4UfuDew==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0", + "@jest/types": "^24.9.0", + "chalk": "^2.0.1", + "expect": "^24.9.0", + "jest-diff": "^24.9.0", + "jest-get-type": "^24.9.0", + "jest-matcher-utils": "^24.9.0", + "jest-message-util": "^24.9.0", + "jest-resolve": "^24.9.0", + "mkdirp": "^0.5.1", + "natural-compare": "^1.4.0", + "pretty-format": "^24.9.0", + "semver": "^6.2.0" + }, + "dependencies": { + "semver": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", + "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", + "dev": true + } + } + }, + "jest-util": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-24.9.0.tgz", + "integrity": "sha512-x+cZU8VRmOJxbA1K5oDBdxQmdq0OIdADarLxk0Mq+3XS4jgvhG/oKGWcIDCtPG0HgjxOYvF+ilPJQsAyXfbNOg==", + "dev": true, + "requires": { + "@jest/console": "^24.9.0", + "@jest/fake-timers": "^24.9.0", + "@jest/source-map": "^24.9.0", + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "callsites": "^3.0.0", + "chalk": "^2.0.1", + "graceful-fs": "^4.1.15", + "is-ci": "^2.0.0", + "mkdirp": "^0.5.1", + "slash": "^2.0.0", + "source-map": "^0.6.0" + } + }, + "jest-validate": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-24.9.0.tgz", + "integrity": "sha512-HPIt6C5ACwiqSiwi+OfSSHbK8sG7akG8eATl+IPKaeIjtPOeBUd/g3J7DghugzxrGjI93qS/+RPKe1H6PqvhRQ==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0", + "camelcase": "^5.3.1", + "chalk": "^2.0.1", + "jest-get-type": "^24.9.0", + "leven": "^3.1.0", + "pretty-format": "^24.9.0" + } + }, + "jest-watcher": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-24.9.0.tgz", + "integrity": "sha512-+/fLOfKPXXYJDYlks62/4R4GoT+GU1tYZed99JSCOsmzkkF7727RqKrjNAxtfO4YpGv11wybgRvCjR73lK2GZw==", + "dev": true, + "requires": { + "@jest/test-result": "^24.9.0", + "@jest/types": "^24.9.0", + "@types/yargs": "^13.0.0", + "ansi-escapes": "^3.0.0", + "chalk": "^2.0.1", + "jest-util": "^24.9.0", + "string-length": "^2.0.0" + } + }, + "jest-worker": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.9.0.tgz", + "integrity": "sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw==", + "dev": true, + "requires": { + "merge-stream": "^2.0.0", + "supports-color": "^6.1.0" + }, + "dependencies": { + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "js-beautify": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.10.2.tgz", + "integrity": "sha512-ZtBYyNUYJIsBWERnQP0rPN9KjkrDfJcMjuVGcvXOUJrD1zmOGwhRwQ4msG+HJ+Ni/FA7+sRQEMYVzdTQDvnzvQ==", + "requires": { + "config-chain": "^1.1.12", + "editorconfig": "^0.15.3", + "glob": "^7.1.3", + "mkdirp": "~0.5.1", + "nopt": "~4.0.1" + } + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true + }, + "jsdom": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-11.12.0.tgz", + "integrity": "sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw==", + "dev": true, + "requires": { + "abab": "^2.0.0", + "acorn": "^5.5.3", + "acorn-globals": "^4.1.0", + "array-equal": "^1.0.0", + "cssom": ">= 0.3.2 < 0.4.0", + "cssstyle": "^1.0.0", + "data-urls": "^1.0.0", + "domexception": "^1.0.1", + "escodegen": "^1.9.1", + "html-encoding-sniffer": "^1.0.2", + "left-pad": "^1.3.0", + "nwsapi": "^2.0.7", + "parse5": "4.0.0", + "pn": "^1.1.0", + "request": "^2.87.0", + "request-promise-native": "^1.0.5", + "sax": "^1.2.4", + "symbol-tree": "^3.2.2", + "tough-cookie": "^2.3.4", + "w3c-hr-time": "^1.0.1", + "webidl-conversions": "^4.0.2", + "whatwg-encoding": "^1.0.3", + "whatwg-mimetype": "^2.1.0", + "whatwg-url": "^6.4.1", + "ws": "^5.2.0", + "xml-name-validator": "^3.0.0" + } + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true + }, + "json5": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.1.tgz", + "integrity": "sha512-l+3HXD0GEI3huGq1njuqtzYK8OYJyXMkOLtQ53pjWh89tvWS2h6l+1zMkYWqlb57+SiQodKZyvMEFb2X+KrFhQ==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "keygrip": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/keygrip/-/keygrip-1.1.0.tgz", + "integrity": "sha512-iYSchDJ+liQ8iwbSI2QqsQOvqv58eJCEanyJPJi+Khyu8smkcKSFUCbPwzFcL7YVtZ6eONjqRX/38caJ7QjRAQ==", + "requires": { + "tsscmp": "1.0.6" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "requires": { + "is-buffer": "^1.1.5" + } + }, + "kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true + }, + "koa": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/koa/-/koa-2.11.0.tgz", + "integrity": "sha512-EpR9dElBTDlaDgyhDMiLkXrPwp6ZqgAIBvhhmxQ9XN4TFgW+gEz6tkcsNI6BnUbUftrKDjVFj4lW2/J2aNBMMA==", + "requires": { + "accepts": "^1.3.5", + "cache-content-type": "^1.0.0", + "content-disposition": "~0.5.2", + "content-type": "^1.0.4", + "cookies": "~0.8.0", + "debug": "~3.1.0", + "delegates": "^1.0.0", + "depd": "^1.1.2", + "destroy": "^1.0.4", + "encodeurl": "^1.0.2", + "error-inject": "^1.0.0", + "escape-html": "^1.0.3", + "fresh": "~0.5.2", + "http-assert": "^1.3.0", + "http-errors": "^1.6.3", + "is-generator-function": "^1.0.7", + "koa-compose": "^4.1.0", + "koa-convert": "^1.2.0", + "on-finished": "^2.3.0", + "only": "~0.0.2", + "parseurl": "^1.3.2", + "statuses": "^1.5.0", + "type-is": "^1.6.16", + "vary": "^1.1.2" + } + }, + "koa-bodyparser": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/koa-bodyparser/-/koa-bodyparser-4.2.1.tgz", + "integrity": "sha512-UIjPAlMZfNYDDe+4zBaOAUKYqkwAGcIU6r2ARf1UOXPAlfennQys5IiShaVeNf7KkVBlf88f2LeLvBFvKylttw==", + "requires": { + "co-body": "^6.0.0", + "copy-to": "^2.0.1" + }, + "dependencies": { + "co-body": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/co-body/-/co-body-6.0.0.tgz", + "integrity": "sha512-9ZIcixguuuKIptnY8yemEOuhb71L/lLf+Rl5JfJEUiDNJk0e02MBt7BPxR2GEh5mw8dPthQYR4jPI/BnS1MQgw==", + "requires": { + "inflation": "^2.0.0", + "qs": "^6.5.2", + "raw-body": "^2.3.3", + "type-is": "^1.6.16" + } + } + } + }, + "koa-compose": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/koa-compose/-/koa-compose-4.1.0.tgz", + "integrity": "sha512-8ODW8TrDuMYvXRwra/Kh7/rJo9BtOfPc6qO8eAfC80CnCvSjSl0bkRM24X6/XBBEyj0v1nRUQ1LyOy3dbqOWXw==" + }, + "koa-convert": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/koa-convert/-/koa-convert-1.2.0.tgz", + "integrity": "sha1-2kCHXfSd4FOQmNFwC1CCDOvNIdA=", + "requires": { + "co": "^4.6.0", + "koa-compose": "^3.0.0" + }, + "dependencies": { + "koa-compose": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/koa-compose/-/koa-compose-3.2.1.tgz", + "integrity": "sha1-qFzLQLfZhtjlo0Wzoazo6rz1Tec=", + "requires": { + "any-promise": "^1.1.0" + } + } + } + }, + "koa-router": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/koa-router/-/koa-router-7.4.0.tgz", + "integrity": "sha512-IWhaDXeAnfDBEpWS6hkGdZ1ablgr6Q6pGdXCyK38RbzuH4LkUOpPqPw+3f8l8aTDrQmBQ7xJc0bs2yV4dzcO+g==", + "requires": { + "debug": "^3.1.0", + "http-errors": "^1.3.1", + "koa-compose": "^3.0.0", + "methods": "^1.0.1", + "path-to-regexp": "^1.1.1", + "urijs": "^1.19.0" + }, + "dependencies": { + "koa-compose": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/koa-compose/-/koa-compose-3.2.1.tgz", + "integrity": "sha1-qFzLQLfZhtjlo0Wzoazo6rz1Tec=", + "requires": { + "any-promise": "^1.1.0" + } + } + } + }, + "koa-send": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/koa-send/-/koa-send-5.0.0.tgz", + "integrity": "sha512-90ZotV7t0p3uN9sRwW2D484rAaKIsD8tAVtypw/aBU+ryfV+fR2xrcAwhI8Wl6WRkojLUs/cB9SBSCuIb+IanQ==", + "requires": { + "debug": "^3.1.0", + "http-errors": "^1.6.3", + "mz": "^2.7.0", + "resolve-path": "^1.4.0" + } + }, + "koa-views": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/koa-views/-/koa-views-6.2.1.tgz", + "integrity": "sha512-wU3tw48KuskaJg0x1JZmC73UWGgVmh6B54HuHDzTrkavig+dBI0NbFeGiWsaOCZREQkaTfIVXSPSByDant71ew==", + "requires": { + "consolidate": "0.15.1", + "debug": "^4.1.0", + "get-paths": "0.0.7", + "koa-send": "^5.0.0", + "mz": "^2.4.0", + "pretty": "^2.0.0" + }, + "dependencies": { + "debug": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", + "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + } + } + }, + "left-pad": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz", + "integrity": "sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA==", + "dev": true + }, + "leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true + }, + "levn": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", + "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2" + } + }, + "load-json-file": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + } + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + }, + "lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", + "dev": true + }, + "loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "dev": true, + "requires": { + "js-tokens": "^3.0.0 || ^4.0.0" + } + }, + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + } + }, + "makeerror": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", + "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=", + "dev": true, + "requires": { + "tmpl": "1.0.x" + } + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "dev": true + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "dev": true, + "requires": { + "object-visit": "^1.0.0" + } + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + }, + "dependencies": { + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + } + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "dev": true + }, + "mime-db": { + "version": "1.40.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", + "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==" + }, + "mime-types": { + "version": "2.1.24", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", + "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", + "requires": { + "mime-db": "1.40.0" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" + }, + "mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "dev": true, + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "requires": { + "minimist": "0.0.8" + } + }, + "mock-fs": { + "version": "4.10.3", + "resolved": "https://registry.npmjs.org/mock-fs/-/mock-fs-4.10.3.tgz", + "integrity": "sha512-bcukePBvuA3qovmq0Qtqu9+1APCIGkFHnsozrPIVromt5XFGGgkQSfaN0H6RI8gStHkO/hRgimvS3tooNes4pQ==", + "dev": true + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "requires": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "nan": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", + "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", + "dev": true, + "optional": true + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + } + } + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, + "negotiator": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", + "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" + }, + "neo-async": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", + "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==", + "dev": true + }, + "nice-try": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", + "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", + "dev": true + }, + "node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", + "dev": true + }, + "node-modules-regexp": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz", + "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=", + "dev": true + }, + "node-notifier": { + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.4.3.tgz", + "integrity": "sha512-M4UBGcs4jeOK9CjTsYwkvH6/MzuUmGCyTW+kCY7uO+1ZVr0+FHGdPdIf5CCLqAaxnRrWidyoQlNkMIIVwbKB8Q==", + "dev": true, + "requires": { + "growly": "^1.3.0", + "is-wsl": "^1.1.0", + "semver": "^5.5.0", + "shellwords": "^0.1.1", + "which": "^1.3.0" + } + }, + "nopt": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", + "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + }, + "npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", + "dev": true, + "requires": { + "path-key": "^2.0.0" + } + }, + "nwsapi": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", + "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", + "dev": true + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dev": true, + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "object-inspect": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.6.0.tgz", + "integrity": "sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ==", + "dev": true + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dev": true, + "requires": { + "isobject": "^3.0.0" + } + }, + "object.getownpropertydescriptors": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", + "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "es-abstract": "^1.5.1" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "requires": { + "ee-first": "1.1.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "only": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/only/-/only-0.0.2.tgz", + "integrity": "sha1-Kv3oTQPlC5qO3EROMGEKcCle37Q=" + }, + "optimist": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", + "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", + "dev": true, + "requires": { + "minimist": "~0.0.1", + "wordwrap": "~0.0.2" + } + }, + "optionator": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", + "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", + "dev": true, + "requires": { + "deep-is": "~0.1.3", + "fast-levenshtein": "~2.0.4", + "levn": "~0.3.0", + "prelude-ls": "~1.1.2", + "type-check": "~0.3.2", + "wordwrap": "~1.0.0" + }, + "dependencies": { + "wordwrap": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", + "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", + "dev": true + } + } + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" + }, + "osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "p-each-series": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-1.0.0.tgz", + "integrity": "sha1-kw89Et0fUOdDRFeiLNbwSsatf3E=", + "dev": true, + "requires": { + "p-reduce": "^1.0.0" + } + }, + "p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", + "dev": true + }, + "p-limit": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", + "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-reduce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-1.0.0.tgz", + "integrity": "sha1-GMKw3ZNqRpClKfgjH1ig/bakffo=", + "dev": true + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "parse-json": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", + "dev": true, + "requires": { + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" + } + }, + "parse5": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz", + "integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==", + "dev": true + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "dev": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", + "dev": true + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "path-to-regexp": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz", + "integrity": "sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=", + "requires": { + "isarray": "0.0.1" + } + }, + "path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "requires": { + "pify": "^3.0.0" + }, + "dependencies": { + "pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", + "dev": true + } + } + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==" + }, + "pirates": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz", + "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==", + "dev": true, + "requires": { + "node-modules-regexp": "^1.0.0" + } + }, + "pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "requires": { + "find-up": "^3.0.0" + } + }, + "pn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz", + "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==", + "dev": true + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "dev": true + }, + "prelude-ls": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", + "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", + "dev": true + }, + "pretty": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pretty/-/pretty-2.0.0.tgz", + "integrity": "sha1-rbx5YLe7/iiaVX3F9zdhmiINBqU=", + "requires": { + "condense-newlines": "^0.2.1", + "extend-shallow": "^2.0.1", + "js-beautify": "^1.6.12" + } + }, + "pretty-format": { + "version": "24.9.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.9.0.tgz", + "integrity": "sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA==", + "dev": true, + "requires": { + "@jest/types": "^24.9.0", + "ansi-regex": "^4.0.0", + "ansi-styles": "^3.2.0", + "react-is": "^16.8.4" + } + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "prompts": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.2.1.tgz", + "integrity": "sha512-VObPvJiWPhpZI6C5m60XOzTfnYg/xc/an+r9VYymj9WJW3B/DIH+REzjpAACPf8brwPeP+7vz3bIim3S+AaMjw==", + "dev": true, + "requires": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.3" + } + }, + "proto-list": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", + "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=" + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" + }, + "psl": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.4.0.tgz", + "integrity": "sha512-HZzqCGPecFLyoRj5HLfuDSKYTJkAfB5thKBIkRHtGjWwY7p1dAyveIbXIq4tO0KYfDF2tHqPUgY9SDnGm00uFw==", + "dev": true + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "qs": { + "version": "6.9.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.0.tgz", + "integrity": "sha512-27RP4UotQORTpmNQDX8BHPukOnBP3p1uUJY5UnDhaJB+rMt9iMsok724XL+UHU23bEFOHRMQ2ZhI99qOWUMGFA==" + }, + "raw-body": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.1.tgz", + "integrity": "sha512-9WmIKF6mkvA0SLmA2Knm9+qj89e+j1zqgyn8aXGd7+nAduPoqgI9lO57SAZNn/Byzo5P7JhXTyg9PzaJbH73bA==", + "requires": { + "bytes": "3.1.0", + "http-errors": "1.7.3", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "react-is": { + "version": "16.11.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.11.0.tgz", + "integrity": "sha512-gbBVYR2p8mnriqAwWx9LbuUrShnAuSCNnuPGyc7GJrMVQtPDAh8iLpv7FRuMPFb56KkaVZIYSz1PrjI9q0QPCw==", + "dev": true + }, + "read-pkg": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", + "dev": true, + "requires": { + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" + } + }, + "read-pkg-up": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz", + "integrity": "sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==", + "dev": true, + "requires": { + "find-up": "^3.0.0", + "read-pkg": "^3.0.0" + } + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + } + } + }, + "realpath-native": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/realpath-native/-/realpath-native-1.1.0.tgz", + "integrity": "sha512-wlgPA6cCIIg9gKz0fgAPjnzh4yR/LnXovwuo9hvyGvx3h8nX4+/iLZplfUWasXpqD8BdnGnP5njOFjkUwPzvjA==", + "dev": true, + "requires": { + "util.promisify": "^1.0.0" + } + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true + }, + "repeat-element": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", + "dev": true + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true + }, + "request": { + "version": "2.88.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", + "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", + "dev": true, + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.0", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.4.3", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "dev": true + }, + "tough-cookie": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", + "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", + "dev": true, + "requires": { + "psl": "^1.1.24", + "punycode": "^1.4.1" + } + } + } + }, + "request-promise-core": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.3.tgz", + "integrity": "sha512-QIs2+ArIGQVp5ZYbWD5ZLCY29D5CfWizP8eWnm8FoGD1TX61veauETVQbrV60662V0oFBkrDOuaBI8XgtuyYAQ==", + "dev": true, + "requires": { + "lodash": "^4.17.15" + } + }, + "request-promise-native": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.8.tgz", + "integrity": "sha512-dapwLGqkHtwL5AEbfenuzjTYg35Jd6KPytsC2/TLkVMz8rm+tNt72MGUWT1RP/aYawMpN6HqbNGBQaRcBtjQMQ==", + "dev": true, + "requires": { + "request-promise-core": "1.1.3", + "stealthy-require": "^1.1.1", + "tough-cookie": "^2.3.3" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "dev": true + }, + "resolve": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", + "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, + "resolve-cwd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", + "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", + "dev": true, + "requires": { + "resolve-from": "^3.0.0" + } + }, + "resolve-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", + "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", + "dev": true + }, + "resolve-path": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/resolve-path/-/resolve-path-1.4.0.tgz", + "integrity": "sha1-xL2p9e+y/OZSR4c6s2u02DT+Fvc=", + "requires": { + "http-errors": "~1.6.2", + "path-is-absolute": "1.0.1" + }, + "dependencies": { + "http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + } + } + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "dev": true + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "rsvp": { + "version": "4.8.5", + "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz", + "integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==", + "dev": true + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "requires": { + "ret": "~0.1.10" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "sane": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/sane/-/sane-4.1.0.tgz", + "integrity": "sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA==", + "dev": true, + "requires": { + "@cnakazawa/watch": "^1.0.3", + "anymatch": "^2.0.0", + "capture-exit": "^2.0.0", + "exec-sh": "^0.3.2", + "execa": "^1.0.0", + "fb-watchman": "^2.0.0", + "micromatch": "^3.1.4", + "minimist": "^1.1.1", + "walker": "~1.0.5" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + } + } + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + } + }, + "setprototypeof": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", + "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" + }, + "shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", + "dev": true, + "requires": { + "shebang-regex": "^1.0.0" + } + }, + "shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", + "dev": true + }, + "shellwords": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", + "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", + "dev": true + }, + "sigmund": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", + "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=" + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true + }, + "sisteransi": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.3.tgz", + "integrity": "sha512-SbEG75TzH8G7eVXFSN5f9EExILKfly7SUvVY5DhhYLvfhKqhDFY0OzevWa/zwak0RLRfWS5AvfMWpd9gJvr5Yg==", + "dev": true + }, + "slash": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", + "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", + "dev": true + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dev": true, + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dev": true, + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "kind-of": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", + "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", + "dev": true + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dev": true, + "requires": { + "kind-of": "^3.2.0" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-resolve": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", + "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", + "dev": true, + "requires": { + "atob": "^2.1.1", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "source-map-support": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.16.tgz", + "integrity": "sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "source-map-url": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", + "dev": true + }, + "spdx-correct": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", + "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", + "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", + "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", + "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", + "dev": true + }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.0" + }, + "dependencies": { + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "dev": true, + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "stack-utils": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.2.tgz", + "integrity": "sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA==", + "dev": true + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "dev": true, + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + }, + "stealthy-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", + "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", + "dev": true + }, + "string-length": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-2.0.0.tgz", + "integrity": "sha1-1A27aGo6zpYMHP/KVivyxF+DY+0=", + "dev": true, + "requires": { + "astral-regex": "^1.0.0", + "strip-ansi": "^4.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "requires": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + } + }, + "string.prototype.trimleft": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz", + "integrity": "sha512-FJ6b7EgdKxxbDxc79cOlok6Afd++TTs5szo+zJTUyow3ycrRfJVE2pq3vcN53XexvKZu/DJMDfeI/qMiZTrjTw==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } + }, + "string.prototype.trimright": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.0.tgz", + "integrity": "sha512-fXZTSV55dNBwv16uw+hh5jkghxSnc5oHq+5K/gXgizHwAvMetdAJlHqqoFC1FSDVPYWLkAKl2cxpUT41sV7nSg==", + "dev": true, + "requires": { + "define-properties": "^1.1.3", + "function-bind": "^1.1.1" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "requires": { + "ansi-regex": "^4.1.0" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, + "strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", + "dev": true + }, + "superagent": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/superagent/-/superagent-3.8.3.tgz", + "integrity": "sha512-GLQtLMCoEIK4eDv6OGtkOoSMt3D+oq0y3dsxMuYuDvaNUvuT8eFBuLmfR0iYYzHC1e8hpzC6ZsxbuP6DIalMFA==", + "dev": true, + "requires": { + "component-emitter": "^1.2.0", + "cookiejar": "^2.1.0", + "debug": "^3.1.0", + "extend": "^3.0.0", + "form-data": "^2.3.1", + "formidable": "^1.2.0", + "methods": "^1.1.1", + "mime": "^1.4.1", + "qs": "^6.5.1", + "readable-stream": "^2.3.5" + } + }, + "supertest": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/supertest/-/supertest-4.0.2.tgz", + "integrity": "sha512-1BAbvrOZsGA3YTCWqbmh14L0YEq0EGICX/nBnfkfVJn7SrxQV1I3pMYjSzG9y/7ZU2V9dWqyqk2POwxlb09duQ==", + "dev": true, + "requires": { + "methods": "^1.1.2", + "superagent": "^3.8.3" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true + }, + "test-exclude": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.2.3.tgz", + "integrity": "sha512-M+oxtseCFO3EDtAaGH7iiej3CBkzXqFMbzqYAACdzKui4eZA+pq3tZEwChvOdNfa7xxy8BfbmgJSIr43cC/+2g==", + "dev": true, + "requires": { + "glob": "^7.1.3", + "minimatch": "^3.0.4", + "read-pkg-up": "^4.0.0", + "require-main-filename": "^2.0.0" + } + }, + "thenify": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.0.tgz", + "integrity": "sha1-5p44obq+lpsBCCB5eLn2K4hgSDk=", + "requires": { + "any-promise": "^1.0.0" + } + }, + "thenify-all": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", + "integrity": "sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY=", + "requires": { + "thenify": ">= 3.1.0 < 4" + } + }, + "throat": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/throat/-/throat-4.1.0.tgz", + "integrity": "sha1-iQN8vJLFarGJJua6TLsgDhVnKmo=", + "dev": true + }, + "tmpl": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz", + "integrity": "sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=", + "dev": true + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", + "dev": true + }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + }, + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, + "toidentifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", + "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" + }, + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dev": true, + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + }, + "tr46": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", + "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "tsscmp": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.6.tgz", + "integrity": "sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==" + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true + }, + "type-check": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", + "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", + "dev": true, + "requires": { + "prelude-ls": "~1.1.2" + } + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "uglify-js": { + "version": "3.6.7", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.7.tgz", + "integrity": "sha512-4sXQDzmdnoXiO+xvmTzQsfIiwrjUCSA95rSP4SEd8tDb51W2TiDOlL76Hl+Kw0Ie42PSItCW8/t6pBNCF2R48A==", + "dev": true, + "optional": true, + "requires": { + "commander": "~2.20.3", + "source-map": "~0.6.1" + } + }, + "union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + } + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "dev": true, + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "dev": true, + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + } + } + }, + "uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "urijs": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/urijs/-/urijs-1.19.2.tgz", + "integrity": "sha512-s/UIq9ap4JPZ7H1EB5ULo/aOUbWqfDi7FKzMC2Nz+0Si8GiT1rIEaprt8hy3Vy2Ex2aJPpOQv4P4DuOZ+K1c6w==" + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "dev": true + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "util.promisify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz", + "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "object.getownpropertydescriptors": "^2.0.3" + } + }, + "uuid": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", + "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "w3c-hr-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz", + "integrity": "sha1-gqwr/2PZUOqeMYmlimViX+3xkEU=", + "dev": true, + "requires": { + "browser-process-hrtime": "^0.1.2" + } + }, + "walker": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz", + "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=", + "dev": true, + "requires": { + "makeerror": "1.0.x" + } + }, + "webidl-conversions": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", + "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", + "dev": true + }, + "whatwg-encoding": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", + "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", + "dev": true, + "requires": { + "iconv-lite": "0.4.24" + } + }, + "whatwg-mimetype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", + "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", + "dev": true + }, + "whatwg-url": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.5.0.tgz", + "integrity": "sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==", + "dev": true, + "requires": { + "lodash.sortby": "^4.7.0", + "tr46": "^1.0.1", + "webidl-conversions": "^4.0.2" + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", + "dev": true + }, + "wordwrap": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", + "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", + "dev": true + }, + "wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "write-file-atomic": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.1.tgz", + "integrity": "sha512-TGHFeZEZMnv+gBFRfjAcxL5bPHrsGKtnb4qsFAws7/vlh+QfwAaySIw4AXP9ZskTTh5GWu3FLuJhsWVdiJPGvg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.2" + } + }, + "ws": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz", + "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0" + } + }, + "xml-name-validator": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", + "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", + "dev": true + }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "dev": true + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" + }, + "yargs": { + "version": "13.3.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", + "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", + "dev": true, + "requires": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.1" + } + }, + "yargs-parser": { + "version": "13.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", + "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", + "dev": true, + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "ylru": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ylru/-/ylru-1.2.1.tgz", + "integrity": "sha512-faQrqNMzcPCHGVC2aaOINk13K+aaBDUPjGWl0teOXywElLjyVAB6Oe2jj62jHYtwsU49jXhScYbvPENK+6zAvQ==" + } + } +} diff --git a/exercises/07_unit_testing/file_system/package.json b/exercises/07_unit_testing/file_system/package.json new file mode 100644 index 00000000..30a36a62 --- /dev/null +++ b/exercises/07_unit_testing/file_system/package.json @@ -0,0 +1,24 @@ +{ + "name": "file_system", + "version": "1.0.0", + "description": "mock-fs", + "main": "index.js", + "dependencies": { + "fs": "^0.0.1-security", + "http-status-codes": "^1.4.0", + "koa": "^2.11.0", + "koa-bodyparser": "^4.2.1", + "koa-router": "^7.4.0", + "koa-views": "^6.2.1" + }, + "devDependencies": { + "mock-fs": "^4.10.3", + "jest": "^24.9.0", + "supertest": "^4.0.2" + }, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC" +} diff --git a/exercises/07_unit_testing/file_system/pictures.html b/exercises/07_unit_testing/file_system/pictures.html new file mode 100644 index 00000000..f7e21603 --- /dev/null +++ b/exercises/07_unit_testing/file_system/pictures.html @@ -0,0 +1,22 @@ + + + + + + + Pictures + + +

Save new pictures

+
+ Image to be uploaded: +
+ +

+ +
+

Saved pictures

+ + + + \ No newline at end of file diff --git a/exercises/07_unit_testing/file_system/unit tests/file.spec.js b/exercises/07_unit_testing/file_system/unit tests/file.spec.js new file mode 100644 index 00000000..1e5f1a91 --- /dev/null +++ b/exercises/07_unit_testing/file_system/unit tests/file.spec.js @@ -0,0 +1,131 @@ + +'use strict' + +const mock = require('mock-fs') + +const File = require('../modules/file') +const fs = require('fs') + +beforeAll( async() => { +}) + +afterAll( async() => { +}) + +describe('savePicture()', () => { + beforeEach( async() => { + mock({ + 'test': { + 'foo': 'bar' + } + }); + }) + afterEach( async() => { + afterEach(mock.restore); + }) + test(`filename can't be empty string`, async done => { + expect.assertions(1) + try { + file.savePicture('', 'asd') + done.fail('test failed') + } catch(err) { + expect(err.message).toBe(`filename can't be empty`) + } finally { + done() + } + }) + test(`filename can't be undefined`, async done => { + expect.assertions(1) + try { + file.savePicture() + done.fail('test failed') + } catch(err) { + expect(err.message).toBe(`filename can't be empty`) + } finally { + done() + } + }) + test(`imageData can't be empty`, async done => { + expect.assertions(1) + try { + file.savePicture('foo.jpg') + done.fail('test failed') + } catch(err) { + expect(err.message).toBe(`imageData can't be empty`) + } finally { + done() + } + }) + test(`binary information has to be correctly saved`, async done => { + expect.assertions(1) + try { + const file = new File() + file.savePicture('test/foobar', 'raboof') + fs.readFile('test/foobar', 'binary', (err, data) => { + if (err) throw new Error(err) + expect(data).toBe('raboof') + }) + } catch(err) { + done.fail('test failed') + } finally { + done() + } + }) +}) + +describe('readPicture()', () => { + beforeEach( async() => { + mock({ + '/test': { + 'foo': 'bar' + } + }); + }) + afterEach( async() => { + afterEach(mock.restore); + }) + test(`filename can't be empty`, async done => { + expect.assertions(1) + try { + file.readPicture('') + done.fail('test failed') + } catch(err) { + expect(err.message).toBe(`filename can't be empty`) + } finally { + done() + } + }) + test(`filename can't be undefined`, async done => { + expect.assertions(1) + try { + file.readPicture() + done.fail('test failed') + } catch(err) { + expect(err.message).toBe(`filename can't be empty`) + } finally { + done() + } + }) + test('file has to exist', async done => { + expect.assertions(1) + try { + file.readPicture('nonExistent.txt') + done.fail('test failed') + } catch(err) { + expect(err.message).toBe(`file doesn't exist`) + } finally { + done() + } + }) + test(`binary information has to be correctly read`, async done => { + expect.assertions(1) + try { + const file = new File() + expect(file.readPicture('test/foo')).toBe('bar') + } catch(err) { + done.fail('test failed') + } finally { + done() + } + }) +}) \ No newline at end of file diff --git a/exercises/07_unit_testing/file_system/views/pictures.html b/exercises/07_unit_testing/file_system/views/pictures.html new file mode 100644 index 00000000..0bdc4ed5 --- /dev/null +++ b/exercises/07_unit_testing/file_system/views/pictures.html @@ -0,0 +1,20 @@ + + + + + + + Pictures + + +

Save new pictures

+
+ Image to be uploaded: +
+ +

+ +
+

Saved pictures

+ + \ No newline at end of file From b0d1c688d924f30beffde9da05ebd567fb3c48c3 Mon Sep 17 00:00:00 2001 From: Balazs Laszlo Bordas Date: Fri, 8 Nov 2019 02:32:36 +0000 Subject: [PATCH 30/70] fixes done to file_system unit test --- .../file_system/modules/file.js | 1 + .../file_system/package-lock.json | 5536 ----------------- .../07_unit_testing/file_system/package.json | 2 +- .../file_system/unit tests/file.spec.js | 32 +- 4 files changed, 18 insertions(+), 5553 deletions(-) delete mode 100644 exercises/07_unit_testing/file_system/package-lock.json diff --git a/exercises/07_unit_testing/file_system/modules/file.js b/exercises/07_unit_testing/file_system/modules/file.js index 7b18a962..644c4aa1 100644 --- a/exercises/07_unit_testing/file_system/modules/file.js +++ b/exercises/07_unit_testing/file_system/modules/file.js @@ -19,6 +19,7 @@ module.exports = class File { try { fs.readFileSync(filename, 'binary') } catch(err) { + console.log(err) throw new Error(`file doesn't exist`) } } diff --git a/exercises/07_unit_testing/file_system/package-lock.json b/exercises/07_unit_testing/file_system/package-lock.json deleted file mode 100644 index 139ea16a..00000000 --- a/exercises/07_unit_testing/file_system/package-lock.json +++ /dev/null @@ -1,5536 +0,0 @@ -{ - "name": "file_system", - "version": "1.0.0", - "lockfileVersion": 1, - "requires": true, - "dependencies": { - "@babel/code-frame": { - "version": "7.5.5", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.5.5.tgz", - "integrity": "sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw==", - "dev": true, - "requires": { - "@babel/highlight": "^7.0.0" - } - }, - "@babel/core": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.6.4.tgz", - "integrity": "sha512-Rm0HGw101GY8FTzpWSyRbki/jzq+/PkNQJ+nSulrdY6gFGOsNseCqD6KHRYe2E+EdzuBdr2pxCp6s4Uk6eJ+XQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.5.5", - "@babel/generator": "^7.6.4", - "@babel/helpers": "^7.6.2", - "@babel/parser": "^7.6.4", - "@babel/template": "^7.6.0", - "@babel/traverse": "^7.6.3", - "@babel/types": "^7.6.3", - "convert-source-map": "^1.1.0", - "debug": "^4.1.0", - "json5": "^2.1.0", - "lodash": "^4.17.13", - "resolve": "^1.3.2", - "semver": "^5.4.1", - "source-map": "^0.5.0" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "@babel/generator": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.6.4.tgz", - "integrity": "sha512-jsBuXkFoZxk0yWLyGI9llT9oiQ2FeTASmRFE32U+aaDTfoE92t78eroO7PTpU/OrYq38hlcDM6vbfLDaOLy+7w==", - "dev": true, - "requires": { - "@babel/types": "^7.6.3", - "jsesc": "^2.5.1", - "lodash": "^4.17.13", - "source-map": "^0.5.0" - }, - "dependencies": { - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "@babel/helper-function-name": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.1.0.tgz", - "integrity": "sha512-A95XEoCpb3TO+KZzJ4S/5uW5fNe26DjBGqf1o9ucyLyCmi1dXq/B3c8iaWTfBk3VvetUxl16e8tIrd5teOCfGw==", - "dev": true, - "requires": { - "@babel/helper-get-function-arity": "^7.0.0", - "@babel/template": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "@babel/helper-get-function-arity": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.0.0.tgz", - "integrity": "sha512-r2DbJeg4svYvt3HOS74U4eWKsUAMRH01Z1ds1zx8KNTPtpTL5JAsdFv8BNyOpVqdFhHkkRDIg5B4AsxmkjAlmQ==", - "dev": true, - "requires": { - "@babel/types": "^7.0.0" - } - }, - "@babel/helper-plugin-utils": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.0.0.tgz", - "integrity": "sha512-CYAOUCARwExnEixLdB6sDm2dIJ/YgEAKDM1MOeMeZu9Ld/bDgVo8aiWrXwcY7OBh+1Ea2uUcVRcxKk0GJvW7QA==", - "dev": true - }, - "@babel/helper-split-export-declaration": { - "version": "7.4.4", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.4.4.tgz", - "integrity": "sha512-Ro/XkzLf3JFITkW6b+hNxzZ1n5OQ80NvIUdmHspih1XAhtN3vPTuUFT4eQnela+2MaZ5ulH+iyP513KJrxbN7Q==", - "dev": true, - "requires": { - "@babel/types": "^7.4.4" - } - }, - "@babel/helpers": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.6.2.tgz", - "integrity": "sha512-3/bAUL8zZxYs1cdX2ilEE0WobqbCmKWr/889lf2SS0PpDcpEIY8pb1CCyz0pEcX3pEb+MCbks1jIokz2xLtGTA==", - "dev": true, - "requires": { - "@babel/template": "^7.6.0", - "@babel/traverse": "^7.6.2", - "@babel/types": "^7.6.0" - } - }, - "@babel/highlight": { - "version": "7.5.0", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.5.0.tgz", - "integrity": "sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ==", - "dev": true, - "requires": { - "chalk": "^2.0.0", - "esutils": "^2.0.2", - "js-tokens": "^4.0.0" - } - }, - "@babel/parser": { - "version": "7.6.4", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.6.4.tgz", - "integrity": "sha512-D8RHPW5qd0Vbyo3qb+YjO5nvUVRTXFLQ/FsDxJU2Nqz4uB5EnUN0ZQSEYpvTIbRuttig1XbHWU5oMeQwQSAA+A==", - "dev": true - }, - "@babel/plugin-syntax-object-rest-spread": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.2.0.tgz", - "integrity": "sha512-t0JKGgqk2We+9may3t0xDdmneaXmyxq0xieYcKHxIsrJO64n1OiMWNUtc5gQK1PA0NpdCRrtZp4z+IUaKugrSA==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0" - } - }, - "@babel/template": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.6.0.tgz", - "integrity": "sha512-5AEH2EXD8euCk446b7edmgFdub/qfH1SN6Nii3+fyXP807QRx9Q73A2N5hNwRRslC2H9sNzaFhsPubkS4L8oNQ==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@babel/parser": "^7.6.0", - "@babel/types": "^7.6.0" - } - }, - "@babel/traverse": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.6.3.tgz", - "integrity": "sha512-unn7P4LGsijIxaAJo/wpoU11zN+2IaClkQAxcJWBNCMS6cmVh802IyLHNkAjQ0iYnRS3nnxk5O3fuXW28IMxTw==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.5.5", - "@babel/generator": "^7.6.3", - "@babel/helper-function-name": "^7.1.0", - "@babel/helper-split-export-declaration": "^7.4.4", - "@babel/parser": "^7.6.3", - "@babel/types": "^7.6.3", - "debug": "^4.1.0", - "globals": "^11.1.0", - "lodash": "^4.17.13" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } - } - }, - "@babel/types": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.6.3.tgz", - "integrity": "sha512-CqbcpTxMcpuQTMhjI37ZHVgjBkysg5icREQIEZ0eG1yCNwg3oy+5AaLiOKmjsCj6nqOsa6Hf0ObjRVwokb7srA==", - "dev": true, - "requires": { - "esutils": "^2.0.2", - "lodash": "^4.17.13", - "to-fast-properties": "^2.0.0" - } - }, - "@cnakazawa/watch": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.3.tgz", - "integrity": "sha512-r5160ogAvGyHsal38Kux7YYtodEKOj89RGb28ht1jh3SJb08VwRwAKKJL0bGb04Zd/3r9FL3BFIc3bBidYffCA==", - "dev": true, - "requires": { - "exec-sh": "^0.3.2", - "minimist": "^1.2.0" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - } - } - }, - "@jest/console": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/console/-/console-24.9.0.tgz", - "integrity": "sha512-Zuj6b8TnKXi3q4ymac8EQfc3ea/uhLeCGThFqXeC8H9/raaH8ARPUTdId+XyGd03Z4In0/VjD2OYFcBF09fNLQ==", - "dev": true, - "requires": { - "@jest/source-map": "^24.9.0", - "chalk": "^2.0.1", - "slash": "^2.0.0" - } - }, - "@jest/core": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/core/-/core-24.9.0.tgz", - "integrity": "sha512-Fogg3s4wlAr1VX7q+rhV9RVnUv5tD7VuWfYy1+whMiWUrvl7U3QJSJyWcDio9Lq2prqYsZaeTv2Rz24pWGkJ2A==", - "dev": true, - "requires": { - "@jest/console": "^24.7.1", - "@jest/reporters": "^24.9.0", - "@jest/test-result": "^24.9.0", - "@jest/transform": "^24.9.0", - "@jest/types": "^24.9.0", - "ansi-escapes": "^3.0.0", - "chalk": "^2.0.1", - "exit": "^0.1.2", - "graceful-fs": "^4.1.15", - "jest-changed-files": "^24.9.0", - "jest-config": "^24.9.0", - "jest-haste-map": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-regex-util": "^24.3.0", - "jest-resolve": "^24.9.0", - "jest-resolve-dependencies": "^24.9.0", - "jest-runner": "^24.9.0", - "jest-runtime": "^24.9.0", - "jest-snapshot": "^24.9.0", - "jest-util": "^24.9.0", - "jest-validate": "^24.9.0", - "jest-watcher": "^24.9.0", - "micromatch": "^3.1.10", - "p-each-series": "^1.0.0", - "realpath-native": "^1.1.0", - "rimraf": "^2.5.4", - "slash": "^2.0.0", - "strip-ansi": "^5.0.0" - } - }, - "@jest/environment": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-24.9.0.tgz", - "integrity": "sha512-5A1QluTPhvdIPFYnO3sZC3smkNeXPVELz7ikPbhUj0bQjB07EoE9qtLrem14ZUYWdVayYbsjVwIiL4WBIMV4aQ==", - "dev": true, - "requires": { - "@jest/fake-timers": "^24.9.0", - "@jest/transform": "^24.9.0", - "@jest/types": "^24.9.0", - "jest-mock": "^24.9.0" - } - }, - "@jest/fake-timers": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-24.9.0.tgz", - "integrity": "sha512-eWQcNa2YSwzXWIMC5KufBh3oWRIijrQFROsIqt6v/NS9Io/gknw1jsAC9c+ih/RQX4A3O7SeWAhQeN0goKhT9A==", - "dev": true, - "requires": { - "@jest/types": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-mock": "^24.9.0" - } - }, - "@jest/reporters": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-24.9.0.tgz", - "integrity": "sha512-mu4X0yjaHrffOsWmVLzitKmmmWSQ3GGuefgNscUSWNiUNcEOSEQk9k3pERKEQVBb0Cnn88+UESIsZEMH3o88Gw==", - "dev": true, - "requires": { - "@jest/environment": "^24.9.0", - "@jest/test-result": "^24.9.0", - "@jest/transform": "^24.9.0", - "@jest/types": "^24.9.0", - "chalk": "^2.0.1", - "exit": "^0.1.2", - "glob": "^7.1.2", - "istanbul-lib-coverage": "^2.0.2", - "istanbul-lib-instrument": "^3.0.1", - "istanbul-lib-report": "^2.0.4", - "istanbul-lib-source-maps": "^3.0.1", - "istanbul-reports": "^2.2.6", - "jest-haste-map": "^24.9.0", - "jest-resolve": "^24.9.0", - "jest-runtime": "^24.9.0", - "jest-util": "^24.9.0", - "jest-worker": "^24.6.0", - "node-notifier": "^5.4.2", - "slash": "^2.0.0", - "source-map": "^0.6.0", - "string-length": "^2.0.0" - } - }, - "@jest/source-map": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-24.9.0.tgz", - "integrity": "sha512-/Xw7xGlsZb4MJzNDgB7PW5crou5JqWiBQaz6xyPd3ArOg2nfn/PunV8+olXbbEZzNl591o5rWKE9BRDaFAuIBg==", - "dev": true, - "requires": { - "callsites": "^3.0.0", - "graceful-fs": "^4.1.15", - "source-map": "^0.6.0" - } - }, - "@jest/test-result": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-24.9.0.tgz", - "integrity": "sha512-XEFrHbBonBJ8dGp2JmF8kP/nQI/ImPpygKHwQ/SY+es59Z3L5PI4Qb9TQQMAEeYsThG1xF0k6tmG0tIKATNiiA==", - "dev": true, - "requires": { - "@jest/console": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/istanbul-lib-coverage": "^2.0.0" - } - }, - "@jest/test-sequencer": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-24.9.0.tgz", - "integrity": "sha512-6qqsU4o0kW1dvA95qfNog8v8gkRN9ph6Lz7r96IvZpHdNipP2cBcb07J1Z45mz/VIS01OHJ3pY8T5fUY38tg4A==", - "dev": true, - "requires": { - "@jest/test-result": "^24.9.0", - "jest-haste-map": "^24.9.0", - "jest-runner": "^24.9.0", - "jest-runtime": "^24.9.0" - } - }, - "@jest/transform": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-24.9.0.tgz", - "integrity": "sha512-TcQUmyNRxV94S0QpMOnZl0++6RMiqpbH/ZMccFB/amku6Uwvyb1cjYX7xkp5nGNkbX4QPH/FcB6q1HBTHynLmQ==", - "dev": true, - "requires": { - "@babel/core": "^7.1.0", - "@jest/types": "^24.9.0", - "babel-plugin-istanbul": "^5.1.0", - "chalk": "^2.0.1", - "convert-source-map": "^1.4.0", - "fast-json-stable-stringify": "^2.0.0", - "graceful-fs": "^4.1.15", - "jest-haste-map": "^24.9.0", - "jest-regex-util": "^24.9.0", - "jest-util": "^24.9.0", - "micromatch": "^3.1.10", - "pirates": "^4.0.1", - "realpath-native": "^1.1.0", - "slash": "^2.0.0", - "source-map": "^0.6.1", - "write-file-atomic": "2.4.1" - } - }, - "@jest/types": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/@jest/types/-/types-24.9.0.tgz", - "integrity": "sha512-XKK7ze1apu5JWQ5eZjHITP66AX+QsLlbaJRBGYr8pNzwcAE2JVkwnf0yqjHTsDRcjR0mujy/NmZMXw5kl+kGBw==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "^2.0.0", - "@types/istanbul-reports": "^1.1.1", - "@types/yargs": "^13.0.0" - } - }, - "@types/babel__core": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.3.tgz", - "integrity": "sha512-8fBo0UR2CcwWxeX7WIIgJ7lXjasFxoYgRnFHUj+hRvKkpiBJbxhdAPTCY6/ZKM0uxANFVzt4yObSLuTiTnazDA==", - "dev": true, - "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0", - "@types/babel__generator": "*", - "@types/babel__template": "*", - "@types/babel__traverse": "*" - } - }, - "@types/babel__generator": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.0.tgz", - "integrity": "sha512-c1mZUu4up5cp9KROs/QAw0gTeHrw/x7m52LcnvMxxOZ03DmLwPV0MlGmlgzV3cnSdjhJOZsj7E7FHeioai+egw==", - "dev": true, - "requires": { - "@babel/types": "^7.0.0" - } - }, - "@types/babel__template": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.0.2.tgz", - "integrity": "sha512-/K6zCpeW7Imzgab2bLkLEbz0+1JlFSrUMdw7KoIIu+IUdu51GWaBZpd3y1VXGVXzynvGa4DaIaxNZHiON3GXUg==", - "dev": true, - "requires": { - "@babel/parser": "^7.1.0", - "@babel/types": "^7.0.0" - } - }, - "@types/babel__traverse": { - "version": "7.0.7", - "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.0.7.tgz", - "integrity": "sha512-CeBpmX1J8kWLcDEnI3Cl2Eo6RfbGvzUctA+CjZUhOKDFbLfcr7fc4usEqLNWetrlJd7RhAkyYe2czXop4fICpw==", - "dev": true, - "requires": { - "@babel/types": "^7.3.0" - } - }, - "@types/istanbul-lib-coverage": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.1.tgz", - "integrity": "sha512-hRJD2ahnnpLgsj6KWMYSrmXkM3rm2Dl1qkx6IOFD5FnuNPXJIG5L0dhgKXCYTRMGzU4n0wImQ/xfmRc4POUFlg==", - "dev": true - }, - "@types/istanbul-lib-report": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-1.1.1.tgz", - "integrity": "sha512-3BUTyMzbZa2DtDI2BkERNC6jJw2Mr2Y0oGI7mRxYNBPxppbtEK1F66u3bKwU2g+wxwWI7PAoRpJnOY1grJqzHg==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "*" - } - }, - "@types/istanbul-reports": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-1.1.1.tgz", - "integrity": "sha512-UpYjBi8xefVChsCoBpKShdxTllC9pwISirfoZsUa2AAdQg/Jd2KQGtSbw+ya7GPo7x/wAPlH6JBhKhAsXUEZNA==", - "dev": true, - "requires": { - "@types/istanbul-lib-coverage": "*", - "@types/istanbul-lib-report": "*" - } - }, - "@types/stack-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz", - "integrity": "sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw==", - "dev": true - }, - "@types/yargs": { - "version": "13.0.3", - "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-13.0.3.tgz", - "integrity": "sha512-K8/LfZq2duW33XW/tFwEAfnZlqIfVsoyRB3kfXdPXYhl0nfM8mmh7GS0jg7WrX2Dgq/0Ha/pR1PaR+BvmWwjiQ==", - "dev": true, - "requires": { - "@types/yargs-parser": "*" - } - }, - "@types/yargs-parser": { - "version": "13.1.0", - "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-13.1.0.tgz", - "integrity": "sha512-gCubfBUZ6KxzoibJ+SCUc/57Ms1jz5NjHe4+dI2krNmU5zCPAphyLJYyTOg06ueIyfj+SaCUqmzun7ImlxDcKg==", - "dev": true - }, - "abab": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/abab/-/abab-2.0.2.tgz", - "integrity": "sha512-2scffjvioEmNz0OyDSLGWDfKCVwaKc6l9Pm9kOIREU13ClXZvHpg/nRL5xyjSSSLhOnXqft2HpsAzNEEA8cFFg==", - "dev": true - }, - "abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" - }, - "accepts": { - "version": "1.3.7", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", - "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", - "requires": { - "mime-types": "~2.1.24", - "negotiator": "0.6.2" - } - }, - "acorn": { - "version": "5.7.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.7.3.tgz", - "integrity": "sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==", - "dev": true - }, - "acorn-globals": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-4.3.4.tgz", - "integrity": "sha512-clfQEh21R+D0leSbUdWf3OcfqyaCSAQ8Ryq00bofSekfr9W8u1jyYZo6ir0xu9Gtcf7BjcHJpnbZH7JOCpP60A==", - "dev": true, - "requires": { - "acorn": "^6.0.1", - "acorn-walk": "^6.0.1" - }, - "dependencies": { - "acorn": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.3.0.tgz", - "integrity": "sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA==", - "dev": true - } - } - }, - "acorn-walk": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-6.2.0.tgz", - "integrity": "sha512-7evsyfH1cLOCdAzZAd43Cic04yKydNx0cF+7tiA19p1XnLLPU4dpCQOqpjqwokFe//vS0QqfqqjCS2JkiIs0cA==", - "dev": true - }, - "ajv": { - "version": "6.10.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", - "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", - "dev": true, - "requires": { - "fast-deep-equal": "^2.0.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - } - }, - "ansi-escapes": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-3.2.0.tgz", - "integrity": "sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ==", - "dev": true - }, - "ansi-regex": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz", - "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==", - "dev": true - }, - "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "requires": { - "color-convert": "^1.9.0" - } - }, - "any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha1-q8av7tzqUugJzcA3au0845Y10X8=" - }, - "anymatch": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", - "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", - "dev": true, - "requires": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - } - }, - "arr-diff": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", - "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", - "dev": true - }, - "arr-flatten": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", - "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", - "dev": true - }, - "arr-union": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", - "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", - "dev": true - }, - "array-equal": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/array-equal/-/array-equal-1.0.0.tgz", - "integrity": "sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=", - "dev": true - }, - "array-unique": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", - "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", - "dev": true - }, - "asn1": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", - "dev": true, - "requires": { - "safer-buffer": "~2.1.0" - } - }, - "assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", - "dev": true - }, - "assign-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", - "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", - "dev": true - }, - "astral-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-1.0.0.tgz", - "integrity": "sha512-+Ryf6g3BKoRc7jfp7ad8tM4TtMiaWvbF/1/sQcZPkkS7ag3D5nMBCe2UfOTONtAkaG0tO0ij3C5Lwmf1EiyjHg==", - "dev": true - }, - "async-limiter": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/async-limiter/-/async-limiter-1.0.1.tgz", - "integrity": "sha512-csOlWGAcRFJaI6m+F2WKdnMKr4HhdhFVBk0H/QbJFMCr+uO2kwohwXQPxw/9OCxp05r5ghVBFSyioixx3gfkNQ==", - "dev": true - }, - "asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", - "dev": true - }, - "atob": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", - "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", - "dev": true - }, - "aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", - "dev": true - }, - "aws4": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", - "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==", - "dev": true - }, - "babel-jest": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-24.9.0.tgz", - "integrity": "sha512-ntuddfyiN+EhMw58PTNL1ph4C9rECiQXjI4nMMBKBaNjXvqLdkXpPRcMSr4iyBrJg/+wz9brFUD6RhOAT6r4Iw==", - "dev": true, - "requires": { - "@jest/transform": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/babel__core": "^7.1.0", - "babel-plugin-istanbul": "^5.1.0", - "babel-preset-jest": "^24.9.0", - "chalk": "^2.4.2", - "slash": "^2.0.0" - } - }, - "babel-plugin-istanbul": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-5.2.0.tgz", - "integrity": "sha512-5LphC0USA8t4i1zCtjbbNb6jJj/9+X6P37Qfirc/70EQ34xKlMW+a1RHGwxGI+SwWpNwZ27HqvzAobeqaXwiZw==", - "dev": true, - "requires": { - "@babel/helper-plugin-utils": "^7.0.0", - "find-up": "^3.0.0", - "istanbul-lib-instrument": "^3.3.0", - "test-exclude": "^5.2.3" - } - }, - "babel-plugin-jest-hoist": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-24.9.0.tgz", - "integrity": "sha512-2EMA2P8Vp7lG0RAzr4HXqtYwacfMErOuv1U3wrvxHX6rD1sV6xS3WXG3r8TRQ2r6w8OhvSdWt+z41hQNwNm3Xw==", - "dev": true, - "requires": { - "@types/babel__traverse": "^7.0.6" - } - }, - "babel-preset-jest": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-24.9.0.tgz", - "integrity": "sha512-izTUuhE4TMfTRPF92fFwD2QfdXaZW08qvWTFCI51V8rW5x00UuPgc3ajRoWofXOuxjfcOM5zzSYsQS3H8KGCAg==", - "dev": true, - "requires": { - "@babel/plugin-syntax-object-rest-spread": "^7.0.0", - "babel-plugin-jest-hoist": "^24.9.0" - } - }, - "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" - }, - "base": { - "version": "0.11.2", - "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", - "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", - "dev": true, - "requires": { - "cache-base": "^1.0.1", - "class-utils": "^0.3.5", - "component-emitter": "^1.2.1", - "define-property": "^1.0.0", - "isobject": "^3.0.1", - "mixin-deep": "^1.2.0", - "pascalcase": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - } - } - }, - "bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", - "dev": true, - "requires": { - "tweetnacl": "^0.14.3" - } - }, - "bluebird": { - "version": "3.7.1", - "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.1.tgz", - "integrity": "sha512-DdmyoGCleJnkbp3nkbxTLJ18rjDsE4yCggEwKNXkeV123sPNfOCYeDoeuOY+F2FrSjO1YXcTU+dsy96KMy+gcg==" - }, - "brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "braces": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", - "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - } - }, - "browser-process-hrtime": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-0.1.3.tgz", - "integrity": "sha512-bRFnI4NnjO6cnyLmOV/7PVoDEMJChlcfN0z4s1YMBY989/SvlfMI1lgCnkFUs53e9gQF+w7qu7XdllSTiSl8Aw==", - "dev": true - }, - "browser-resolve": { - "version": "1.11.3", - "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-1.11.3.tgz", - "integrity": "sha512-exDi1BYWB/6raKHmDTCicQfTkqwN5fioMFV4j8BsfMU4R2DK/QfZfK7kOVkmWCNANf0snkBzqGqAJBao9gZMdQ==", - "dev": true, - "requires": { - "resolve": "1.1.7" - }, - "dependencies": { - "resolve": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", - "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", - "dev": true - } - } - }, - "bser": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", - "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", - "dev": true, - "requires": { - "node-int64": "^0.4.0" - } - }, - "buffer-from": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", - "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", - "dev": true - }, - "bytes": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz", - "integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==" - }, - "cache-base": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", - "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", - "dev": true, - "requires": { - "collection-visit": "^1.0.0", - "component-emitter": "^1.2.1", - "get-value": "^2.0.6", - "has-value": "^1.0.0", - "isobject": "^3.0.1", - "set-value": "^2.0.0", - "to-object-path": "^0.3.0", - "union-value": "^1.0.0", - "unset-value": "^1.0.0" - } - }, - "cache-content-type": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cache-content-type/-/cache-content-type-1.0.1.tgz", - "integrity": "sha512-IKufZ1o4Ut42YUrZSo8+qnMTrFuKkvyoLXUywKz9GJ5BrhOFGhLdkx9sG4KAnVvbY6kEcSFjLQul+DVmBm2bgA==", - "requires": { - "mime-types": "^2.1.18", - "ylru": "^1.2.0" - } - }, - "callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true - }, - "camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true - }, - "capture-exit": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz", - "integrity": "sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g==", - "dev": true, - "requires": { - "rsvp": "^4.8.4" - } - }, - "caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", - "dev": true - }, - "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", - "dev": true - }, - "class-utils": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", - "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "define-property": "^0.2.5", - "isobject": "^3.0.0", - "static-extend": "^0.1.1" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, - "cliui": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", - "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", - "dev": true, - "requires": { - "string-width": "^3.1.0", - "strip-ansi": "^5.2.0", - "wrap-ansi": "^5.1.0" - } - }, - "co": { - "version": "4.6.0", - "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", - "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=" - }, - "collection-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", - "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", - "dev": true, - "requires": { - "map-visit": "^1.0.0", - "object-visit": "^1.0.0" - } - }, - "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "requires": { - "color-name": "1.1.3" - } - }, - "color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, - "requires": { - "delayed-stream": "~1.0.0" - } - }, - "commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" - }, - "component-emitter": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz", - "integrity": "sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg==", - "dev": true - }, - "concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" - }, - "condense-newlines": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/condense-newlines/-/condense-newlines-0.2.1.tgz", - "integrity": "sha1-PemFVTE5R10yUCyDsC9gaE0kxV8=", - "requires": { - "extend-shallow": "^2.0.1", - "is-whitespace": "^0.3.0", - "kind-of": "^3.0.2" - } - }, - "config-chain": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/config-chain/-/config-chain-1.1.12.tgz", - "integrity": "sha512-a1eOIcu8+7lUInge4Rpf/n4Krkf3Dd9lqhljRzII1/Zno/kRtUWnznPO3jOKBmTEktkt3fkxisUcivoj0ebzoA==", - "requires": { - "ini": "^1.3.4", - "proto-list": "~1.2.1" - } - }, - "consolidate": { - "version": "0.15.1", - "resolved": "https://registry.npmjs.org/consolidate/-/consolidate-0.15.1.tgz", - "integrity": "sha512-DW46nrsMJgy9kqAbPt5rKaCr7uFtpo4mSUvLHIUbJEjm0vo+aY5QLwBUq3FK4tRnJr/X0Psc0C4jf/h+HtXSMw==", - "requires": { - "bluebird": "^3.1.1" - } - }, - "content-disposition": { - "version": "0.5.3", - "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.3.tgz", - "integrity": "sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g==", - "requires": { - "safe-buffer": "5.1.2" - } - }, - "content-type": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.4.tgz", - "integrity": "sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==" - }, - "convert-source-map": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", - "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.1" - } - }, - "cookiejar": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/cookiejar/-/cookiejar-2.1.2.tgz", - "integrity": "sha512-Mw+adcfzPxcPeI+0WlvRrr/3lGVO0bD75SxX6811cxSh1Wbxx7xZBGK1eVtDf6si8rg2lhnUjsVLMFMfbRIuwA==", - "dev": true - }, - "cookies": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/cookies/-/cookies-0.8.0.tgz", - "integrity": "sha512-8aPsApQfebXnuI+537McwYsDtjVxGm8gTIzQI3FDW6t5t/DAhERxtnbEPN/8RX+uZthoz4eCOgloXaE5cYyNow==", - "requires": { - "depd": "~2.0.0", - "keygrip": "~1.1.0" - }, - "dependencies": { - "depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" - } - } - }, - "copy-descriptor": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", - "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", - "dev": true - }, - "copy-to": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/copy-to/-/copy-to-2.0.1.tgz", - "integrity": "sha1-JoD7uAaKSNCGVrYJgJK9r8kG9KU=" - }, - "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", - "dev": true - }, - "cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "requires": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "cssom": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz", - "integrity": "sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==", - "dev": true - }, - "cssstyle": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-1.4.0.tgz", - "integrity": "sha512-GBrLZYZ4X4x6/QEoBnIrqb8B/f5l4+8me2dkom/j1Gtbxy0kBv6OGzKuAsGM75bkGwGAFkt56Iwg28S3XTZgSA==", - "dev": true, - "requires": { - "cssom": "0.3.x" - } - }, - "dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0" - } - }, - "data-urls": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-1.1.0.tgz", - "integrity": "sha512-YTWYI9se1P55u58gL5GkQHW4P6VJBJ5iBT+B5a7i2Tjadhv52paJG0qHX4A0OR6/t52odI64KP2YvFpkDOi3eQ==", - "dev": true, - "requires": { - "abab": "^2.0.0", - "whatwg-mimetype": "^2.2.0", - "whatwg-url": "^7.0.0" - }, - "dependencies": { - "whatwg-url": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-7.1.0.tgz", - "integrity": "sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==", - "dev": true, - "requires": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" - } - } - } - }, - "debug": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", - "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", - "requires": { - "ms": "2.0.0" - } - }, - "decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true - }, - "decode-uri-component": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", - "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", - "dev": true - }, - "deep-equal": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-1.0.1.tgz", - "integrity": "sha1-9dJgKStmDghO/0zbyfCK0yR0SLU=" - }, - "deep-is": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz", - "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=", - "dev": true - }, - "define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dev": true, - "requires": { - "object-keys": "^1.0.12" - } - }, - "define-property": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", - "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", - "dev": true, - "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - }, - "dependencies": { - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - } - } - }, - "delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true - }, - "delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=" - }, - "depd": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", - "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" - }, - "destroy": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", - "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" - }, - "detect-newline": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-2.1.0.tgz", - "integrity": "sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I=", - "dev": true - }, - "diff-sequences": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-24.9.0.tgz", - "integrity": "sha512-Dj6Wk3tWyTE+Fo1rW8v0Xhwk80um6yFYKbuAxc9c3EZxIHFDYwbi34Uk42u1CdnIiVorvt4RmlSDjIPyzGC2ew==", - "dev": true - }, - "domexception": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/domexception/-/domexception-1.0.1.tgz", - "integrity": "sha512-raigMkn7CJNNo6Ihro1fzG7wr3fHuYVytzquZKX5n0yizGsTcYgzdIUwj1X9pK0VvjeihV+XiclP+DjwbsSKug==", - "dev": true, - "requires": { - "webidl-conversions": "^4.0.2" - } - }, - "ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", - "dev": true, - "requires": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, - "editorconfig": { - "version": "0.15.3", - "resolved": "https://registry.npmjs.org/editorconfig/-/editorconfig-0.15.3.tgz", - "integrity": "sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g==", - "requires": { - "commander": "^2.19.0", - "lru-cache": "^4.1.5", - "semver": "^5.6.0", - "sigmund": "^1.0.1" - } - }, - "ee-first": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", - "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" - }, - "emoji-regex": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", - "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", - "dev": true - }, - "encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" - }, - "end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "requires": { - "once": "^1.4.0" - } - }, - "error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "requires": { - "is-arrayish": "^0.2.1" - } - }, - "error-inject": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/error-inject/-/error-inject-1.0.0.tgz", - "integrity": "sha1-4rPZG1Su1nLzCdlQ0VSFD6EdTzc=" - }, - "es-abstract": { - "version": "1.16.0", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.16.0.tgz", - "integrity": "sha512-xdQnfykZ9JMEiasTAJZJdMWCQ1Vm00NBw79/AWi7ELfZuuPCSOMDZbT9mkOfSctVtfhb+sAAzrm+j//GjjLHLg==", - "dev": true, - "requires": { - "es-to-primitive": "^1.2.0", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.0", - "is-callable": "^1.1.4", - "is-regex": "^1.0.4", - "object-inspect": "^1.6.0", - "object-keys": "^1.1.1", - "string.prototype.trimleft": "^2.1.0", - "string.prototype.trimright": "^2.1.0" - } - }, - "es-to-primitive": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", - "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", - "dev": true, - "requires": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "escape-html": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", - "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" - }, - "escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "escodegen": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.12.0.tgz", - "integrity": "sha512-TuA+EhsanGcme5T3R0L80u4t8CpbXQjegRmf7+FPTJrtCTErXFeelblRgHQa1FofEzqYYJmJ/OqjTwREp9qgmg==", - "dev": true, - "requires": { - "esprima": "^3.1.3", - "estraverse": "^4.2.0", - "esutils": "^2.0.2", - "optionator": "^0.8.1", - "source-map": "~0.6.1" - } - }, - "esprima": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz", - "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=", - "dev": true - }, - "estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true - }, - "esutils": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", - "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true - }, - "exec-sh": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.2.tgz", - "integrity": "sha512-9sLAvzhI5nc8TpuQUh4ahMdCrWT00wPWz7j47/emR5+2qEfoZP5zzUXvx+vdx+H6ohhnsYC31iX04QLYJK8zTg==", - "dev": true - }, - "execa": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", - "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", - "dev": true, - "requires": { - "cross-spawn": "^6.0.0", - "get-stream": "^4.0.0", - "is-stream": "^1.1.0", - "npm-run-path": "^2.0.0", - "p-finally": "^1.0.0", - "signal-exit": "^3.0.0", - "strip-eof": "^1.0.0" - } - }, - "exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", - "dev": true - }, - "expand-brackets": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", - "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", - "dev": true, - "requires": { - "debug": "^2.3.3", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "posix-character-classes": "^0.1.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, - "expect": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/expect/-/expect-24.9.0.tgz", - "integrity": "sha512-wvVAx8XIol3Z5m9zvZXiyZOQ+sRJqNTIm6sGjdWlaZIeupQGO3WbYI+15D/AmEwZywL6wtJkbAbJtzkOfBuR0Q==", - "dev": true, - "requires": { - "@jest/types": "^24.9.0", - "ansi-styles": "^3.2.0", - "jest-get-type": "^24.9.0", - "jest-matcher-utils": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-regex-util": "^24.9.0" - } - }, - "extend": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", - "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", - "dev": true - }, - "extend-shallow": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", - "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", - "requires": { - "is-extendable": "^0.1.0" - } - }, - "extglob": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", - "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", - "dev": true, - "requires": { - "array-unique": "^0.3.2", - "define-property": "^1.0.0", - "expand-brackets": "^2.1.4", - "extend-shallow": "^2.0.1", - "fragment-cache": "^0.2.1", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - } - } - }, - "extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", - "dev": true - }, - "fast-deep-equal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", - "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", - "dev": true - }, - "fast-json-stable-stringify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", - "dev": true - }, - "fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", - "dev": true - }, - "fb-watchman": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.0.tgz", - "integrity": "sha1-VOmr99+i8mzZsWNsWIwa/AXeXVg=", - "dev": true, - "requires": { - "bser": "^2.0.0" - } - }, - "fill-range": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", - "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - } - }, - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "requires": { - "locate-path": "^3.0.0" - } - }, - "for-in": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", - "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", - "dev": true - }, - "forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", - "dev": true - }, - "form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "dev": true, - "requires": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - } - }, - "formidable": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.2.1.tgz", - "integrity": "sha512-Fs9VRguL0gqGHkXS5GQiMCr1VhZBxz0JnJs4JmMp/2jL18Fmbzvv7vOFRU+U8TBkHEE/CX1qDXzJplVULgsLeg==", - "dev": true - }, - "fragment-cache": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", - "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", - "dev": true, - "requires": { - "map-cache": "^0.2.2" - } - }, - "fresh": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", - "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" - }, - "fs": { - "version": "0.0.1-security", - "resolved": "https://registry.npmjs.org/fs/-/fs-0.0.1-security.tgz", - "integrity": "sha1-invTcYa23d84E/I4WLV+yq9eQdQ=" - }, - "fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" - }, - "fsevents": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz", - "integrity": "sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw==", - "dev": true, - "optional": true, - "requires": { - "nan": "^2.12.1", - "node-pre-gyp": "^0.12.0" - }, - "dependencies": { - "abbrev": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "ansi-regex": { - "version": "2.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "aproba": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "optional": true - }, - "are-we-there-yet": { - "version": "1.1.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "delegates": "^1.0.0", - "readable-stream": "^2.0.6" - } - }, - "balanced-match": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "brace-expansion": { - "version": "1.1.11", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "chownr": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "code-point-at": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "optional": true - }, - "concat-map": { - "version": "0.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "console-control-strings": { - "version": "1.1.0", - "bundled": true, - "dev": true, - "optional": true - }, - "core-util-is": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "debug": { - "version": "4.1.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ms": "^2.1.1" - } - }, - "deep-extend": { - "version": "0.6.0", - "bundled": true, - "dev": true, - "optional": true - }, - "delegates": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "detect-libc": { - "version": "1.0.3", - "bundled": true, - "dev": true, - "optional": true - }, - "fs-minipass": { - "version": "1.2.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minipass": "^2.2.1" - } - }, - "fs.realpath": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "gauge": { - "version": "2.7.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "aproba": "^1.0.3", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", - "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" - } - }, - "glob": { - "version": "7.1.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "has-unicode": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "iconv-lite": { - "version": "0.4.24", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "ignore-walk": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minimatch": "^3.0.4" - } - }, - "inflight": { - "version": "1.0.6", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.3", - "bundled": true, - "dev": true, - "optional": true - }, - "ini": { - "version": "1.3.5", - "bundled": true, - "dev": true, - "optional": true - }, - "is-fullwidth-code-point": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "number-is-nan": "^1.0.0" - } - }, - "isarray": { - "version": "1.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "minimatch": { - "version": "3.0.4", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "0.0.8", - "bundled": true, - "dev": true, - "optional": true - }, - "minipass": { - "version": "2.3.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "^5.1.2", - "yallist": "^3.0.0" - } - }, - "minizlib": { - "version": "1.2.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minipass": "^2.2.1" - } - }, - "mkdirp": { - "version": "0.5.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "minimist": "0.0.8" - } - }, - "ms": { - "version": "2.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "needle": { - "version": "2.3.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "debug": "^4.1.0", - "iconv-lite": "^0.4.4", - "sax": "^1.2.4" - } - }, - "node-pre-gyp": { - "version": "0.12.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "detect-libc": "^1.0.2", - "mkdirp": "^0.5.1", - "needle": "^2.2.1", - "nopt": "^4.0.1", - "npm-packlist": "^1.1.6", - "npmlog": "^4.0.2", - "rc": "^1.2.7", - "rimraf": "^2.6.1", - "semver": "^5.3.0", - "tar": "^4" - } - }, - "nopt": { - "version": "4.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "abbrev": "1", - "osenv": "^0.1.4" - } - }, - "npm-bundled": { - "version": "1.0.6", - "bundled": true, - "dev": true, - "optional": true - }, - "npm-packlist": { - "version": "1.4.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ignore-walk": "^3.0.1", - "npm-bundled": "^1.0.1" - } - }, - "npmlog": { - "version": "4.1.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" - } - }, - "number-is-nan": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "object-assign": { - "version": "4.1.1", - "bundled": true, - "dev": true, - "optional": true - }, - "once": { - "version": "1.4.0", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "wrappy": "1" - } - }, - "os-homedir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "os-tmpdir": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "osenv": { - "version": "0.1.5", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, - "path-is-absolute": { - "version": "1.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "process-nextick-args": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "rc": { - "version": "1.2.8", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "deep-extend": "^0.6.0", - "ini": "~1.3.0", - "minimist": "^1.2.0", - "strip-json-comments": "~2.0.1" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "readable-stream": { - "version": "2.3.6", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "rimraf": { - "version": "2.6.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "glob": "^7.1.3" - } - }, - "safe-buffer": { - "version": "5.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "safer-buffer": { - "version": "2.1.2", - "bundled": true, - "dev": true, - "optional": true - }, - "sax": { - "version": "1.2.4", - "bundled": true, - "dev": true, - "optional": true - }, - "semver": { - "version": "5.7.0", - "bundled": true, - "dev": true, - "optional": true - }, - "set-blocking": { - "version": "2.0.0", - "bundled": true, - "dev": true, - "optional": true - }, - "signal-exit": { - "version": "3.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "string-width": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" - } - }, - "string_decoder": { - "version": "1.1.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "strip-ansi": { - "version": "3.0.1", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "strip-json-comments": { - "version": "2.0.1", - "bundled": true, - "dev": true, - "optional": true - }, - "tar": { - "version": "4.4.8", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "chownr": "^1.1.1", - "fs-minipass": "^1.2.5", - "minipass": "^2.3.4", - "minizlib": "^1.1.1", - "mkdirp": "^0.5.0", - "safe-buffer": "^5.1.2", - "yallist": "^3.0.2" - } - }, - "util-deprecate": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "wide-align": { - "version": "1.1.3", - "bundled": true, - "dev": true, - "optional": true, - "requires": { - "string-width": "^1.0.2 || 2" - } - }, - "wrappy": { - "version": "1.0.2", - "bundled": true, - "dev": true, - "optional": true - }, - "yallist": { - "version": "3.0.3", - "bundled": true, - "dev": true, - "optional": true - } - } - }, - "function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "dev": true - }, - "get-paths": { - "version": "0.0.7", - "resolved": "https://registry.npmjs.org/get-paths/-/get-paths-0.0.7.tgz", - "integrity": "sha512-0wdJt7C1XKQxuCgouqd+ZvLJ56FQixKoki9MrFaO4EriqzXOiH9gbukaDE1ou08S8Ns3/yDzoBAISNPqj6e6tA==", - "requires": { - "pify": "^4.0.1" - } - }, - "get-stream": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", - "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", - "dev": true, - "requires": { - "pump": "^3.0.0" - } - }, - "get-value": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", - "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", - "dev": true - }, - "getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0" - } - }, - "glob": { - "version": "7.1.5", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.5.tgz", - "integrity": "sha512-J9dlskqUXK1OeTOYBEn5s8aMukWMwWfs+rPTn/jn50Ux4MNXVhubL1wu/j2t+H4NVI+cXEcCaYellqaPVGXNqQ==", - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true - }, - "graceful-fs": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", - "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", - "dev": true - }, - "growly": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz", - "integrity": "sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE=", - "dev": true - }, - "handlebars": { - "version": "4.5.1", - "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.5.1.tgz", - "integrity": "sha512-C29UoFzHe9yM61lOsIlCE5/mQVGrnIOrOq7maQl76L7tYPCgC1og0Ajt6uWnX4ZTxBPnjw+CUvawphwCfJgUnA==", - "dev": true, - "requires": { - "neo-async": "^2.6.0", - "optimist": "^0.6.1", - "source-map": "^0.6.1", - "uglify-js": "^3.1.4" - } - }, - "har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", - "dev": true - }, - "har-validator": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", - "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", - "dev": true, - "requires": { - "ajv": "^6.5.5", - "har-schema": "^2.0.0" - } - }, - "has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "requires": { - "function-bind": "^1.1.1" - } - }, - "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "has-symbols": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", - "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", - "dev": true - }, - "has-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", - "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", - "dev": true, - "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" - } - }, - "has-values": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", - "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" - }, - "dependencies": { - "kind-of": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", - "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "hosted-git-info": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.5.tgz", - "integrity": "sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg==", - "dev": true - }, - "html-encoding-sniffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz", - "integrity": "sha512-71lZziiDnsuabfdYiUeWdCVyKuqwWi23L8YeIgV9jSSZHCtb6wB1BKWooH7L3tn4/FuZJMVWyNaIDr4RGmaSYw==", - "dev": true, - "requires": { - "whatwg-encoding": "^1.0.1" - } - }, - "http-assert": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/http-assert/-/http-assert-1.4.1.tgz", - "integrity": "sha512-rdw7q6GTlibqVVbXr0CKelfV5iY8G2HqEUkhSk297BMbSpSL8crXC+9rjKoMcZZEsksX30le6f/4ul4E28gegw==", - "requires": { - "deep-equal": "~1.0.1", - "http-errors": "~1.7.2" - } - }, - "http-errors": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.7.3.tgz", - "integrity": "sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw==", - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.4", - "setprototypeof": "1.1.1", - "statuses": ">= 1.5.0 < 2", - "toidentifier": "1.0.0" - } - }, - "http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } - }, - "http-status-codes": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/http-status-codes/-/http-status-codes-1.4.0.tgz", - "integrity": "sha512-JrT3ua+WgH8zBD3HEJYbeEgnuQaAnUeRRko/YojPAJjGmIfGD3KPU/asLdsLwKjfxOmQe5nXMQ0pt/7MyapVbQ==" - }, - "iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "requires": { - "safer-buffer": ">= 2.1.2 < 3" - } - }, - "import-local": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/import-local/-/import-local-2.0.0.tgz", - "integrity": "sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ==", - "dev": true, - "requires": { - "pkg-dir": "^3.0.0", - "resolve-cwd": "^2.0.0" - } - }, - "imurmurhash": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", - "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", - "dev": true - }, - "inflation": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/inflation/-/inflation-2.0.0.tgz", - "integrity": "sha1-i0F+R8KPklpFEz2RTKH9OJEH8w8=" - }, - "inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "ini": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", - "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==" - }, - "invariant": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", - "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", - "dev": true, - "requires": { - "loose-envify": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", - "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - } - }, - "is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "is-buffer": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", - "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" - }, - "is-callable": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.4.tgz", - "integrity": "sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA==", - "dev": true - }, - "is-ci": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz", - "integrity": "sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w==", - "dev": true, - "requires": { - "ci-info": "^2.0.0" - } - }, - "is-data-descriptor": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", - "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - } - }, - "is-date-object": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.1.tgz", - "integrity": "sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY=", - "dev": true - }, - "is-descriptor": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", - "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", - "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", - "dev": true - } - } - }, - "is-extendable": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", - "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=" - }, - "is-fullwidth-code-point": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", - "integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8=", - "dev": true - }, - "is-generator-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", - "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", - "dev": true - }, - "is-generator-function": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.7.tgz", - "integrity": "sha512-YZc5EwyO4f2kWCax7oegfuSr9mFz1ZvieNYBEjmukLxgXfBUbxAWGVF7GZf0zidYtoBl3WvC07YK0wT76a+Rtw==" - }, - "is-number": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", - "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - } - }, - "is-plain-object": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", - "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, - "is-regex": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.4.tgz", - "integrity": "sha1-VRdIm1RwkbCTDglWVM7SXul+lJE=", - "dev": true, - "requires": { - "has": "^1.0.1" - } - }, - "is-stream": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", - "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=", - "dev": true - }, - "is-symbol": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", - "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", - "dev": true, - "requires": { - "has-symbols": "^1.0.0" - } - }, - "is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", - "dev": true - }, - "is-whitespace": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/is-whitespace/-/is-whitespace-0.3.0.tgz", - "integrity": "sha1-Fjnssb4DauxppUy7QBz77XEUq38=" - }, - "is-windows": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", - "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", - "dev": true - }, - "is-wsl": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", - "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", - "dev": true - }, - "isarray": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=" - }, - "isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "isobject": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", - "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", - "dev": true - }, - "isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", - "dev": true - }, - "istanbul-lib-coverage": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", - "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", - "dev": true - }, - "istanbul-lib-instrument": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-3.3.0.tgz", - "integrity": "sha512-5nnIN4vo5xQZHdXno/YDXJ0G+I3dAm4XgzfSVTPLQpj/zAV2dV6Juy0yaf10/zrJOJeHoN3fraFe+XRq2bFVZA==", - "dev": true, - "requires": { - "@babel/generator": "^7.4.0", - "@babel/parser": "^7.4.3", - "@babel/template": "^7.4.0", - "@babel/traverse": "^7.4.3", - "@babel/types": "^7.4.0", - "istanbul-lib-coverage": "^2.0.5", - "semver": "^6.0.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "istanbul-lib-report": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-2.0.8.tgz", - "integrity": "sha512-fHBeG573EIihhAblwgxrSenp0Dby6tJMFR/HvlerBsrCTD5bkUuoNtn3gVh29ZCS824cGGBPn7Sg7cNk+2xUsQ==", - "dev": true, - "requires": { - "istanbul-lib-coverage": "^2.0.5", - "make-dir": "^2.1.0", - "supports-color": "^6.1.0" - }, - "dependencies": { - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "istanbul-lib-source-maps": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz", - "integrity": "sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==", - "dev": true, - "requires": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^2.0.5", - "make-dir": "^2.1.0", - "rimraf": "^2.6.3", - "source-map": "^0.6.1" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "dev": true, - "requires": { - "ms": "^2.1.1" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true - } - } - }, - "istanbul-reports": { - "version": "2.2.6", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-2.2.6.tgz", - "integrity": "sha512-SKi4rnMyLBKe0Jy2uUdx28h8oG7ph2PPuQPvIAh31d+Ci+lSiEu4C+h3oBPuJ9+mPKhOyW0M8gY4U5NM1WLeXA==", - "dev": true, - "requires": { - "handlebars": "^4.1.2" - } - }, - "jest": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest/-/jest-24.9.0.tgz", - "integrity": "sha512-YvkBL1Zm7d2B1+h5fHEOdyjCG+sGMz4f8D86/0HiqJ6MB4MnDc8FgP5vdWsGnemOQro7lnYo8UakZ3+5A0jxGw==", - "dev": true, - "requires": { - "import-local": "^2.0.0", - "jest-cli": "^24.9.0" - }, - "dependencies": { - "jest-cli": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-24.9.0.tgz", - "integrity": "sha512-+VLRKyitT3BWoMeSUIHRxV/2g8y9gw91Jh5z2UmXZzkZKpbC08CSehVxgHUwTpy+HwGcns/tqafQDJW7imYvGg==", - "dev": true, - "requires": { - "@jest/core": "^24.9.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "chalk": "^2.0.1", - "exit": "^0.1.2", - "import-local": "^2.0.0", - "is-ci": "^2.0.0", - "jest-config": "^24.9.0", - "jest-util": "^24.9.0", - "jest-validate": "^24.9.0", - "prompts": "^2.0.1", - "realpath-native": "^1.1.0", - "yargs": "^13.3.0" - } - } - } - }, - "jest-changed-files": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-24.9.0.tgz", - "integrity": "sha512-6aTWpe2mHF0DhL28WjdkO8LyGjs3zItPET4bMSeXU6T3ub4FPMw+mcOcbdGXQOAfmLcxofD23/5Bl9Z4AkFwqg==", - "dev": true, - "requires": { - "@jest/types": "^24.9.0", - "execa": "^1.0.0", - "throat": "^4.0.0" - } - }, - "jest-config": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-24.9.0.tgz", - "integrity": "sha512-RATtQJtVYQrp7fvWg6f5y3pEFj9I+H8sWw4aKxnDZ96mob5i5SD6ZEGWgMLXQ4LE8UurrjbdlLWdUeo+28QpfQ==", - "dev": true, - "requires": { - "@babel/core": "^7.1.0", - "@jest/test-sequencer": "^24.9.0", - "@jest/types": "^24.9.0", - "babel-jest": "^24.9.0", - "chalk": "^2.0.1", - "glob": "^7.1.1", - "jest-environment-jsdom": "^24.9.0", - "jest-environment-node": "^24.9.0", - "jest-get-type": "^24.9.0", - "jest-jasmine2": "^24.9.0", - "jest-regex-util": "^24.3.0", - "jest-resolve": "^24.9.0", - "jest-util": "^24.9.0", - "jest-validate": "^24.9.0", - "micromatch": "^3.1.10", - "pretty-format": "^24.9.0", - "realpath-native": "^1.1.0" - } - }, - "jest-diff": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-24.9.0.tgz", - "integrity": "sha512-qMfrTs8AdJE2iqrTp0hzh7kTd2PQWrsFyj9tORoKmu32xjPjeE4NyjVRDz8ybYwqS2ik8N4hsIpiVTyFeo2lBQ==", - "dev": true, - "requires": { - "chalk": "^2.0.1", - "diff-sequences": "^24.9.0", - "jest-get-type": "^24.9.0", - "pretty-format": "^24.9.0" - } - }, - "jest-docblock": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-24.9.0.tgz", - "integrity": "sha512-F1DjdpDMJMA1cN6He0FNYNZlo3yYmOtRUnktrT9Q37njYzC5WEaDdmbynIgy0L/IvXvvgsG8OsqhLPXTpfmZAA==", - "dev": true, - "requires": { - "detect-newline": "^2.1.0" - } - }, - "jest-each": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-24.9.0.tgz", - "integrity": "sha512-ONi0R4BvW45cw8s2Lrx8YgbeXL1oCQ/wIDwmsM3CqM/nlblNCPmnC3IPQlMbRFZu3wKdQ2U8BqM6lh3LJ5Bsog==", - "dev": true, - "requires": { - "@jest/types": "^24.9.0", - "chalk": "^2.0.1", - "jest-get-type": "^24.9.0", - "jest-util": "^24.9.0", - "pretty-format": "^24.9.0" - } - }, - "jest-environment-jsdom": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-24.9.0.tgz", - "integrity": "sha512-Zv9FV9NBRzLuALXjvRijO2351DRQeLYXtpD4xNvfoVFw21IOKNhZAEUKcbiEtjTkm2GsJ3boMVgkaR7rN8qetA==", - "dev": true, - "requires": { - "@jest/environment": "^24.9.0", - "@jest/fake-timers": "^24.9.0", - "@jest/types": "^24.9.0", - "jest-mock": "^24.9.0", - "jest-util": "^24.9.0", - "jsdom": "^11.5.1" - } - }, - "jest-environment-node": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-24.9.0.tgz", - "integrity": "sha512-6d4V2f4nxzIzwendo27Tr0aFm+IXWa0XEUnaH6nU0FMaozxovt+sfRvh4J47wL1OvF83I3SSTu0XK+i4Bqe7uA==", - "dev": true, - "requires": { - "@jest/environment": "^24.9.0", - "@jest/fake-timers": "^24.9.0", - "@jest/types": "^24.9.0", - "jest-mock": "^24.9.0", - "jest-util": "^24.9.0" - } - }, - "jest-get-type": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-24.9.0.tgz", - "integrity": "sha512-lUseMzAley4LhIcpSP9Jf+fTrQ4a1yHQwLNeeVa2cEmbCGeoZAtYPOIv8JaxLD/sUpKxetKGP+gsHl8f8TSj8Q==", - "dev": true - }, - "jest-haste-map": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-24.9.0.tgz", - "integrity": "sha512-kfVFmsuWui2Sj1Rp1AJ4D9HqJwE4uwTlS/vO+eRUaMmd54BFpli2XhMQnPC2k4cHFVbB2Q2C+jtI1AGLgEnCjQ==", - "dev": true, - "requires": { - "@jest/types": "^24.9.0", - "anymatch": "^2.0.0", - "fb-watchman": "^2.0.0", - "fsevents": "^1.2.7", - "graceful-fs": "^4.1.15", - "invariant": "^2.2.4", - "jest-serializer": "^24.9.0", - "jest-util": "^24.9.0", - "jest-worker": "^24.9.0", - "micromatch": "^3.1.10", - "sane": "^4.0.3", - "walker": "^1.0.7" - } - }, - "jest-jasmine2": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-24.9.0.tgz", - "integrity": "sha512-Cq7vkAgaYKp+PsX+2/JbTarrk0DmNhsEtqBXNwUHkdlbrTBLtMJINADf2mf5FkowNsq8evbPc07/qFO0AdKTzw==", - "dev": true, - "requires": { - "@babel/traverse": "^7.1.0", - "@jest/environment": "^24.9.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "chalk": "^2.0.1", - "co": "^4.6.0", - "expect": "^24.9.0", - "is-generator-fn": "^2.0.0", - "jest-each": "^24.9.0", - "jest-matcher-utils": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-runtime": "^24.9.0", - "jest-snapshot": "^24.9.0", - "jest-util": "^24.9.0", - "pretty-format": "^24.9.0", - "throat": "^4.0.0" - } - }, - "jest-leak-detector": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-24.9.0.tgz", - "integrity": "sha512-tYkFIDsiKTGwb2FG1w8hX9V0aUb2ot8zY/2nFg087dUageonw1zrLMP4W6zsRO59dPkTSKie+D4rhMuP9nRmrA==", - "dev": true, - "requires": { - "jest-get-type": "^24.9.0", - "pretty-format": "^24.9.0" - } - }, - "jest-matcher-utils": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-24.9.0.tgz", - "integrity": "sha512-OZz2IXsu6eaiMAwe67c1T+5tUAtQyQx27/EMEkbFAGiw52tB9em+uGbzpcgYVpA8wl0hlxKPZxrly4CXU/GjHA==", - "dev": true, - "requires": { - "chalk": "^2.0.1", - "jest-diff": "^24.9.0", - "jest-get-type": "^24.9.0", - "pretty-format": "^24.9.0" - } - }, - "jest-message-util": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-24.9.0.tgz", - "integrity": "sha512-oCj8FiZ3U0hTP4aSui87P4L4jC37BtQwUMqk+zk/b11FR19BJDeZsZAvIHutWnmtw7r85UmR3CEWZ0HWU2mAlw==", - "dev": true, - "requires": { - "@babel/code-frame": "^7.0.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/stack-utils": "^1.0.1", - "chalk": "^2.0.1", - "micromatch": "^3.1.10", - "slash": "^2.0.0", - "stack-utils": "^1.0.1" - } - }, - "jest-mock": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-24.9.0.tgz", - "integrity": "sha512-3BEYN5WbSq9wd+SyLDES7AHnjH9A/ROBwmz7l2y+ol+NtSFO8DYiEBzoO1CeFc9a8DYy10EO4dDFVv/wN3zl1w==", - "dev": true, - "requires": { - "@jest/types": "^24.9.0" - } - }, - "jest-pnp-resolver": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.1.tgz", - "integrity": "sha512-pgFw2tm54fzgYvc/OHrnysABEObZCUNFnhjoRjaVOCN8NYc032/gVjPaHD4Aq6ApkSieWtfKAFQtmDKAmhupnQ==", - "dev": true - }, - "jest-regex-util": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-24.9.0.tgz", - "integrity": "sha512-05Cmb6CuxaA+Ys6fjr3PhvV3bGQmO+2p2La4hFbU+W5uOc479f7FdLXUWXw4pYMAhhSZIuKHwSXSu6CsSBAXQA==", - "dev": true - }, - "jest-resolve": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-24.9.0.tgz", - "integrity": "sha512-TaLeLVL1l08YFZAt3zaPtjiVvyy4oSA6CRe+0AFPPVX3Q/VI0giIWWoAvoS5L96vj9Dqxj4fB5p2qrHCmTU/MQ==", - "dev": true, - "requires": { - "@jest/types": "^24.9.0", - "browser-resolve": "^1.11.3", - "chalk": "^2.0.1", - "jest-pnp-resolver": "^1.2.1", - "realpath-native": "^1.1.0" - } - }, - "jest-resolve-dependencies": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-24.9.0.tgz", - "integrity": "sha512-Fm7b6AlWnYhT0BXy4hXpactHIqER7erNgIsIozDXWl5dVm+k8XdGVe1oTg1JyaFnOxarMEbax3wyRJqGP2Pq+g==", - "dev": true, - "requires": { - "@jest/types": "^24.9.0", - "jest-regex-util": "^24.3.0", - "jest-snapshot": "^24.9.0" - } - }, - "jest-runner": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-24.9.0.tgz", - "integrity": "sha512-KksJQyI3/0mhcfspnxxEOBueGrd5E4vV7ADQLT9ESaCzz02WnbdbKWIf5Mkaucoaj7obQckYPVX6JJhgUcoWWg==", - "dev": true, - "requires": { - "@jest/console": "^24.7.1", - "@jest/environment": "^24.9.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "chalk": "^2.4.2", - "exit": "^0.1.2", - "graceful-fs": "^4.1.15", - "jest-config": "^24.9.0", - "jest-docblock": "^24.3.0", - "jest-haste-map": "^24.9.0", - "jest-jasmine2": "^24.9.0", - "jest-leak-detector": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-resolve": "^24.9.0", - "jest-runtime": "^24.9.0", - "jest-util": "^24.9.0", - "jest-worker": "^24.6.0", - "source-map-support": "^0.5.6", - "throat": "^4.0.0" - } - }, - "jest-runtime": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-24.9.0.tgz", - "integrity": "sha512-8oNqgnmF3v2J6PVRM2Jfuj8oX3syKmaynlDMMKQ4iyzbQzIG6th5ub/lM2bCMTmoTKM3ykcUYI2Pw9xwNtjMnw==", - "dev": true, - "requires": { - "@jest/console": "^24.7.1", - "@jest/environment": "^24.9.0", - "@jest/source-map": "^24.3.0", - "@jest/transform": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/yargs": "^13.0.0", - "chalk": "^2.0.1", - "exit": "^0.1.2", - "glob": "^7.1.3", - "graceful-fs": "^4.1.15", - "jest-config": "^24.9.0", - "jest-haste-map": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-mock": "^24.9.0", - "jest-regex-util": "^24.3.0", - "jest-resolve": "^24.9.0", - "jest-snapshot": "^24.9.0", - "jest-util": "^24.9.0", - "jest-validate": "^24.9.0", - "realpath-native": "^1.1.0", - "slash": "^2.0.0", - "strip-bom": "^3.0.0", - "yargs": "^13.3.0" - } - }, - "jest-serializer": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-serializer/-/jest-serializer-24.9.0.tgz", - "integrity": "sha512-DxYipDr8OvfrKH3Kel6NdED3OXxjvxXZ1uIY2I9OFbGg+vUkkg7AGvi65qbhbWNPvDckXmzMPbK3u3HaDO49bQ==", - "dev": true - }, - "jest-snapshot": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-24.9.0.tgz", - "integrity": "sha512-uI/rszGSs73xCM0l+up7O7a40o90cnrk429LOiK3aeTvfC0HHmldbd81/B7Ix81KSFe1lwkbl7GnBGG4UfuDew==", - "dev": true, - "requires": { - "@babel/types": "^7.0.0", - "@jest/types": "^24.9.0", - "chalk": "^2.0.1", - "expect": "^24.9.0", - "jest-diff": "^24.9.0", - "jest-get-type": "^24.9.0", - "jest-matcher-utils": "^24.9.0", - "jest-message-util": "^24.9.0", - "jest-resolve": "^24.9.0", - "mkdirp": "^0.5.1", - "natural-compare": "^1.4.0", - "pretty-format": "^24.9.0", - "semver": "^6.2.0" - }, - "dependencies": { - "semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "dev": true - } - } - }, - "jest-util": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-24.9.0.tgz", - "integrity": "sha512-x+cZU8VRmOJxbA1K5oDBdxQmdq0OIdADarLxk0Mq+3XS4jgvhG/oKGWcIDCtPG0HgjxOYvF+ilPJQsAyXfbNOg==", - "dev": true, - "requires": { - "@jest/console": "^24.9.0", - "@jest/fake-timers": "^24.9.0", - "@jest/source-map": "^24.9.0", - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "callsites": "^3.0.0", - "chalk": "^2.0.1", - "graceful-fs": "^4.1.15", - "is-ci": "^2.0.0", - "mkdirp": "^0.5.1", - "slash": "^2.0.0", - "source-map": "^0.6.0" - } - }, - "jest-validate": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-24.9.0.tgz", - "integrity": "sha512-HPIt6C5ACwiqSiwi+OfSSHbK8sG7akG8eATl+IPKaeIjtPOeBUd/g3J7DghugzxrGjI93qS/+RPKe1H6PqvhRQ==", - "dev": true, - "requires": { - "@jest/types": "^24.9.0", - "camelcase": "^5.3.1", - "chalk": "^2.0.1", - "jest-get-type": "^24.9.0", - "leven": "^3.1.0", - "pretty-format": "^24.9.0" - } - }, - "jest-watcher": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-24.9.0.tgz", - "integrity": "sha512-+/fLOfKPXXYJDYlks62/4R4GoT+GU1tYZed99JSCOsmzkkF7727RqKrjNAxtfO4YpGv11wybgRvCjR73lK2GZw==", - "dev": true, - "requires": { - "@jest/test-result": "^24.9.0", - "@jest/types": "^24.9.0", - "@types/yargs": "^13.0.0", - "ansi-escapes": "^3.0.0", - "chalk": "^2.0.1", - "jest-util": "^24.9.0", - "string-length": "^2.0.0" - } - }, - "jest-worker": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-24.9.0.tgz", - "integrity": "sha512-51PE4haMSXcHohnSMdM42anbvZANYTqMrr52tVKPqqsPJMzoP6FYYDVqahX/HrAoKEKz3uUPzSvKs9A3qR4iVw==", - "dev": true, - "requires": { - "merge-stream": "^2.0.0", - "supports-color": "^6.1.0" - }, - "dependencies": { - "supports-color": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", - "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - } - } - }, - "js-beautify": { - "version": "1.10.2", - "resolved": "https://registry.npmjs.org/js-beautify/-/js-beautify-1.10.2.tgz", - "integrity": "sha512-ZtBYyNUYJIsBWERnQP0rPN9KjkrDfJcMjuVGcvXOUJrD1zmOGwhRwQ4msG+HJ+Ni/FA7+sRQEMYVzdTQDvnzvQ==", - "requires": { - "config-chain": "^1.1.12", - "editorconfig": "^0.15.3", - "glob": "^7.1.3", - "mkdirp": "~0.5.1", - "nopt": "~4.0.1" - } - }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", - "dev": true - }, - "jsdom": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-11.12.0.tgz", - "integrity": "sha512-y8Px43oyiBM13Zc1z780FrfNLJCXTL40EWlty/LXUtcjykRBNgLlCjWXpfSPBl2iv+N7koQN+dvqszHZgT/Fjw==", - "dev": true, - "requires": { - "abab": "^2.0.0", - "acorn": "^5.5.3", - "acorn-globals": "^4.1.0", - "array-equal": "^1.0.0", - "cssom": ">= 0.3.2 < 0.4.0", - "cssstyle": "^1.0.0", - "data-urls": "^1.0.0", - "domexception": "^1.0.1", - "escodegen": "^1.9.1", - "html-encoding-sniffer": "^1.0.2", - "left-pad": "^1.3.0", - "nwsapi": "^2.0.7", - "parse5": "4.0.0", - "pn": "^1.1.0", - "request": "^2.87.0", - "request-promise-native": "^1.0.5", - "sax": "^1.2.4", - "symbol-tree": "^3.2.2", - "tough-cookie": "^2.3.4", - "w3c-hr-time": "^1.0.1", - "webidl-conversions": "^4.0.2", - "whatwg-encoding": "^1.0.3", - "whatwg-mimetype": "^2.1.0", - "whatwg-url": "^6.4.1", - "ws": "^5.2.0", - "xml-name-validator": "^3.0.0" - } - }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true - }, - "json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true - }, - "json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", - "dev": true - }, - "json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", - "dev": true - }, - "json5": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/json5/-/json5-2.1.1.tgz", - "integrity": "sha512-l+3HXD0GEI3huGq1njuqtzYK8OYJyXMkOLtQ53pjWh89tvWS2h6l+1zMkYWqlb57+SiQodKZyvMEFb2X+KrFhQ==", - "dev": true, - "requires": { - "minimist": "^1.2.0" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - } - } - }, - "jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", - "dev": true, - "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.2.3", - "verror": "1.10.0" - } - }, - "keygrip": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/keygrip/-/keygrip-1.1.0.tgz", - "integrity": "sha512-iYSchDJ+liQ8iwbSI2QqsQOvqv58eJCEanyJPJi+Khyu8smkcKSFUCbPwzFcL7YVtZ6eONjqRX/38caJ7QjRAQ==", - "requires": { - "tsscmp": "1.0.6" - } - }, - "kind-of": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", - "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", - "requires": { - "is-buffer": "^1.1.5" - } - }, - "kleur": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", - "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", - "dev": true - }, - "koa": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/koa/-/koa-2.11.0.tgz", - "integrity": "sha512-EpR9dElBTDlaDgyhDMiLkXrPwp6ZqgAIBvhhmxQ9XN4TFgW+gEz6tkcsNI6BnUbUftrKDjVFj4lW2/J2aNBMMA==", - "requires": { - "accepts": "^1.3.5", - "cache-content-type": "^1.0.0", - "content-disposition": "~0.5.2", - "content-type": "^1.0.4", - "cookies": "~0.8.0", - "debug": "~3.1.0", - "delegates": "^1.0.0", - "depd": "^1.1.2", - "destroy": "^1.0.4", - "encodeurl": "^1.0.2", - "error-inject": "^1.0.0", - "escape-html": "^1.0.3", - "fresh": "~0.5.2", - "http-assert": "^1.3.0", - "http-errors": "^1.6.3", - "is-generator-function": "^1.0.7", - "koa-compose": "^4.1.0", - "koa-convert": "^1.2.0", - "on-finished": "^2.3.0", - "only": "~0.0.2", - "parseurl": "^1.3.2", - "statuses": "^1.5.0", - "type-is": "^1.6.16", - "vary": "^1.1.2" - } - }, - "koa-bodyparser": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/koa-bodyparser/-/koa-bodyparser-4.2.1.tgz", - "integrity": "sha512-UIjPAlMZfNYDDe+4zBaOAUKYqkwAGcIU6r2ARf1UOXPAlfennQys5IiShaVeNf7KkVBlf88f2LeLvBFvKylttw==", - "requires": { - "co-body": "^6.0.0", - "copy-to": "^2.0.1" - }, - "dependencies": { - "co-body": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/co-body/-/co-body-6.0.0.tgz", - "integrity": "sha512-9ZIcixguuuKIptnY8yemEOuhb71L/lLf+Rl5JfJEUiDNJk0e02MBt7BPxR2GEh5mw8dPthQYR4jPI/BnS1MQgw==", - "requires": { - "inflation": "^2.0.0", - "qs": "^6.5.2", - "raw-body": "^2.3.3", - "type-is": "^1.6.16" - } - } - } - }, - "koa-compose": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/koa-compose/-/koa-compose-4.1.0.tgz", - "integrity": "sha512-8ODW8TrDuMYvXRwra/Kh7/rJo9BtOfPc6qO8eAfC80CnCvSjSl0bkRM24X6/XBBEyj0v1nRUQ1LyOy3dbqOWXw==" - }, - "koa-convert": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/koa-convert/-/koa-convert-1.2.0.tgz", - "integrity": "sha1-2kCHXfSd4FOQmNFwC1CCDOvNIdA=", - "requires": { - "co": "^4.6.0", - "koa-compose": "^3.0.0" - }, - "dependencies": { - "koa-compose": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/koa-compose/-/koa-compose-3.2.1.tgz", - "integrity": "sha1-qFzLQLfZhtjlo0Wzoazo6rz1Tec=", - "requires": { - "any-promise": "^1.1.0" - } - } - } - }, - "koa-router": { - "version": "7.4.0", - "resolved": "https://registry.npmjs.org/koa-router/-/koa-router-7.4.0.tgz", - "integrity": "sha512-IWhaDXeAnfDBEpWS6hkGdZ1ablgr6Q6pGdXCyK38RbzuH4LkUOpPqPw+3f8l8aTDrQmBQ7xJc0bs2yV4dzcO+g==", - "requires": { - "debug": "^3.1.0", - "http-errors": "^1.3.1", - "koa-compose": "^3.0.0", - "methods": "^1.0.1", - "path-to-regexp": "^1.1.1", - "urijs": "^1.19.0" - }, - "dependencies": { - "koa-compose": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/koa-compose/-/koa-compose-3.2.1.tgz", - "integrity": "sha1-qFzLQLfZhtjlo0Wzoazo6rz1Tec=", - "requires": { - "any-promise": "^1.1.0" - } - } - } - }, - "koa-send": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/koa-send/-/koa-send-5.0.0.tgz", - "integrity": "sha512-90ZotV7t0p3uN9sRwW2D484rAaKIsD8tAVtypw/aBU+ryfV+fR2xrcAwhI8Wl6WRkojLUs/cB9SBSCuIb+IanQ==", - "requires": { - "debug": "^3.1.0", - "http-errors": "^1.6.3", - "mz": "^2.7.0", - "resolve-path": "^1.4.0" - } - }, - "koa-views": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/koa-views/-/koa-views-6.2.1.tgz", - "integrity": "sha512-wU3tw48KuskaJg0x1JZmC73UWGgVmh6B54HuHDzTrkavig+dBI0NbFeGiWsaOCZREQkaTfIVXSPSByDant71ew==", - "requires": { - "consolidate": "0.15.1", - "debug": "^4.1.0", - "get-paths": "0.0.7", - "koa-send": "^5.0.0", - "mz": "^2.4.0", - "pretty": "^2.0.0" - }, - "dependencies": { - "debug": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.1.1.tgz", - "integrity": "sha512-pYAIzeRo8J6KPEaJ0VWOh5Pzkbw/RetuzehGM7QRRX5he4fPHx2rdKMB256ehJCkX+XRQm16eZLqLNS8RSZXZw==", - "requires": { - "ms": "^2.1.1" - } - }, - "ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" - } - } - }, - "left-pad": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/left-pad/-/left-pad-1.3.0.tgz", - "integrity": "sha512-XI5MPzVNApjAyhQzphX8BkmKsKUxD4LdyK24iZeQGinBN9yTQT3bFlCBy/aVx2HrNcqQGsdot8ghrjyrvMCoEA==", - "dev": true - }, - "leven": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", - "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", - "dev": true - }, - "levn": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz", - "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2" - } - }, - "load-json-file": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", - "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" - }, - "dependencies": { - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - } - } - }, - "locate-path": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", - "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", - "dev": true, - "requires": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" - } - }, - "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", - "dev": true - }, - "lodash.sortby": { - "version": "4.7.0", - "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", - "integrity": "sha1-7dFMgk4sycHgsKG0K7UhBRakJDg=", - "dev": true - }, - "loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dev": true, - "requires": { - "js-tokens": "^3.0.0 || ^4.0.0" - } - }, - "lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - }, - "make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", - "dev": true, - "requires": { - "pify": "^4.0.1", - "semver": "^5.6.0" - } - }, - "makeerror": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz", - "integrity": "sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw=", - "dev": true, - "requires": { - "tmpl": "1.0.x" - } - }, - "map-cache": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", - "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", - "dev": true - }, - "map-visit": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", - "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", - "dev": true, - "requires": { - "object-visit": "^1.0.0" - } - }, - "media-typer": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", - "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" - }, - "merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" - }, - "micromatch": { - "version": "3.1.10", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", - "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - }, - "dependencies": { - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - } - }, - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - } - } - }, - "mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true - }, - "mime-db": { - "version": "1.40.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", - "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==" - }, - "mime-types": { - "version": "2.1.24", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", - "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", - "requires": { - "mime-db": "1.40.0" - } - }, - "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=" - }, - "mixin-deep": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", - "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", - "dev": true, - "requires": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", - "requires": { - "minimist": "0.0.8" - } - }, - "mock-fs": { - "version": "4.10.3", - "resolved": "https://registry.npmjs.org/mock-fs/-/mock-fs-4.10.3.tgz", - "integrity": "sha512-bcukePBvuA3qovmq0Qtqu9+1APCIGkFHnsozrPIVromt5XFGGgkQSfaN0H6RI8gStHkO/hRgimvS3tooNes4pQ==", - "dev": true - }, - "ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" - }, - "mz": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", - "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", - "requires": { - "any-promise": "^1.0.0", - "object-assign": "^4.0.1", - "thenify-all": "^1.0.0" - } - }, - "nan": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", - "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", - "dev": true, - "optional": true - }, - "nanomatch": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", - "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - } - }, - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - } - } - }, - "natural-compare": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", - "dev": true - }, - "negotiator": { - "version": "0.6.2", - "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", - "integrity": "sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw==" - }, - "neo-async": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", - "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==", - "dev": true - }, - "nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true - }, - "node-int64": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", - "integrity": "sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs=", - "dev": true - }, - "node-modules-regexp": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz", - "integrity": "sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA=", - "dev": true - }, - "node-notifier": { - "version": "5.4.3", - "resolved": "https://registry.npmjs.org/node-notifier/-/node-notifier-5.4.3.tgz", - "integrity": "sha512-M4UBGcs4jeOK9CjTsYwkvH6/MzuUmGCyTW+kCY7uO+1ZVr0+FHGdPdIf5CCLqAaxnRrWidyoQlNkMIIVwbKB8Q==", - "dev": true, - "requires": { - "growly": "^1.3.0", - "is-wsl": "^1.1.0", - "semver": "^5.5.0", - "shellwords": "^0.1.1", - "which": "^1.3.0" - } - }, - "nopt": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", - "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", - "requires": { - "abbrev": "1", - "osenv": "^0.1.4" - } - }, - "normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "requires": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "normalize-path": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", - "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", - "dev": true, - "requires": { - "remove-trailing-separator": "^1.0.1" - } - }, - "npm-run-path": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", - "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=", - "dev": true, - "requires": { - "path-key": "^2.0.0" - } - }, - "nwsapi": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz", - "integrity": "sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==", - "dev": true - }, - "oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "dev": true - }, - "object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" - }, - "object-copy": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", - "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", - "dev": true, - "requires": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, - "object-inspect": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.6.0.tgz", - "integrity": "sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ==", - "dev": true - }, - "object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true - }, - "object-visit": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", - "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", - "dev": true, - "requires": { - "isobject": "^3.0.0" - } - }, - "object.getownpropertydescriptors": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz", - "integrity": "sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY=", - "dev": true, - "requires": { - "define-properties": "^1.1.2", - "es-abstract": "^1.5.1" - } - }, - "object.pick": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", - "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", - "dev": true, - "requires": { - "isobject": "^3.0.1" - } - }, - "on-finished": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", - "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", - "requires": { - "ee-first": "1.1.1" - } - }, - "once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "requires": { - "wrappy": "1" - } - }, - "only": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/only/-/only-0.0.2.tgz", - "integrity": "sha1-Kv3oTQPlC5qO3EROMGEKcCle37Q=" - }, - "optimist": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", - "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=", - "dev": true, - "requires": { - "minimist": "~0.0.1", - "wordwrap": "~0.0.2" - } - }, - "optionator": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz", - "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=", - "dev": true, - "requires": { - "deep-is": "~0.1.3", - "fast-levenshtein": "~2.0.4", - "levn": "~0.3.0", - "prelude-ls": "~1.1.2", - "type-check": "~0.3.2", - "wordwrap": "~1.0.0" - }, - "dependencies": { - "wordwrap": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz", - "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=", - "dev": true - } - } - }, - "os-homedir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=" - }, - "os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=" - }, - "osenv": { - "version": "0.1.5", - "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", - "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", - "requires": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" - } - }, - "p-each-series": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-each-series/-/p-each-series-1.0.0.tgz", - "integrity": "sha1-kw89Et0fUOdDRFeiLNbwSsatf3E=", - "dev": true, - "requires": { - "p-reduce": "^1.0.0" - } - }, - "p-finally": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", - "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=", - "dev": true - }, - "p-limit": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", - "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", - "dev": true, - "requires": { - "p-try": "^2.0.0" - } - }, - "p-locate": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", - "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", - "dev": true, - "requires": { - "p-limit": "^2.0.0" - } - }, - "p-reduce": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/p-reduce/-/p-reduce-1.0.0.tgz", - "integrity": "sha1-GMKw3ZNqRpClKfgjH1ig/bakffo=", - "dev": true - }, - "p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", - "dev": true, - "requires": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - } - }, - "parse5": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-4.0.0.tgz", - "integrity": "sha512-VrZ7eOd3T1Fk4XWNXMgiGBK/z0MG48BWG2uQNU4I72fkQuKUTZpl+u9k+CxEG0twMVzSmXEEz12z5Fnw1jIQFA==", - "dev": true - }, - "parseurl": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", - "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" - }, - "pascalcase": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", - "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", - "dev": true - }, - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - }, - "path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" - }, - "path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true - }, - "path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", - "dev": true - }, - "path-to-regexp": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz", - "integrity": "sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=", - "requires": { - "isarray": "0.0.1" - } - }, - "path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", - "dev": true, - "requires": { - "pify": "^3.0.0" - }, - "dependencies": { - "pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - } - } - }, - "performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", - "dev": true - }, - "pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==" - }, - "pirates": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz", - "integrity": "sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA==", - "dev": true, - "requires": { - "node-modules-regexp": "^1.0.0" - } - }, - "pkg-dir": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", - "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", - "dev": true, - "requires": { - "find-up": "^3.0.0" - } - }, - "pn": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/pn/-/pn-1.1.0.tgz", - "integrity": "sha512-2qHaIQr2VLRFoxe2nASzsV6ef4yOOH+Fi9FBOVH6cqeSgUnoyySPZkxzLuzd+RYOQTRpROA0ztTMqxROKSb/nA==", - "dev": true - }, - "posix-character-classes": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", - "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", - "dev": true - }, - "prelude-ls": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz", - "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ=", - "dev": true - }, - "pretty": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/pretty/-/pretty-2.0.0.tgz", - "integrity": "sha1-rbx5YLe7/iiaVX3F9zdhmiINBqU=", - "requires": { - "condense-newlines": "^0.2.1", - "extend-shallow": "^2.0.1", - "js-beautify": "^1.6.12" - } - }, - "pretty-format": { - "version": "24.9.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-24.9.0.tgz", - "integrity": "sha512-00ZMZUiHaJrNfk33guavqgvfJS30sLYf0f8+Srklv0AMPodGGHcoHgksZ3OThYnIvOd+8yMCn0YiEOogjlgsnA==", - "dev": true, - "requires": { - "@jest/types": "^24.9.0", - "ansi-regex": "^4.0.0", - "ansi-styles": "^3.2.0", - "react-is": "^16.8.4" - } - }, - "process-nextick-args": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", - "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", - "dev": true - }, - "prompts": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.2.1.tgz", - "integrity": "sha512-VObPvJiWPhpZI6C5m60XOzTfnYg/xc/an+r9VYymj9WJW3B/DIH+REzjpAACPf8brwPeP+7vz3bIim3S+AaMjw==", - "dev": true, - "requires": { - "kleur": "^3.0.3", - "sisteransi": "^1.0.3" - } - }, - "proto-list": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/proto-list/-/proto-list-1.2.4.tgz", - "integrity": "sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk=" - }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=" - }, - "psl": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.4.0.tgz", - "integrity": "sha512-HZzqCGPecFLyoRj5HLfuDSKYTJkAfB5thKBIkRHtGjWwY7p1dAyveIbXIq4tO0KYfDF2tHqPUgY9SDnGm00uFw==", - "dev": true - }, - "pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "requires": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "punycode": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", - "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", - "dev": true - }, - "qs": { - "version": "6.9.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.9.0.tgz", - "integrity": "sha512-27RP4UotQORTpmNQDX8BHPukOnBP3p1uUJY5UnDhaJB+rMt9iMsok724XL+UHU23bEFOHRMQ2ZhI99qOWUMGFA==" - }, - "raw-body": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.4.1.tgz", - "integrity": "sha512-9WmIKF6mkvA0SLmA2Knm9+qj89e+j1zqgyn8aXGd7+nAduPoqgI9lO57SAZNn/Byzo5P7JhXTyg9PzaJbH73bA==", - "requires": { - "bytes": "3.1.0", - "http-errors": "1.7.3", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" - } - }, - "react-is": { - "version": "16.11.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.11.0.tgz", - "integrity": "sha512-gbBVYR2p8mnriqAwWx9LbuUrShnAuSCNnuPGyc7GJrMVQtPDAh8iLpv7FRuMPFb56KkaVZIYSz1PrjI9q0QPCw==", - "dev": true - }, - "read-pkg": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", - "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", - "dev": true, - "requires": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" - } - }, - "read-pkg-up": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-4.0.0.tgz", - "integrity": "sha512-6etQSH7nJGsK0RbG/2TeDzZFa8shjQ1um+SwQQ5cwKy0dhSXdOncEhb1CPpvQG4h7FyOV6EB6YlV0yJvZQNAkA==", - "dev": true, - "requires": { - "find-up": "^3.0.0", - "read-pkg": "^3.0.0" - } - }, - "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", - "dev": true, - "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - }, - "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - } - } - }, - "realpath-native": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/realpath-native/-/realpath-native-1.1.0.tgz", - "integrity": "sha512-wlgPA6cCIIg9gKz0fgAPjnzh4yR/LnXovwuo9hvyGvx3h8nX4+/iLZplfUWasXpqD8BdnGnP5njOFjkUwPzvjA==", - "dev": true, - "requires": { - "util.promisify": "^1.0.0" - } - }, - "regex-not": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", - "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", - "dev": true, - "requires": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - } - }, - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "remove-trailing-separator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", - "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", - "dev": true - }, - "repeat-element": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", - "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", - "dev": true - }, - "repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", - "dev": true - }, - "request": { - "version": "2.88.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", - "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", - "dev": true, - "requires": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.0", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.4.3", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "dependencies": { - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", - "dev": true - }, - "qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", - "dev": true - }, - "tough-cookie": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", - "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", - "dev": true, - "requires": { - "psl": "^1.1.24", - "punycode": "^1.4.1" - } - } - } - }, - "request-promise-core": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.3.tgz", - "integrity": "sha512-QIs2+ArIGQVp5ZYbWD5ZLCY29D5CfWizP8eWnm8FoGD1TX61veauETVQbrV60662V0oFBkrDOuaBI8XgtuyYAQ==", - "dev": true, - "requires": { - "lodash": "^4.17.15" - } - }, - "request-promise-native": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.8.tgz", - "integrity": "sha512-dapwLGqkHtwL5AEbfenuzjTYg35Jd6KPytsC2/TLkVMz8rm+tNt72MGUWT1RP/aYawMpN6HqbNGBQaRcBtjQMQ==", - "dev": true, - "requires": { - "request-promise-core": "1.1.3", - "stealthy-require": "^1.1.1", - "tough-cookie": "^2.3.3" - } - }, - "require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true - }, - "require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true - }, - "resolve": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", - "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==", - "dev": true, - "requires": { - "path-parse": "^1.0.6" - } - }, - "resolve-cwd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-2.0.0.tgz", - "integrity": "sha1-AKn3OHVW4nA46uIyyqNypqWbZlo=", - "dev": true, - "requires": { - "resolve-from": "^3.0.0" - } - }, - "resolve-from": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-3.0.0.tgz", - "integrity": "sha1-six699nWiBvItuZTM17rywoYh0g=", - "dev": true - }, - "resolve-path": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/resolve-path/-/resolve-path-1.4.0.tgz", - "integrity": "sha1-xL2p9e+y/OZSR4c6s2u02DT+Fvc=", - "requires": { - "http-errors": "~1.6.2", - "path-is-absolute": "1.0.1" - }, - "dependencies": { - "http-errors": { - "version": "1.6.3", - "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", - "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", - "requires": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.0", - "statuses": ">= 1.4.0 < 2" - } - }, - "inherits": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", - "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" - }, - "setprototypeof": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", - "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" - } - } - }, - "resolve-url": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", - "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", - "dev": true - }, - "ret": { - "version": "0.1.15", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", - "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", - "dev": true - }, - "rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "dev": true, - "requires": { - "glob": "^7.1.3" - } - }, - "rsvp": { - "version": "4.8.5", - "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz", - "integrity": "sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA==", - "dev": true - }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" - }, - "safe-regex": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", - "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", - "dev": true, - "requires": { - "ret": "~0.1.10" - } - }, - "safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" - }, - "sane": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/sane/-/sane-4.1.0.tgz", - "integrity": "sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA==", - "dev": true, - "requires": { - "@cnakazawa/watch": "^1.0.3", - "anymatch": "^2.0.0", - "capture-exit": "^2.0.0", - "exec-sh": "^0.3.2", - "execa": "^1.0.0", - "fb-watchman": "^2.0.0", - "micromatch": "^3.1.4", - "minimist": "^1.1.1", - "walker": "~1.0.5" - }, - "dependencies": { - "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", - "dev": true - } - } - }, - "sax": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", - "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", - "dev": true - }, - "semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==" - }, - "set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true - }, - "set-value": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", - "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" - } - }, - "setprototypeof": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.1.tgz", - "integrity": "sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw==" - }, - "shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "dev": true, - "requires": { - "shebang-regex": "^1.0.0" - } - }, - "shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "dev": true - }, - "shellwords": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz", - "integrity": "sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww==", - "dev": true - }, - "sigmund": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", - "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=" - }, - "signal-exit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", - "dev": true - }, - "sisteransi": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.3.tgz", - "integrity": "sha512-SbEG75TzH8G7eVXFSN5f9EExILKfly7SUvVY5DhhYLvfhKqhDFY0OzevWa/zwak0RLRfWS5AvfMWpd9gJvr5Yg==", - "dev": true - }, - "slash": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-2.0.0.tgz", - "integrity": "sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A==", - "dev": true - }, - "snapdragon": { - "version": "0.8.2", - "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", - "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", - "dev": true, - "requires": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "requires": { - "ms": "2.0.0" - } - }, - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", - "dev": true - } - } - }, - "snapdragon-node": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", - "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", - "dev": true, - "requires": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", - "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", - "dev": true, - "requires": { - "is-descriptor": "^1.0.0" - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", - "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", - "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", - "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "kind-of": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.2.tgz", - "integrity": "sha512-s5kLOcnH0XqDO+FvuaLX8DDjZ18CGFk7VygH40QoKPUQhW4e2rvM0rwUq0t8IQDOwYSeLK01U90OjzBTme2QqA==", - "dev": true - } - } - }, - "snapdragon-util": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", - "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", - "dev": true, - "requires": { - "kind-of": "^3.2.0" - } - }, - "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true - }, - "source-map-resolve": { - "version": "0.5.2", - "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", - "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", - "dev": true, - "requires": { - "atob": "^2.1.1", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" - } - }, - "source-map-support": { - "version": "0.5.16", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.16.tgz", - "integrity": "sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==", - "dev": true, - "requires": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "source-map-url": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", - "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", - "dev": true - }, - "spdx-correct": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", - "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", - "dev": true, - "requires": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-exceptions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", - "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", - "dev": true - }, - "spdx-expression-parse": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", - "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", - "dev": true, - "requires": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "spdx-license-ids": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", - "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", - "dev": true - }, - "split-string": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", - "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", - "dev": true, - "requires": { - "extend-shallow": "^3.0.0" - }, - "dependencies": { - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - } - }, - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "sshpk": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", - "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", - "dev": true, - "requires": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - } - }, - "stack-utils": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-1.0.2.tgz", - "integrity": "sha512-MTX+MeG5U994cazkjd/9KNAapsHnibjMLnfXodlkXw76JEea0UiNzrqidzo1emMwk7w5Qhc9jd4Bn9TBb1MFwA==", - "dev": true - }, - "static-extend": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", - "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", - "dev": true, - "requires": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" - }, - "dependencies": { - "define-property": { - "version": "0.2.5", - "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", - "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", - "dev": true, - "requires": { - "is-descriptor": "^0.1.0" - } - } - } - }, - "statuses": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", - "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" - }, - "stealthy-require": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz", - "integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks=", - "dev": true - }, - "string-length": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/string-length/-/string-length-2.0.0.tgz", - "integrity": "sha1-1A27aGo6zpYMHP/KVivyxF+DY+0=", - "dev": true, - "requires": { - "astral-regex": "^1.0.0", - "strip-ansi": "^4.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", - "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", - "dev": true - }, - "strip-ansi": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", - "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", - "dev": true, - "requires": { - "ansi-regex": "^3.0.0" - } - } - } - }, - "string-width": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", - "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", - "dev": true, - "requires": { - "emoji-regex": "^7.0.1", - "is-fullwidth-code-point": "^2.0.0", - "strip-ansi": "^5.1.0" - } - }, - "string.prototype.trimleft": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz", - "integrity": "sha512-FJ6b7EgdKxxbDxc79cOlok6Afd++TTs5szo+zJTUyow3ycrRfJVE2pq3vcN53XexvKZu/DJMDfeI/qMiZTrjTw==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "function-bind": "^1.1.1" - } - }, - "string.prototype.trimright": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.0.tgz", - "integrity": "sha512-fXZTSV55dNBwv16uw+hh5jkghxSnc5oHq+5K/gXgizHwAvMetdAJlHqqoFC1FSDVPYWLkAKl2cxpUT41sV7nSg==", - "dev": true, - "requires": { - "define-properties": "^1.1.3", - "function-bind": "^1.1.1" - } - }, - "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", - "dev": true, - "requires": { - "safe-buffer": "~5.1.0" - } - }, - "strip-ansi": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", - "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", - "dev": true, - "requires": { - "ansi-regex": "^4.1.0" - } - }, - "strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true - }, - "strip-eof": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", - "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=", - "dev": true - }, - "superagent": { - "version": "3.8.3", - "resolved": "https://registry.npmjs.org/superagent/-/superagent-3.8.3.tgz", - "integrity": "sha512-GLQtLMCoEIK4eDv6OGtkOoSMt3D+oq0y3dsxMuYuDvaNUvuT8eFBuLmfR0iYYzHC1e8hpzC6ZsxbuP6DIalMFA==", - "dev": true, - "requires": { - "component-emitter": "^1.2.0", - "cookiejar": "^2.1.0", - "debug": "^3.1.0", - "extend": "^3.0.0", - "form-data": "^2.3.1", - "formidable": "^1.2.0", - "methods": "^1.1.1", - "mime": "^1.4.1", - "qs": "^6.5.1", - "readable-stream": "^2.3.5" - } - }, - "supertest": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/supertest/-/supertest-4.0.2.tgz", - "integrity": "sha512-1BAbvrOZsGA3YTCWqbmh14L0YEq0EGICX/nBnfkfVJn7SrxQV1I3pMYjSzG9y/7ZU2V9dWqyqk2POwxlb09duQ==", - "dev": true, - "requires": { - "methods": "^1.1.2", - "superagent": "^3.8.3" - } - }, - "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "requires": { - "has-flag": "^3.0.0" - } - }, - "symbol-tree": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", - "dev": true - }, - "test-exclude": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-5.2.3.tgz", - "integrity": "sha512-M+oxtseCFO3EDtAaGH7iiej3CBkzXqFMbzqYAACdzKui4eZA+pq3tZEwChvOdNfa7xxy8BfbmgJSIr43cC/+2g==", - "dev": true, - "requires": { - "glob": "^7.1.3", - "minimatch": "^3.0.4", - "read-pkg-up": "^4.0.0", - "require-main-filename": "^2.0.0" - } - }, - "thenify": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.0.tgz", - "integrity": "sha1-5p44obq+lpsBCCB5eLn2K4hgSDk=", - "requires": { - "any-promise": "^1.0.0" - } - }, - "thenify-all": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", - "integrity": "sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY=", - "requires": { - "thenify": ">= 3.1.0 < 4" - } - }, - "throat": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/throat/-/throat-4.1.0.tgz", - "integrity": "sha1-iQN8vJLFarGJJua6TLsgDhVnKmo=", - "dev": true - }, - "tmpl": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz", - "integrity": "sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE=", - "dev": true - }, - "to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4=", - "dev": true - }, - "to-object-path": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", - "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - } - }, - "to-regex": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", - "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", - "dev": true, - "requires": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" - }, - "dependencies": { - "extend-shallow": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", - "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - } - }, - "is-extendable": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", - "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - } - } - }, - "to-regex-range": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", - "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", - "dev": true, - "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" - } - }, - "toidentifier": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.0.tgz", - "integrity": "sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw==" - }, - "tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", - "dev": true, - "requires": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - } - }, - "tr46": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-1.0.1.tgz", - "integrity": "sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk=", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "tsscmp": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/tsscmp/-/tsscmp-1.0.6.tgz", - "integrity": "sha512-LxhtAkPDTkVCMQjt2h6eBVY28KCjikZqZfMcC15YBeNjkgUpdCfBu5HoiOTDu86v6smE8yOjyEktJ8hlbANHQA==" - }, - "tunnel-agent": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", - "dev": true, - "requires": { - "safe-buffer": "^5.0.1" - } - }, - "tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", - "dev": true - }, - "type-check": { - "version": "0.3.2", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz", - "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=", - "dev": true, - "requires": { - "prelude-ls": "~1.1.2" - } - }, - "type-is": { - "version": "1.6.18", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", - "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", - "requires": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - } - }, - "uglify-js": { - "version": "3.6.7", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.7.tgz", - "integrity": "sha512-4sXQDzmdnoXiO+xvmTzQsfIiwrjUCSA95rSP4SEd8tDb51W2TiDOlL76Hl+Kw0Ie42PSItCW8/t6pBNCF2R48A==", - "dev": true, - "optional": true, - "requires": { - "commander": "~2.20.3", - "source-map": "~0.6.1" - } - }, - "union-value": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", - "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", - "dev": true, - "requires": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^2.0.1" - } - }, - "unpipe": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", - "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" - }, - "unset-value": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", - "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", - "dev": true, - "requires": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, - "dependencies": { - "has-value": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", - "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", - "dev": true, - "requires": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" - }, - "dependencies": { - "isobject": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", - "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", - "dev": true, - "requires": { - "isarray": "1.0.0" - } - } - } - }, - "has-values": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", - "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", - "dev": true - }, - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - } - } - }, - "uri-js": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", - "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", - "dev": true, - "requires": { - "punycode": "^2.1.0" - } - }, - "urijs": { - "version": "1.19.2", - "resolved": "https://registry.npmjs.org/urijs/-/urijs-1.19.2.tgz", - "integrity": "sha512-s/UIq9ap4JPZ7H1EB5ULo/aOUbWqfDi7FKzMC2Nz+0Si8GiT1rIEaprt8hy3Vy2Ex2aJPpOQv4P4DuOZ+K1c6w==" - }, - "urix": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", - "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", - "dev": true - }, - "use": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", - "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", - "dev": true - }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", - "dev": true - }, - "util.promisify": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/util.promisify/-/util.promisify-1.0.0.tgz", - "integrity": "sha512-i+6qA2MPhvoKLuxnJNpXAGhg7HphQOSUq2LKMZD0m15EiskXUkMvKdF4Uui0WYeCUGea+o2cw/ZuwehtfsrNkA==", - "dev": true, - "requires": { - "define-properties": "^1.1.2", - "object.getownpropertydescriptors": "^2.0.3" - } - }, - "uuid": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.3.tgz", - "integrity": "sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ==", - "dev": true - }, - "validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "requires": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "vary": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", - "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" - }, - "verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", - "dev": true, - "requires": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, - "w3c-hr-time": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz", - "integrity": "sha1-gqwr/2PZUOqeMYmlimViX+3xkEU=", - "dev": true, - "requires": { - "browser-process-hrtime": "^0.1.2" - } - }, - "walker": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz", - "integrity": "sha1-L3+bj9ENZ3JisYqITijRlhjgKPs=", - "dev": true, - "requires": { - "makeerror": "1.0.x" - } - }, - "webidl-conversions": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-4.0.2.tgz", - "integrity": "sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==", - "dev": true - }, - "whatwg-encoding": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz", - "integrity": "sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==", - "dev": true, - "requires": { - "iconv-lite": "0.4.24" - } - }, - "whatwg-mimetype": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz", - "integrity": "sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==", - "dev": true - }, - "whatwg-url": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-6.5.0.tgz", - "integrity": "sha512-rhRZRqx/TLJQWUpQ6bmrt2UV4f0HCQ463yQuONJqC6fO2VoEb1pTYddbe59SkYq87aoM5A3bdhMZiUiVws+fzQ==", - "dev": true, - "requires": { - "lodash.sortby": "^4.7.0", - "tr46": "^1.0.1", - "webidl-conversions": "^4.0.2" - } - }, - "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } - }, - "which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", - "dev": true - }, - "wordwrap": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz", - "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc=", - "dev": true - }, - "wrap-ansi": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", - "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", - "dev": true, - "requires": { - "ansi-styles": "^3.2.0", - "string-width": "^3.0.0", - "strip-ansi": "^5.0.0" - } - }, - "wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" - }, - "write-file-atomic": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-2.4.1.tgz", - "integrity": "sha512-TGHFeZEZMnv+gBFRfjAcxL5bPHrsGKtnb4qsFAws7/vlh+QfwAaySIw4AXP9ZskTTh5GWu3FLuJhsWVdiJPGvg==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.11", - "imurmurhash": "^0.1.4", - "signal-exit": "^3.0.2" - } - }, - "ws": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-5.2.2.tgz", - "integrity": "sha512-jaHFD6PFv6UgoIVda6qZllptQsMlDEJkTQcybzzXDYM1XO9Y8em691FGMPmM46WGyLU4z9KMgQN+qrux/nhlHA==", - "dev": true, - "requires": { - "async-limiter": "~1.0.0" - } - }, - "xml-name-validator": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz", - "integrity": "sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==", - "dev": true - }, - "y18n": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", - "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", - "dev": true - }, - "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=" - }, - "yargs": { - "version": "13.3.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz", - "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==", - "dev": true, - "requires": { - "cliui": "^5.0.0", - "find-up": "^3.0.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^3.0.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^13.1.1" - } - }, - "yargs-parser": { - "version": "13.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz", - "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==", - "dev": true, - "requires": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - } - }, - "ylru": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ylru/-/ylru-1.2.1.tgz", - "integrity": "sha512-faQrqNMzcPCHGVC2aaOINk13K+aaBDUPjGWl0teOXywElLjyVAB6Oe2jj62jHYtwsU49jXhScYbvPENK+6zAvQ==" - } - } -} diff --git a/exercises/07_unit_testing/file_system/package.json b/exercises/07_unit_testing/file_system/package.json index 30a36a62..82544822 100644 --- a/exercises/07_unit_testing/file_system/package.json +++ b/exercises/07_unit_testing/file_system/package.json @@ -12,8 +12,8 @@ "koa-views": "^6.2.1" }, "devDependencies": { - "mock-fs": "^4.10.3", "jest": "^24.9.0", + "mock-fs": "^4.10.3", "supertest": "^4.0.2" }, "scripts": { diff --git a/exercises/07_unit_testing/file_system/unit tests/file.spec.js b/exercises/07_unit_testing/file_system/unit tests/file.spec.js index 1e5f1a91..b67e52ef 100644 --- a/exercises/07_unit_testing/file_system/unit tests/file.spec.js +++ b/exercises/07_unit_testing/file_system/unit tests/file.spec.js @@ -18,15 +18,16 @@ describe('savePicture()', () => { 'test': { 'foo': 'bar' } - }); + }) + const file = new File() }) afterEach( async() => { - afterEach(mock.restore); + afterEach(mock.restore) }) test(`filename can't be empty string`, async done => { expect.assertions(1) try { - file.savePicture('', 'asd') + await file.savePicture('', 'asd') done.fail('test failed') } catch(err) { expect(err.message).toBe(`filename can't be empty`) @@ -37,7 +38,7 @@ describe('savePicture()', () => { test(`filename can't be undefined`, async done => { expect.assertions(1) try { - file.savePicture() + await file.savePicture() done.fail('test failed') } catch(err) { expect(err.message).toBe(`filename can't be empty`) @@ -48,7 +49,7 @@ describe('savePicture()', () => { test(`imageData can't be empty`, async done => { expect.assertions(1) try { - file.savePicture('foo.jpg') + await file.savePicture('foo.jpg') done.fail('test failed') } catch(err) { expect(err.message).toBe(`imageData can't be empty`) @@ -59,9 +60,8 @@ describe('savePicture()', () => { test(`binary information has to be correctly saved`, async done => { expect.assertions(1) try { - const file = new File() - file.savePicture('test/foobar', 'raboof') - fs.readFile('test/foobar', 'binary', (err, data) => { + await fs.savePicture('image', 'raboof') + fs.readFile('image', 'binary', (err, data) => { if (err) throw new Error(err) expect(data).toBe('raboof') }) @@ -76,18 +76,19 @@ describe('savePicture()', () => { describe('readPicture()', () => { beforeEach( async() => { mock({ - '/test': { + 'test': { 'foo': 'bar' } - }); + }) + const file = new File() }) afterEach( async() => { - afterEach(mock.restore); + afterEach(mock.restore) }) test(`filename can't be empty`, async done => { expect.assertions(1) try { - file.readPicture('') + await file.readPicture('') done.fail('test failed') } catch(err) { expect(err.message).toBe(`filename can't be empty`) @@ -98,7 +99,7 @@ describe('readPicture()', () => { test(`filename can't be undefined`, async done => { expect.assertions(1) try { - file.readPicture() + await file.readPicture() done.fail('test failed') } catch(err) { expect(err.message).toBe(`filename can't be empty`) @@ -109,7 +110,7 @@ describe('readPicture()', () => { test('file has to exist', async done => { expect.assertions(1) try { - file.readPicture('nonExistent.txt') + await file.readPicture('nonExistent.txt') done.fail('test failed') } catch(err) { expect(err.message).toBe(`file doesn't exist`) @@ -120,7 +121,6 @@ describe('readPicture()', () => { test(`binary information has to be correctly read`, async done => { expect.assertions(1) try { - const file = new File() expect(file.readPicture('test/foo')).toBe('bar') } catch(err) { done.fail('test failed') @@ -128,4 +128,4 @@ describe('readPicture()', () => { done() } }) -}) \ No newline at end of file +}) From 7cf77b6637eeeda05fc9bb486c10cc07a44df5a2 Mon Sep 17 00:00:00 2001 From: Balazs Laszlo Bordas Date: Fri, 8 Nov 2019 03:02:10 +0000 Subject: [PATCH 31/70] trying to fix file_system unit test --- .../file_system/unit tests/file.spec.js | 10 ++++---- .../file_system/unit tests/trymockfs.js | 24 +++++++++++++++++++ 2 files changed, 29 insertions(+), 5 deletions(-) create mode 100644 exercises/07_unit_testing/file_system/unit tests/trymockfs.js diff --git a/exercises/07_unit_testing/file_system/unit tests/file.spec.js b/exercises/07_unit_testing/file_system/unit tests/file.spec.js index b67e52ef..0664087f 100644 --- a/exercises/07_unit_testing/file_system/unit tests/file.spec.js +++ b/exercises/07_unit_testing/file_system/unit tests/file.spec.js @@ -2,9 +2,11 @@ 'use strict' const mock = require('mock-fs') +const fs = require('fs') const File = require('../modules/file') -const fs = require('fs') + +const file = new File() beforeAll( async() => { }) @@ -19,10 +21,9 @@ describe('savePicture()', () => { 'foo': 'bar' } }) - const file = new File() }) afterEach( async() => { - afterEach(mock.restore) + mock.restore() }) test(`filename can't be empty string`, async done => { expect.assertions(1) @@ -80,10 +81,9 @@ describe('readPicture()', () => { 'foo': 'bar' } }) - const file = new File() }) afterEach( async() => { - afterEach(mock.restore) + mock.restore() }) test(`filename can't be empty`, async done => { expect.assertions(1) diff --git a/exercises/07_unit_testing/file_system/unit tests/trymockfs.js b/exercises/07_unit_testing/file_system/unit tests/trymockfs.js new file mode 100644 index 00000000..b0b29de2 --- /dev/null +++ b/exercises/07_unit_testing/file_system/unit tests/trymockfs.js @@ -0,0 +1,24 @@ + +'use strict' + +const mock = require('mock-fs') +const fs = require('fs') + +mock({ + 'test': { + 'foo': 'bar' + } +}) +fs.readFile('test/foo', 'UTF-8', (err, data) =>{ + if (err) throw new Error(err) + console.log(data) +}) +fs.writeFile('test/bar', 'foo', 'UTF-8', (err) => { + if (err) throw new Error(err) +}) +fs.readFile('test/bar', 'UTF-8', (err, data) =>{ + if (err) throw new Error(err) + console.log(data) +}) + +mock.restore() From 5b4ac41eaa21ae1b20416a85457d5d5f26ecb7b9 Mon Sep 17 00:00:00 2001 From: "Mark Tyers (aa7401)" Date: Fri, 8 Nov 2019 07:42:25 +0000 Subject: [PATCH 32/70] Removed Merge Conflict One of the modules retained a merge conflict. This has now been removed. --- exercises/07_unit_testing/todo/modules/todo.js | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/exercises/07_unit_testing/todo/modules/todo.js b/exercises/07_unit_testing/todo/modules/todo.js index 6ce40d22..f4fdd7b8 100644 --- a/exercises/07_unit_testing/todo/modules/todo.js +++ b/exercises/07_unit_testing/todo/modules/todo.js @@ -9,22 +9,8 @@ module.exports.clear = () => { module.exports.add = (item, qty) => { qty = Number(qty) -<<<<<<< HEAD - if(isNaN(qty)) throw new Error('the quantity must be a number') - let flag = false - for(let index in data) { - if (data[index].item === item) { - data[index].qty+= qty - flag = true - } - } - if(flag === false) { - data.push({item: item, qty: qty}) - } -======= if(isNaN(qty)) throw new Error('qty must be a number') data.push({item: item, qty: qty}) ->>>>>>> upstream/master } module.exports.getAll = () => { From c4d788d2d2458d1ac5410c7b73a94860bfa0585a Mon Sep 17 00:00:00 2001 From: Mark Tyers Date: Fri, 8 Nov 2019 08:05:51 +0000 Subject: [PATCH 33/70] Replaced Module Async functions can't use the standard readline module. This has been replaced with the sync version. --- exercises/06_code_quality/asyncFunctions.js | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/exercises/06_code_quality/asyncFunctions.js b/exercises/06_code_quality/asyncFunctions.js index 35f1e2b4..cca2bfda 100644 --- a/exercises/06_code_quality/asyncFunctions.js +++ b/exercises/06_code_quality/asyncFunctions.js @@ -2,7 +2,7 @@ 'use strict' const request = require('request') -const readline = require('readline') +const readline = require('readline-sync') const baseURL = 'https://api.exchangeratesapi.io/latest' @@ -21,12 +21,8 @@ async function main() { } const getInput = prompt => new Promise(resolve => { - const read = readline.createInterface({ input: process.stdin, output: process.stdout }) - read.question(`${prompt}: `, value => { - console.log(`You entered ${value}`) - read.close() - resolve(value) - }) + const response = readline.question(`${prompt}: `) + return resolve(response) }) const checkValidCurrencyCode = code => new Promise( (resolve, reject) => { From 54a02fa371267e8a54a5a56cb68911b1b8453c3f Mon Sep 17 00:00:00 2001 From: harjaus Date: Fri, 8 Nov 2019 10:39:04 +0000 Subject: [PATCH 34/70] Now we throw specific errors, not generic --- .../file_system/modules/file.js | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/exercises/07_unit_testing/file_system/modules/file.js b/exercises/07_unit_testing/file_system/modules/file.js index 644c4aa1..08fd2a37 100644 --- a/exercises/07_unit_testing/file_system/modules/file.js +++ b/exercises/07_unit_testing/file_system/modules/file.js @@ -1,26 +1,28 @@ 'use strict' -const fs = require('fs') - module.exports = class File { - constructor() {} + constructor() { } async savePicture(filename, imageData) { if (filename === undefined || filename === '') throw new Error(`filename can't be empty`) if (imageData === undefined || imageData === '') throw new Error(`imageData can't be empty`) - fs.writeFile(filename, imageData, 'binary', (err) => { - if (err) throw new Error(err) - console.log('File saved.') - }) + + const fs = require('fs') + try{ + fs.writeFile(filename, imageData, 'binary') + } catch(err) + { + throw err + } } readPicture(filename) { if (filename === undefined || filename === '') throw new Error(`filename can't be empty`) + const fs = require('fs') try { fs.readFileSync(filename, 'binary') } catch(err) { - console.log(err) - throw new Error(`file doesn't exist`) + throw err } } } From a69a9c844a5a6b14a0c38fbef2f1ad485c22e705 Mon Sep 17 00:00:00 2001 From: harjaus Date: Fri, 8 Nov 2019 10:39:17 +0000 Subject: [PATCH 35/70] Added dependency --- exercises/07_unit_testing/file_system/package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/exercises/07_unit_testing/file_system/package.json b/exercises/07_unit_testing/file_system/package.json index 82544822..540d1f46 100644 --- a/exercises/07_unit_testing/file_system/package.json +++ b/exercises/07_unit_testing/file_system/package.json @@ -4,6 +4,7 @@ "description": "mock-fs", "main": "index.js", "dependencies": { + "callsites": "^3.1.0", "fs": "^0.0.1-security", "http-status-codes": "^1.4.0", "koa": "^2.11.0", From bc98b02df45bf86765bb7baf00ff9b8ae4b6fad5 Mon Sep 17 00:00:00 2001 From: harjaus Date: Fri, 8 Nov 2019 10:39:56 +0000 Subject: [PATCH 36/70] We no longer done.fail() on everything, we expect no errors on catch --- .../file_system/unit tests/file.spec.js | 31 ++++++++++--------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/exercises/07_unit_testing/file_system/unit tests/file.spec.js b/exercises/07_unit_testing/file_system/unit tests/file.spec.js index 0664087f..3ff3fdce 100644 --- a/exercises/07_unit_testing/file_system/unit tests/file.spec.js +++ b/exercises/07_unit_testing/file_system/unit tests/file.spec.js @@ -2,29 +2,30 @@ 'use strict' const mock = require('mock-fs') -const fs = require('fs') - const File = require('../modules/file') +const fs = require('fs') const file = new File() + beforeAll( async() => { + mock({ + 'test': { + 'foo': 'bar' + } + }) }) afterAll( async() => { + mock.restore() }) describe('savePicture()', () => { beforeEach( async() => { - mock({ - 'test': { - 'foo': 'bar' - } - }) }) afterEach( async() => { - mock.restore() }) + test(`filename can't be empty string`, async done => { expect.assertions(1) try { @@ -59,15 +60,15 @@ describe('savePicture()', () => { } }) test(`binary information has to be correctly saved`, async done => { - expect.assertions(1) + expect.assertions(2) try { - await fs.savePicture('image', 'raboof') - fs.readFile('image', 'binary', (err, data) => { - if (err) throw new Error(err) + await file.savePicture('image', 'raboof') + file.readPicture('image', 'binary', (err, data) => { expect(data).toBe('raboof') + expect(err).toBeUndefined() }) } catch(err) { - done.fail('test failed') + expect(err.message).toBe(null) } finally { done() } @@ -113,7 +114,7 @@ describe('readPicture()', () => { await file.readPicture('nonExistent.txt') done.fail('test failed') } catch(err) { - expect(err.message).toBe(`file doesn't exist`) + expect(err.message).toBe(`ENOENT: no such file or directory, open 'nonExistent.txt'`) } finally { done() } @@ -123,7 +124,7 @@ describe('readPicture()', () => { try { expect(file.readPicture('test/foo')).toBe('bar') } catch(err) { - done.fail('test failed') + expect(err.message).toBe(null) } finally { done() } From 6e1486821895ebdd3f3938cb36d0971f6e8c5234 Mon Sep 17 00:00:00 2001 From: bordasb Date: Fri, 8 Nov 2019 12:29:41 +0000 Subject: [PATCH 37/70] trying to fix mockfs exercise --- .../07_unit_testing/file_system/index.js | 78 +++--- .../file_system/jest-test.config.js | 40 +-- .../file_system/modules/file.js | 54 ++-- .../07_unit_testing/file_system/package.json | 2 +- .../07_unit_testing/file_system/pictures.html | 22 -- .../file_system/unit tests/file.spec.js | 253 +++++++++--------- .../file_system/unit tests/trymockfs.js | 21 +- .../file_system/views/pictures.html | 38 +-- 8 files changed, 236 insertions(+), 272 deletions(-) delete mode 100644 exercises/07_unit_testing/file_system/pictures.html diff --git a/exercises/07_unit_testing/file_system/index.js b/exercises/07_unit_testing/file_system/index.js index 6677cf0b..b11dc9dd 100644 --- a/exercises/07_unit_testing/file_system/index.js +++ b/exercises/07_unit_testing/file_system/index.js @@ -1,39 +1,39 @@ -#!/usr/bin/env node - -'use strict' - -const File = require('./modules/file') - -const Koa = require('koa') -const Router = require('koa-router') -const BodyParser = require('koa-bodyparser') -const views = require('koa-views') -const status = require('http-status-codes') - -const port = 8080 -const file = new File() - -const app = new Koa() -app.use(views(`${__dirname}/views`, { extension: 'html' }, {map: { handlebars: 'handlebars' }})) -app.use(BodyParser({ - encoding: 'multipart/form-data' -})) - -const router = new Router() - -router.get('/', async ctx => { - await ctx.render('pictures.html') -}) -router.post('/', ctx => { - try { - console.log('processing the post request') - const body = ctx.request.body - console.log(body.fileUpload) - } catch(err) { - ctx.status = status.UNPROCESSABLE_ENTITY - ctx.body = err.message - } -}) - -app.use(router.routes()) -module.exports = app.listen(port, () => console.log(`listening on port ${port}`)) +#!/usr/bin/env node + +'use strict' + +const File = require('./modules/file') + +const Koa = require('koa') +const Router = require('koa-router') +const BodyParser = require('koa-bodyparser') +const views = require('koa-views') +const status = require('http-status-codes') + +const port = 8080 +const file = new File() + +const app = new Koa() +app.use(views(`${__dirname}/views`, { extension: 'html' }, {map: { handlebars: 'handlebars' }})) +app.use(BodyParser({ + encoding: 'multipart/form-data' +})) + +const router = new Router() + +router.get('/', async ctx => { + await ctx.render('pictures.html') +}) +router.post('/', ctx => { + try { + console.log('processing the post request') + const body = ctx.request.body + console.log(body.fileUpload) + } catch(err) { + ctx.status = status.UNPROCESSABLE_ENTITY + ctx.body = err.message + } +}) + +app.use(router.routes()) +module.exports = app.listen(port, () => console.log(`listening on port ${port}`)) diff --git a/exercises/07_unit_testing/file_system/jest-test.config.js b/exercises/07_unit_testing/file_system/jest-test.config.js index a758c709..fc892638 100644 --- a/exercises/07_unit_testing/file_system/jest-test.config.js +++ b/exercises/07_unit_testing/file_system/jest-test.config.js @@ -1,20 +1,20 @@ - -'use strict'; - -module.exports = { - displayName: 'test', - verbose: true, - collectCoverage: true, - coverageThreshold: { - global: { - branches: 0, - functions: 0, - lines: 0, - statements: 0 - } - }, - testPathIgnorePatterns: [ - '/node_modules/', - '/__tests__/fixtures/', - ] -} + +'use strict' + +module.exports = { + displayName: 'test', + verbose: true, + collectCoverage: true, + coverageThreshold: { + global: { + branches: 0, + functions: 0, + lines: 0, + statements: 0 + } + }, + testPathIgnorePatterns: [ + '/node_modules/', + '/__tests__/fixtures/', + ] +} diff --git a/exercises/07_unit_testing/file_system/modules/file.js b/exercises/07_unit_testing/file_system/modules/file.js index 08fd2a37..1d7a9be3 100644 --- a/exercises/07_unit_testing/file_system/modules/file.js +++ b/exercises/07_unit_testing/file_system/modules/file.js @@ -1,28 +1,26 @@ -'use strict' - -module.exports = class File { - constructor() { } - - async savePicture(filename, imageData) { - if (filename === undefined || filename === '') throw new Error(`filename can't be empty`) - if (imageData === undefined || imageData === '') throw new Error(`imageData can't be empty`) - - const fs = require('fs') - try{ - fs.writeFile(filename, imageData, 'binary') - } catch(err) - { - throw err - } - } - - readPicture(filename) { - if (filename === undefined || filename === '') throw new Error(`filename can't be empty`) - const fs = require('fs') - try { - fs.readFileSync(filename, 'binary') - } catch(err) { - throw err - } - } -} +'use strict' + +const fs = require('fs') + +module.exports = class File { + constructor() {} + + async savePicture(filename, imageData) { + if (filename === undefined || filename === '') throw new Error(`filename can't be empty`) + if (imageData === undefined || imageData === '') throw new Error(`imageData can't be empty`) + try { + fs.writeFile(filename, imageData, 'binary') + } catch(err) { + throw err + } + } + + readPicture(filename) { + if (filename === undefined || filename === '') throw new Error(`filename can't be empty`) + try { + return fs.readFileSync(filename, 'binary') + } catch(err) { + throw err + } + } +} diff --git a/exercises/07_unit_testing/file_system/package.json b/exercises/07_unit_testing/file_system/package.json index 540d1f46..001f3a84 100644 --- a/exercises/07_unit_testing/file_system/package.json +++ b/exercises/07_unit_testing/file_system/package.json @@ -18,7 +18,7 @@ "supertest": "^4.0.2" }, "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "test": "jest --config=./jest-test.config.js --coverage" }, "author": "", "license": "ISC" diff --git a/exercises/07_unit_testing/file_system/pictures.html b/exercises/07_unit_testing/file_system/pictures.html deleted file mode 100644 index f7e21603..00000000 --- a/exercises/07_unit_testing/file_system/pictures.html +++ /dev/null @@ -1,22 +0,0 @@ - - - - - - - Pictures - - -

Save new pictures

-
- Image to be uploaded: -
- -

- -
-

Saved pictures

- - - - \ No newline at end of file diff --git a/exercises/07_unit_testing/file_system/unit tests/file.spec.js b/exercises/07_unit_testing/file_system/unit tests/file.spec.js index 3ff3fdce..a91c28d7 100644 --- a/exercises/07_unit_testing/file_system/unit tests/file.spec.js +++ b/exercises/07_unit_testing/file_system/unit tests/file.spec.js @@ -1,132 +1,121 @@ - -'use strict' - -const mock = require('mock-fs') -const File = require('../modules/file') - -const fs = require('fs') -const file = new File() - - -beforeAll( async() => { - mock({ - 'test': { - 'foo': 'bar' - } - }) -}) - -afterAll( async() => { - mock.restore() -}) - -describe('savePicture()', () => { - beforeEach( async() => { - }) - afterEach( async() => { - }) - - test(`filename can't be empty string`, async done => { - expect.assertions(1) - try { - await file.savePicture('', 'asd') - done.fail('test failed') - } catch(err) { - expect(err.message).toBe(`filename can't be empty`) - } finally { - done() - } - }) - test(`filename can't be undefined`, async done => { - expect.assertions(1) - try { - await file.savePicture() - done.fail('test failed') - } catch(err) { - expect(err.message).toBe(`filename can't be empty`) - } finally { - done() - } - }) - test(`imageData can't be empty`, async done => { - expect.assertions(1) - try { - await file.savePicture('foo.jpg') - done.fail('test failed') - } catch(err) { - expect(err.message).toBe(`imageData can't be empty`) - } finally { - done() - } - }) - test(`binary information has to be correctly saved`, async done => { - expect.assertions(2) - try { - await file.savePicture('image', 'raboof') - file.readPicture('image', 'binary', (err, data) => { - expect(data).toBe('raboof') - expect(err).toBeUndefined() - }) - } catch(err) { - expect(err.message).toBe(null) - } finally { - done() - } - }) -}) - -describe('readPicture()', () => { - beforeEach( async() => { - mock({ - 'test': { - 'foo': 'bar' - } - }) - }) - afterEach( async() => { - mock.restore() - }) - test(`filename can't be empty`, async done => { - expect.assertions(1) - try { - await file.readPicture('') - done.fail('test failed') - } catch(err) { - expect(err.message).toBe(`filename can't be empty`) - } finally { - done() - } - }) - test(`filename can't be undefined`, async done => { - expect.assertions(1) - try { - await file.readPicture() - done.fail('test failed') - } catch(err) { - expect(err.message).toBe(`filename can't be empty`) - } finally { - done() - } - }) - test('file has to exist', async done => { - expect.assertions(1) - try { - await file.readPicture('nonExistent.txt') - done.fail('test failed') - } catch(err) { - expect(err.message).toBe(`ENOENT: no such file or directory, open 'nonExistent.txt'`) - } finally { - done() - } - }) - test(`binary information has to be correctly read`, async done => { - expect.assertions(1) - try { - expect(file.readPicture('test/foo')).toBe('bar') - } catch(err) { - expect(err.message).toBe(null) - } finally { - done() - } - }) -}) +'use strict' + +const mock = require('mock-fs') +const File = require('../modules/file') + +const fs = require('fs') +const file = new File() + + +beforeAll( async() => { + // mock({ + // 'test': { + // 'foo': 'bar' + // } + // }) +}) + +afterAll( async() => { + // mock.restore() +}) + +describe('savePicture()', () => { + beforeEach( async() => {}) + afterEach( async() => {}) + + test(`filename can't be empty string`, async done => { + expect.assertions(1) + try { + await file.savePicture('', 'asd') + done.fail('test failed') + } catch(err) { + expect(err.message).toBe(`filename can't be empty`) + } finally { + done() + } + }) + test(`filename can't be undefined`, async done => { + expect.assertions(1) + try { + await file.savePicture() + done.fail('test failed') + } catch(err) { + expect(err.message).toBe(`filename can't be empty`) + } finally { + done() + } + }) + test(`imageData can't be empty`, async done => { + expect.assertions(1) + try { + await file.savePicture('foo.jpg') + done.fail('test failed') + } catch(err) { + expect(err.message).toBe(`imageData can't be empty`) + } finally { + done() + } + }) + test(`binary information has to be correctly saved`, async done => { + expect.assertions(3) + try { + await file.savePicture('image', 'raboof') + await file.readPicture('image', 'binary', (err, data) => { + expect(data).toBe('raboof') + expect(err).toBeUndefined() + }) + } catch(err) { + expect(err.message).toBe(null) + } finally { + done() + } + }) +}) + +describe('readPicture()', () => { + beforeEach( async() => { }) + afterEach( async() => { }) + test(`filename can't be empty`, async done => { + expect.assertions(1) + try { + await file.readPicture('') + done.fail('test failed') + } catch(err) { + expect(err.message).toBe(`filename can't be empty`) + } finally { + done() + } + }) + test(`filename can't be undefined`, async done => { + expect.assertions(1) + try { + await file.readPicture() + done.fail('test failed') + } catch(err) { + expect(err.message).toBe(`filename can't be empty`) + } finally { + done() + } + }) + test('file has to exist', async done => { + expect.assertions(1) + try { + await file.readPicture('nonExistent.txt') + done.fail('test failed') + } catch(err) { + expect(err.message).toBe(`ENOENT: no such file or directory, open 'nonExistent.txt'`) + } finally { + done() + } + }) + test(`binary information has to be correctly read`, async done => { + expect.assertions(2) + try { + expect(file.readPicture('foobar')).toBe('foobar2') + } catch(err) { + expect(err.message).toBe(null) + } finally { + done() + } + }) +}) diff --git a/exercises/07_unit_testing/file_system/unit tests/trymockfs.js b/exercises/07_unit_testing/file_system/unit tests/trymockfs.js index b0b29de2..c2553ba1 100644 --- a/exercises/07_unit_testing/file_system/unit tests/trymockfs.js +++ b/exercises/07_unit_testing/file_system/unit tests/trymockfs.js @@ -1,24 +1,23 @@ - 'use strict' const mock = require('mock-fs') const fs = require('fs') mock({ - 'test': { - 'foo': 'bar' - } + 'test': { + 'foo': 'bar' + } }) -fs.readFile('test/foo', 'UTF-8', (err, data) =>{ - if (err) throw new Error(err) - console.log(data) +fs.readFile('test/foo', 'UTF-8', (err, data) => { + if (err) throw new Error(err) + console.log(data) }) fs.writeFile('test/bar', 'foo', 'UTF-8', (err) => { - if (err) throw new Error(err) + if (err) throw new Error(err) }) -fs.readFile('test/bar', 'UTF-8', (err, data) =>{ - if (err) throw new Error(err) - console.log(data) +fs.readFile('test/bar', 'UTF-8', (err, data) => { + if (err) throw new Error(err) + console.log(data) }) mock.restore() diff --git a/exercises/07_unit_testing/file_system/views/pictures.html b/exercises/07_unit_testing/file_system/views/pictures.html index 0bdc4ed5..5f8ff74d 100644 --- a/exercises/07_unit_testing/file_system/views/pictures.html +++ b/exercises/07_unit_testing/file_system/views/pictures.html @@ -1,20 +1,20 @@ - - - - - - - Pictures - - -

Save new pictures

-
- Image to be uploaded: -
- -

- -
-

Saved pictures

- + + + + + + + Pictures + + +

Save new pictures

+
+ Image to be uploaded: +
+ +

+ +
+

Saved pictures

+ \ No newline at end of file From 5e5e55df91e180b31828aa21924fa8dbb2b98c1b Mon Sep 17 00:00:00 2001 From: harjaus Date: Fri, 8 Nov 2019 15:38:19 +0000 Subject: [PATCH 38/70] Now throws correct error on file not existing --- exercises/07_unit_testing/file_system/modules/file.js | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/exercises/07_unit_testing/file_system/modules/file.js b/exercises/07_unit_testing/file_system/modules/file.js index 1d7a9be3..ba29978a 100644 --- a/exercises/07_unit_testing/file_system/modules/file.js +++ b/exercises/07_unit_testing/file_system/modules/file.js @@ -15,12 +15,15 @@ module.exports = class File { } } - readPicture(filename) { + async readPicture(filename) { if (filename === undefined || filename === '') throw new Error(`filename can't be empty`) try { - return fs.readFileSync(filename, 'binary') + return fs.readFileSync(filename, 'UTF-8') } catch(err) { - throw err + if (err.message == `ENOENT: no such file or directory, open '${filename}'`) + throw new Error("file doesn't exist") + else + throw err } } } From 39db18bf9fffc8e6bc1db89b99f720ad5d9085ea Mon Sep 17 00:00:00 2001 From: harjaus Date: Fri, 8 Nov 2019 15:38:37 +0000 Subject: [PATCH 39/70] Reading mocking works --- .../file_system/unit tests/file.spec.js | 125 +++++++++--------- .../file_system/unit tests/foobar | 1 + 2 files changed, 65 insertions(+), 61 deletions(-) create mode 100644 exercises/07_unit_testing/file_system/unit tests/foobar diff --git a/exercises/07_unit_testing/file_system/unit tests/file.spec.js b/exercises/07_unit_testing/file_system/unit tests/file.spec.js index a91c28d7..88ba57f8 100644 --- a/exercises/07_unit_testing/file_system/unit tests/file.spec.js +++ b/exercises/07_unit_testing/file_system/unit tests/file.spec.js @@ -8,69 +8,69 @@ const file = new File() beforeAll( async() => { - // mock({ - // 'test': { - // 'foo': 'bar' - // } - // }) + mock({ + 'test': { + 'foobar': 'foobar2\n' + } + }) }) afterAll( async() => { - // mock.restore() + mock.restore() }) -describe('savePicture()', () => { - beforeEach( async() => {}) - afterEach( async() => {}) +// describe('savePicture()', () => { +// beforeEach( async() => {}) +// afterEach( async() => {}) - test(`filename can't be empty string`, async done => { - expect.assertions(1) - try { - await file.savePicture('', 'asd') - done.fail('test failed') - } catch(err) { - expect(err.message).toBe(`filename can't be empty`) - } finally { - done() - } - }) - test(`filename can't be undefined`, async done => { - expect.assertions(1) - try { - await file.savePicture() - done.fail('test failed') - } catch(err) { - expect(err.message).toBe(`filename can't be empty`) - } finally { - done() - } - }) - test(`imageData can't be empty`, async done => { - expect.assertions(1) - try { - await file.savePicture('foo.jpg') - done.fail('test failed') - } catch(err) { - expect(err.message).toBe(`imageData can't be empty`) - } finally { - done() - } - }) - test(`binary information has to be correctly saved`, async done => { - expect.assertions(3) - try { - await file.savePicture('image', 'raboof') - await file.readPicture('image', 'binary', (err, data) => { - expect(data).toBe('raboof') - expect(err).toBeUndefined() - }) - } catch(err) { - expect(err.message).toBe(null) - } finally { - done() - } - }) -}) +// test(`filename can't be empty string`, async done => { +// expect.assertions(1) +// try { +// await file.savePicture('', 'asd') +// done.fail('test failed') +// } catch(err) { +// expect(err.message).toBe(`filename can't be empty`) +// } finally { +// done() +// } +// }) +// test(`filename can't be undefined`, async done => { +// expect.assertions(1) +// try { +// await file.savePicture() +// done.fail('test failed') +// } catch(err) { +// expect(err.message).toBe(`filename can't be empty`) +// } finally { +// done() +// } +// }) +// test(`imageData can't be empty`, async done => { +// expect.assertions(1) +// try { +// await file.savePicture('foo.jpg') +// done.fail('test failed') +// } catch(err) { +// expect(err.message).toBe(`imageData can't be empty`) +// } finally { +// done() +// } +// }) +// test(`binary information has to be correctly saved`, async done => { +// expect.assertions(3) +// try { +// await file.savePicture('image', 'raboof') +// await file.readPicture('image', 'binary', (err, data) => { +// expect(data).toBe('raboof') +// expect(err).toBeUndefined() +// }) +// } catch(err) { +// expect(err.message).toBe("issue with writing") +// } finally { +// done() +// } +// }) +// }) describe('readPicture()', () => { beforeEach( async() => { }) @@ -103,17 +103,20 @@ describe('readPicture()', () => { await file.readPicture('nonExistent.txt') done.fail('test failed') } catch(err) { - expect(err.message).toBe(`ENOENT: no such file or directory, open 'nonExistent.txt'`) + expect(err.message).toBe("file doesn't exist") } finally { done() } }) test(`binary information has to be correctly read`, async done => { - expect.assertions(2) + expect.assertions(1) try { - expect(file.readPicture('foobar')).toBe('foobar2') + let output = await file.readPicture('test/foobar') + //console.log("Output: ", output) + expect(output).toBe("foobar2\n") } catch(err) { - expect(err.message).toBe(null) + console.log(err) + expect(err.message).toBe("issue with reading") } finally { done() } diff --git a/exercises/07_unit_testing/file_system/unit tests/foobar b/exercises/07_unit_testing/file_system/unit tests/foobar new file mode 100644 index 00000000..1c46fdb1 --- /dev/null +++ b/exercises/07_unit_testing/file_system/unit tests/foobar @@ -0,0 +1 @@ +foobar2 From 810222983f8eb68703bd4cbe583cf93289814647 Mon Sep 17 00:00:00 2001 From: harjaus Date: Fri, 8 Nov 2019 15:39:41 +0000 Subject: [PATCH 40/70] Now reads as binary --- exercises/07_unit_testing/file_system/modules/file.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/exercises/07_unit_testing/file_system/modules/file.js b/exercises/07_unit_testing/file_system/modules/file.js index ba29978a..1b5921f6 100644 --- a/exercises/07_unit_testing/file_system/modules/file.js +++ b/exercises/07_unit_testing/file_system/modules/file.js @@ -18,7 +18,7 @@ module.exports = class File { async readPicture(filename) { if (filename === undefined || filename === '') throw new Error(`filename can't be empty`) try { - return fs.readFileSync(filename, 'UTF-8') + return fs.readFileSync(filename, 'binary') } catch(err) { if (err.message == `ENOENT: no such file or directory, open '${filename}'`) throw new Error("file doesn't exist") From 0b9b9e1534e14f064aca1e05a5110c3f21d8af71 Mon Sep 17 00:00:00 2001 From: harjaus Date: Fri, 8 Nov 2019 15:56:09 +0000 Subject: [PATCH 41/70] Now writes synchronously, fixes bug --- exercises/07_unit_testing/file_system/modules/file.js | 2 +- exercises/07_unit_testing/file_system/modules/image | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) create mode 100644 exercises/07_unit_testing/file_system/modules/image diff --git a/exercises/07_unit_testing/file_system/modules/file.js b/exercises/07_unit_testing/file_system/modules/file.js index 1b5921f6..e2eab795 100644 --- a/exercises/07_unit_testing/file_system/modules/file.js +++ b/exercises/07_unit_testing/file_system/modules/file.js @@ -9,7 +9,7 @@ module.exports = class File { if (filename === undefined || filename === '') throw new Error(`filename can't be empty`) if (imageData === undefined || imageData === '') throw new Error(`imageData can't be empty`) try { - fs.writeFile(filename, imageData, 'binary') + fs.writeFileSync(filename, imageData, 'binary') } catch(err) { throw err } diff --git a/exercises/07_unit_testing/file_system/modules/image b/exercises/07_unit_testing/file_system/modules/image new file mode 100644 index 00000000..a9acf68e --- /dev/null +++ b/exercises/07_unit_testing/file_system/modules/image @@ -0,0 +1 @@ +raboof \ No newline at end of file From 39518ac7289ce0715f1a0a877b644410e00839fe Mon Sep 17 00:00:00 2001 From: harjaus Date: Fri, 8 Nov 2019 15:57:16 +0000 Subject: [PATCH 42/70] Now can mock writing to filesystem --- .../file_system/unit tests/file.spec.js | 102 +++++++++--------- .../file_system/unit tests/image | 1 + 2 files changed, 51 insertions(+), 52 deletions(-) create mode 100644 exercises/07_unit_testing/file_system/unit tests/image diff --git a/exercises/07_unit_testing/file_system/unit tests/file.spec.js b/exercises/07_unit_testing/file_system/unit tests/file.spec.js index 88ba57f8..ef7c4ec8 100644 --- a/exercises/07_unit_testing/file_system/unit tests/file.spec.js +++ b/exercises/07_unit_testing/file_system/unit tests/file.spec.js @@ -16,61 +16,59 @@ beforeAll( async() => { }) afterAll( async() => { - mock.restore() + mock.restore() }) -// describe('savePicture()', () => { -// beforeEach( async() => {}) -// afterEach( async() => {}) +describe('savePicture()', () => { + beforeEach( async() => {}) + afterEach( async() => {}) -// test(`filename can't be empty string`, async done => { -// expect.assertions(1) -// try { -// await file.savePicture('', 'asd') -// done.fail('test failed') -// } catch(err) { -// expect(err.message).toBe(`filename can't be empty`) -// } finally { -// done() -// } -// }) -// test(`filename can't be undefined`, async done => { -// expect.assertions(1) -// try { -// await file.savePicture() -// done.fail('test failed') -// } catch(err) { -// expect(err.message).toBe(`filename can't be empty`) -// } finally { -// done() -// } -// }) -// test(`imageData can't be empty`, async done => { -// expect.assertions(1) -// try { -// await file.savePicture('foo.jpg') -// done.fail('test failed') -// } catch(err) { -// expect(err.message).toBe(`imageData can't be empty`) -// } finally { -// done() -// } -// }) -// test(`binary information has to be correctly saved`, async done => { -// expect.assertions(3) -// try { -// await file.savePicture('image', 'raboof') -// await file.readPicture('image', 'binary', (err, data) => { -// expect(data).toBe('raboof') -// expect(err).toBeUndefined() -// }) -// } catch(err) { -// expect(err.message).toBe("issue with writing") -// } finally { -// done() -// } -// }) -// }) + test(`filename can't be empty string`, async done => { + expect.assertions(1) + try { + await file.savePicture('', 'asd') + done.fail('test failed') + } catch(err) { + expect(err.message).toBe(`filename can't be empty`) + } finally { + done() + } + }) + test(`filename can't be undefined`, async done => { + expect.assertions(1) + try { + await file.savePicture() + done.fail('test failed') + } catch(err) { + expect(err.message).toBe(`filename can't be empty`) + } finally { + done() + } + }) + test(`imageData can't be empty`, async done => { + expect.assertions(1) + try { + await file.savePicture('foo.jpg') + done.fail('test failed') + } catch(err) { + expect(err.message).toBe(`imageData can't be empty`) + } finally { + done() + } + }) + test(`binary information has to be correctly saved`, async done => { + expect.assertions(1) + try { + await file.savePicture('image', 'raboof') + let output = await file.readPicture('image') + expect(output).toBe('raboof') + } catch(err) { + expect(err.message).toBe("issue with writing") + } finally { + done() + } + }) +}) describe('readPicture()', () => { beforeEach( async() => { }) diff --git a/exercises/07_unit_testing/file_system/unit tests/image b/exercises/07_unit_testing/file_system/unit tests/image new file mode 100644 index 00000000..a9acf68e --- /dev/null +++ b/exercises/07_unit_testing/file_system/unit tests/image @@ -0,0 +1 @@ +raboof \ No newline at end of file From 213478adc03f1cd8570afb1a9655948f9178ba51 Mon Sep 17 00:00:00 2001 From: harjaus Date: Fri, 8 Nov 2019 16:02:12 +0000 Subject: [PATCH 43/70] Removed unnecessary files --- exercises/07_unit_testing/file_system/unit tests/foobar | 1 - exercises/07_unit_testing/file_system/unit tests/image | 1 - 2 files changed, 2 deletions(-) delete mode 100644 exercises/07_unit_testing/file_system/unit tests/foobar delete mode 100644 exercises/07_unit_testing/file_system/unit tests/image diff --git a/exercises/07_unit_testing/file_system/unit tests/foobar b/exercises/07_unit_testing/file_system/unit tests/foobar deleted file mode 100644 index 1c46fdb1..00000000 --- a/exercises/07_unit_testing/file_system/unit tests/foobar +++ /dev/null @@ -1 +0,0 @@ -foobar2 diff --git a/exercises/07_unit_testing/file_system/unit tests/image b/exercises/07_unit_testing/file_system/unit tests/image deleted file mode 100644 index a9acf68e..00000000 --- a/exercises/07_unit_testing/file_system/unit tests/image +++ /dev/null @@ -1 +0,0 @@ -raboof \ No newline at end of file From d4fc244457e1b1b0939af8bfe609c856312535bb Mon Sep 17 00:00:00 2001 From: "Balazs Bordas (bordasb)" Date: Mon, 11 Nov 2019 14:21:37 +0000 Subject: [PATCH 44/70] minor typo and semantic fixes --- 02 HTTP.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/02 HTTP.md b/02 HTTP.md index 338c6333..0a047be3 100644 --- a/02 HTTP.md +++ b/02 HTTP.md @@ -14,7 +14,7 @@ HTTP uses a [request-response](https://en.wikipedia.org/wiki/Request–response) When this request is received by the server it analyses the information provided and sends a _response_ back to the client. This typically might include: -1. The [HTTP message body](https://en.wikipedia.org/wiki/HTTP_message_body), typically the data that was requested such as a html page or image. +1. The [HTTP message body](https://en.wikipedia.org/wiki/HTTP_message_body), typically the data that was requested such as an HTML page or image. 2. A [status code](https://searchengineland.com/the-ultimate-guide-to-http-status-codes-and-headers-for-seo-302786), a number representing the success or otherwise of the request. 3. Extra information such as the format the data is in sent as [response headers](https://developer.mozilla.org/en-US/docs/Glossary/Response_header). @@ -60,7 +60,7 @@ Study the `index.js` script in the `exercises/02_http/01_url/` directory. 1. The `let` keyword defines a _mutable variable_ which can change its value. 2. The `const` keyword defines an _immutable variable_. Once a value is assigned it cannot be changed, these are sometime called _constants_. 6. The main part of the script defines the _routes_ and we will be covering these in more detail as we progress through the lab. -7. Right at the end (line 123) we start the server on the defined port and _export_ the _koa object_ `app`. By exporting it we can import the script into our automated test suite (briefly covered in the previous lab). +7. Right at the end (line 161) we start the server on the defined port and _export_ the _koa object_ `app`. By exporting it we can import the script into our automated test suite (briefly covered in the previous lab). Now start the server: From 2cf65679808f0a3be0e819df2ac32ba78676d683 Mon Sep 17 00:00:00 2001 From: "Balazs Bordas (bordasb)" Date: Tue, 12 Nov 2019 01:53:42 +0000 Subject: [PATCH 45/70] corrected the bracket notation example --- 02 HTTP.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/02 HTTP.md b/02 HTTP.md index 0a047be3..94fb440e 100644 --- a/02 HTTP.md +++ b/02 HTTP.md @@ -112,7 +112,7 @@ Each value in an object can be extracted using one or two different syntaxes: ```javascript const firstName = name.first -const lastName = name['last'] +const lastName = name['last name'] const prop = year const dobYear = name.dob.[prop] ``` From 9ff513609e9987550215511101a1ba49dd92ae60 Mon Sep 17 00:00:00 2001 From: "Balazs Bordas (bordasb)" Date: Tue, 12 Nov 2019 14:52:57 +0000 Subject: [PATCH 46/70] fixed displayed directory tree --- 03 HTML5.md | 1 - 1 file changed, 1 deletion(-) diff --git a/03 HTML5.md b/03 HTML5.md index 26d6eda5..92af98c5 100644 --- a/03 HTML5.md +++ b/03 HTML5.md @@ -8,7 +8,6 @@ In this worksheet you will be learning about the markup language HTML which is c ``` └── 03_html    ├── 01_syntax -    ├── 02_hypermedia    ├── 02_lists    ├── 03_hypermedia    ├── 04_tables From 92f29a5586f99c932208bcc408f7065f25e61971 Mon Sep 17 00:00:00 2001 From: "Balazs Bordas (bordasb)" Date: Tue, 12 Nov 2019 14:54:42 +0000 Subject: [PATCH 47/70] fixed displayed directory tree --- 03 HTML5.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/03 HTML5.md b/03 HTML5.md index 92af98c5..32ba6bae 100644 --- a/03 HTML5.md +++ b/03 HTML5.md @@ -11,8 +11,8 @@ In this worksheet you will be learning about the markup language HTML which is c    ├── 02_lists    ├── 03_hypermedia    ├── 04_tables -    ├── 05_forms - ├── 06_semantic +    ├── 05_semantic + ├── 06_markdown    └── template.html ``` From 7af1d8d6c420878771e1191a17e1ede1978b351d Mon Sep 17 00:00:00 2001 From: "Mark Tyers (aa7401)" Date: Thu, 14 Nov 2019 18:36:30 +0000 Subject: [PATCH 48/70] Added Notes on managing modules --- 06 Code Quality.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/06 Code Quality.md b/06 Code Quality.md index 81cdda6f..dff65bfa 100644 --- a/06 Code Quality.md +++ b/06 Code Quality.md @@ -56,6 +56,17 @@ In the previous example you ran the script from the terminal. If you open a proj ![Scripts Explorer](exercises/.images/npm_scripts.png) +### 1.2 Managing Modules + +As you continue developing your project you will both be adding additional dependencies and stop using some existing ones. In addition certain modules receive major updates. All these issues can cause a lack of consistency between the package manifest and the modules in use by your code. Thankfully there is a useful tool called `npm-check` to identify where there might be issues. Once installed you can run it from the `node_modules/.bin/` directory just like other binaries. + +```shell +npm install --save-dev npm-check +./node_modules/.bin/npm-check +``` + +This will generate a detailed report to help you manage your package dependencies. + ## 2 Modularisation Next you will need to do is to split your code up to make it easier to understand. Take a look at the `06_code_quality/todo/` project. If you run this you will see that it is a simple shopping list app where you can add multiple items and quantities. Currently all the functionality is contained in the `index.js` file. Locate the `modules/list.js` file. This declares a new Object Prototype called `List` which includes all the necessary functionality for the app. At the moment this is not being used by the app. From 30c5f0b1c1c3d90e28c5e37c63636e267a77dc6e Mon Sep 17 00:00:00 2001 From: Balazs Laszlo Bordas Date: Mon, 25 Nov 2019 00:01:25 +0000 Subject: [PATCH 49/70] improvements made to file_system mock-fs exercise --- .../07_unit_testing/file_system/modules/file.js | 13 +++++-------- .../file_system/unit tests/file.spec.js | 3 +-- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/exercises/07_unit_testing/file_system/modules/file.js b/exercises/07_unit_testing/file_system/modules/file.js index e2eab795..9755a6a1 100644 --- a/exercises/07_unit_testing/file_system/modules/file.js +++ b/exercises/07_unit_testing/file_system/modules/file.js @@ -8,11 +8,7 @@ module.exports = class File { async savePicture(filename, imageData) { if (filename === undefined || filename === '') throw new Error(`filename can't be empty`) if (imageData === undefined || imageData === '') throw new Error(`imageData can't be empty`) - try { - fs.writeFileSync(filename, imageData, 'binary') - } catch(err) { - throw err - } + fs.writeFileSync(filename, imageData, 'binary') } async readPicture(filename) { @@ -20,10 +16,11 @@ module.exports = class File { try { return fs.readFileSync(filename, 'binary') } catch(err) { - if (err.message == `ENOENT: no such file or directory, open '${filename}'`) - throw new Error("file doesn't exist") - else + if (err.message == `ENOENT: no such file or directory, open '${filename}'`) { + throw new Error(`file '${filename}' doesn't exist`) + } else { throw err + } } } } diff --git a/exercises/07_unit_testing/file_system/unit tests/file.spec.js b/exercises/07_unit_testing/file_system/unit tests/file.spec.js index ef7c4ec8..82f74ecd 100644 --- a/exercises/07_unit_testing/file_system/unit tests/file.spec.js +++ b/exercises/07_unit_testing/file_system/unit tests/file.spec.js @@ -101,7 +101,7 @@ describe('readPicture()', () => { await file.readPicture('nonExistent.txt') done.fail('test failed') } catch(err) { - expect(err.message).toBe("file doesn't exist") + expect(err.message).toBe("file 'nonExistent.txt' doesn't exist") } finally { done() } @@ -110,7 +110,6 @@ describe('readPicture()', () => { expect.assertions(1) try { let output = await file.readPicture('test/foobar') - //console.log("Output: ", output) expect(output).toBe("foobar2\n") } catch(err) { console.log(err) From 333dcb2e361610c4b246acabfae550afa93e19ba Mon Sep 17 00:00:00 2001 From: Balazs Laszlo Bordas Date: Mon, 25 Nov 2019 00:46:04 +0000 Subject: [PATCH 50/70] #28 create example to demonstrate saving file to mock-fs --- .../07_unit_testing/file_system/modules/image | 1 - .../file_system/modules/mockImage.js | 20 ++++++++++++++++++ .../file_system/modules/nodelogo.png | Bin 0 -> 4512 bytes .../file_system/unit tests/trymockfs.js | 6 ++++-- 4 files changed, 24 insertions(+), 3 deletions(-) delete mode 100644 exercises/07_unit_testing/file_system/modules/image create mode 100644 exercises/07_unit_testing/file_system/modules/mockImage.js create mode 100644 exercises/07_unit_testing/file_system/modules/nodelogo.png diff --git a/exercises/07_unit_testing/file_system/modules/image b/exercises/07_unit_testing/file_system/modules/image deleted file mode 100644 index a9acf68e..00000000 --- a/exercises/07_unit_testing/file_system/modules/image +++ /dev/null @@ -1 +0,0 @@ -raboof \ No newline at end of file diff --git a/exercises/07_unit_testing/file_system/modules/mockImage.js b/exercises/07_unit_testing/file_system/modules/mockImage.js new file mode 100644 index 00000000..c8937a0d --- /dev/null +++ b/exercises/07_unit_testing/file_system/modules/mockImage.js @@ -0,0 +1,20 @@ +// example file that demonstrates the File class and mock-fs working simultaneously + +'use strict' + +const mock = require('mock-fs') +const File = require('./file') +const file = new File() + +const fileName = 'nodelogo.png' + +const mockImageReadWrite = async (fileName) => { + const imageReadFromFs = await file.readPicture(fileName) + mock({}) + file.savePicture(fileName, imageReadFromFs) + const imageReadFromMock = await file.readPicture(fileName) + mock.restore() + file.savePicture(`mocked_${fileName}`, imageReadFromMock) +} + +mockImageReadWrite(fileName) diff --git a/exercises/07_unit_testing/file_system/modules/nodelogo.png b/exercises/07_unit_testing/file_system/modules/nodelogo.png new file mode 100644 index 0000000000000000000000000000000000000000..33201619e42a6e42b35fc77431a2725f20683110 GIT binary patch literal 4512 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 { if (err) throw new Error(err) console.log(data) }) - -mock.restore() +// shouldn't be restored prematurely when dealing with async code +// mock.restore() From d8ae63493e258a408f2978f6e98a3cc1dc964569 Mon Sep 17 00:00:00 2001 From: Balazs Laszlo Bordas Date: Mon, 25 Nov 2019 01:33:49 +0000 Subject: [PATCH 51/70] #28 webserver handles incoming files --- .../07_unit_testing/file_system/index.js | 88 +++++++++++-------- .../07_unit_testing/file_system/package.json | 50 +++++------ .../file_system/views/pictures.html | 40 ++++----- 3 files changed, 94 insertions(+), 84 deletions(-) diff --git a/exercises/07_unit_testing/file_system/index.js b/exercises/07_unit_testing/file_system/index.js index b11dc9dd..54972cc9 100644 --- a/exercises/07_unit_testing/file_system/index.js +++ b/exercises/07_unit_testing/file_system/index.js @@ -1,39 +1,49 @@ -#!/usr/bin/env node - -'use strict' - -const File = require('./modules/file') - -const Koa = require('koa') -const Router = require('koa-router') -const BodyParser = require('koa-bodyparser') -const views = require('koa-views') -const status = require('http-status-codes') - -const port = 8080 -const file = new File() - -const app = new Koa() -app.use(views(`${__dirname}/views`, { extension: 'html' }, {map: { handlebars: 'handlebars' }})) -app.use(BodyParser({ - encoding: 'multipart/form-data' -})) - -const router = new Router() - -router.get('/', async ctx => { - await ctx.render('pictures.html') -}) -router.post('/', ctx => { - try { - console.log('processing the post request') - const body = ctx.request.body - console.log(body.fileUpload) - } catch(err) { - ctx.status = status.UNPROCESSABLE_ENTITY - ctx.body = err.message - } -}) - -app.use(router.routes()) -module.exports = app.listen(port, () => console.log(`listening on port ${port}`)) +#!/usr/bin/env node +//todo: fix this +'use strict' + +const File = require('./modules/file') + +const Koa = require('koa') +const Router = require('koa-router') +const koaForm = require("formidable-upload-koa"); +const views = require('koa-views') +const status = require('http-status-codes') + +const port = 8080 +const file = new File() + +const app = new Koa() +app.use(views(`${__dirname}/views`, { extension: 'html' }, {map: { handlebars: 'handlebars' }})) +// app.use(Body({ +// encoding: 'multipart/form-data' +// })) +// app.use(BodyParser({ +// formidable:{uploadDir: './uploads'}, //This is where the files would come +// multipart: true, +// urlencoded: true +// })) +const options = { + uploadDir: `./upload/`, + keepExtensions: true +} +const router = new Router() + +router.get('/', async ctx => { + await ctx.render('pictures.html') +}) +router.post('/', koaForm(options), ctx => { + try { + console.log('processing the post request') + // const body = ctx.request.body + // console.log(ctx.request.body) + console.log(ctx.req.files) + } catch(err) { + console.log(err) + ctx.status = status.UNPROCESSABLE_ENTITY + ctx.body = err.message + } +}) + +app.use(router.routes()) +module.exports = app.listen(port, () => console.log(`listening on port ${port}`)) diff --git a/exercises/07_unit_testing/file_system/package.json b/exercises/07_unit_testing/file_system/package.json index 001f3a84..9a8c79ec 100644 --- a/exercises/07_unit_testing/file_system/package.json +++ b/exercises/07_unit_testing/file_system/package.json @@ -1,25 +1,25 @@ -{ - "name": "file_system", - "version": "1.0.0", - "description": "mock-fs", - "main": "index.js", - "dependencies": { - "callsites": "^3.1.0", - "fs": "^0.0.1-security", - "http-status-codes": "^1.4.0", - "koa": "^2.11.0", - "koa-bodyparser": "^4.2.1", - "koa-router": "^7.4.0", - "koa-views": "^6.2.1" - }, - "devDependencies": { - "jest": "^24.9.0", - "mock-fs": "^4.10.3", - "supertest": "^4.0.2" - }, - "scripts": { - "test": "jest --config=./jest-test.config.js --coverage" - }, - "author": "", - "license": "ISC" -} +{ + "name": "file_system", + "version": "1.0.0", + "description": "mock-fs", + "main": "index.js", + "dependencies": { + "callsites": "^3.1.0", + "formidable-upload-koa": "^1.0.1", + "fs": "^0.0.1-security", + "http-status-codes": "^1.4.0", + "koa": "^2.11.0", + "koa-router": "^7.4.0", + "koa-views": "^6.2.1" + }, + "devDependencies": { + "jest": "^24.9.0", + "mock-fs": "^4.10.3", + "supertest": "^4.0.2" + }, + "scripts": { + "test": "jest --config=./jest-test.config.js --coverage" + }, + "author": "", + "license": "ISC" +} diff --git a/exercises/07_unit_testing/file_system/views/pictures.html b/exercises/07_unit_testing/file_system/views/pictures.html index 5f8ff74d..1d0372f5 100644 --- a/exercises/07_unit_testing/file_system/views/pictures.html +++ b/exercises/07_unit_testing/file_system/views/pictures.html @@ -1,20 +1,20 @@ - - - - - - - Pictures - - -

Save new pictures

-
- Image to be uploaded: -
- -

- -
-

Saved pictures

- - \ No newline at end of file + + + + + + + Pictures + + +

Save new pictures

+
+ Image to be uploaded: +
+ +

+ +
+

Saved pictures

+ + From b166a8cd5b27c465a0721b963cff63a2e4aca5f9 Mon Sep 17 00:00:00 2001 From: Mark Tyers Date: Fri, 29 Nov 2019 17:17:07 +0000 Subject: [PATCH 52/70] Added New Materials --- 05 JavaScript.md | 46 ++++++++++++++++++++--------- exercises/05_javascript/counties.js | 16 ++++++++++ 2 files changed, 48 insertions(+), 14 deletions(-) create mode 100755 exercises/05_javascript/counties.js diff --git a/05 JavaScript.md b/05 JavaScript.md index 1cfdf9ae..02081352 100644 --- a/05 JavaScript.md +++ b/05 JavaScript.md @@ -320,11 +320,28 @@ This will retrieve the value of the grade property if defined and store it in th 3. Use the `for...in` statement to iterate over this `study01` object printing out all of the _module codes_. 4. Use the `for...of` statement to print out all of the _module names_. -### 3.3 JSON Data +### 3.3 Context + +Every JavaScript object has a reference to its current execution **context**. This refers to how the function was called. To reference the current context we use the `this` object. + +You should start by opening the `counties.js` file and studying it carefully. This simple script demonstrates some of the key features of working with context. + +1. Lines 5-7 define a simple function called `print()` which prints the context object `this`. +2. Lines 9-11 define two objects: + 1. Each contains two properties, a `name` string and the `print()` function. + 2. Since we are storing the `print()` function in a property with the same name we can use the ES6 Object Shorthand syntax. The second object uses this. +3. Line 13 calls the `print()` function from the global context. This prints an empty object. +4. Lines 15 and 16 call the `print()` function from inside each of the objects. This demonstrates that the `name` properties are part of the object context. + +If you look at the console output you will notice that, when we access `this` from _inside_ an object, it is bound to the object from where it was called. + +Because we are operating in _strict mode_, when we try to access `this` in the global context it returns `undefined`. + +### 3.4 JSON Data JSON (JavaScript Object Notation) is a standard text-based format to represent structured data. This is very useful as it means we can take any JavaScript object and convert it into a text string. This can then be saved to disk or posted to a web server, etc. It also means that you can take a JSON-formatted text string and convert it into a complex JavaScript object! -#### 3.3.1 Parsing JSON Strings into Objects +#### 3.4.1 Parsing JSON Strings into Objects It is trivial to convert a JSON string into an object using the `JSON.parse()` function. Study the following code carefully: @@ -335,7 +352,7 @@ const employee = JSON.parse(jsonstring) Notice that in a JSON string all the properties and values _must_ be enclosed in double-quotes. The constant `jsonstring` is a **String** but `employee` is a standard JavaScript **Object**. -#### 3.3.2 Converting Objects into Strings +#### 3.4.2 Converting Objects into Strings In the same way that we can convert a JSON string into a JavaScript object we can also do the reverse. @@ -365,7 +382,7 @@ const jsonstring = JSON.stringify(employee, null, 2) This inserts newline and space characters to make the string more readable. The third parameter defines the level of indent (in spaces). -#### 3.3.3 Test Your Understanding +#### 3.4.3 Test Your Understanding Lets apply our knowledge of callbacks to implement a simple quotes tool. @@ -376,7 +393,7 @@ Lets apply our knowledge of callbacks to implement a simple quotes tool. 5. Modify the code so that it only prints the quotes string (not the entire object). 6. Convert the `university` object from the previous exercise into a JSON string and save it to the filesystem as `university.json`. -### 3.3 ECMA6 Object Destructuring +### 3.5 ECMA6 Object Destructuring There are situations where we want to retrieve multiple object properties and store then in different variables, for example: @@ -405,11 +422,11 @@ console.log(first) // prints 'Colin' console.log(dept) // prints 'Computing' ``` -#### 3.3.1 Test Your Understanding +#### 3.5.1 Test Your Understanding 1. Take the `university` object you created in an earlier exercise and use a single line destructuring assignment to create three variables, `year1`, `year2` and `year3`. -### 3.4 Getters and Setters +### 3.6 Getters and Setters Most object properties are simple values and you can simply assign a value. Sometimes however properties need to be calculated. One solution is to store a function as one of the properties however we would need to call a function to retrieve the value: @@ -469,12 +486,12 @@ const employee = { employee.name = 'Micky Mouse' ``` -#### 3.4.1 Test Your Understanding +#### 3.6.1 Test Your Understanding 1. Print the person's details in an easy to understand sentence. 2. Add a getter to return the number of years the employee has been working for the company, you will need to round this down to a whole number. You should make use of one of the static methods of the built-in [Math](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math) object. -### 3.5 Modifying Objects +### 3.7 Modifying Objects Once an object has been created it can be modified in several ways. @@ -510,7 +527,7 @@ const employee = { delete employee.department ``` -### 3.6 Undefined Values +### 3.8 Undefined Values Undefined Objects @@ -531,13 +548,13 @@ const postCode = employee.address && employee.address.postCode console.log(postCode) // returns undefined ``` -#### 3.6.1 Test Your Understanding +#### 3.8.1 Test Your Understanding 1. Modify the code to handle bad data: 1. Remove the startYear property. 2. Set the startYear property to a String. -### 3.7 Object Prototypes +### 3.9 Object Prototypes All JavaScript object (such as String, Number, Array, etc.) inherit properties and methods from a **prototype**. This also applies to any new objects you create. Since JavaScript does not support _traditional_ classes, this becomes the way to add new functionality. Let's look at a simple example. @@ -559,7 +576,7 @@ There are a couple of important concepts here. 2. Inside the function we manipulate the `this` object which represents the value of the object. 1. Replace the `function() {}` construct with an arrow function. What happens when you run the script? -#### 3.7.1 Test Your Understanding +#### 3.9.1 Test Your Understanding 1. Extend the `Array` object by adding a function `toStr()` that takes an array and turns it into a string. You will need to use the [`Array.join()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/join) function. @@ -627,7 +644,8 @@ class Person { constructor(name, startYear) { this.name = name this.startYear = startYear || currentYear - this.years = currentYear - this.startYear + this.years = currentYear - this.startYear + return this } } ``` diff --git a/exercises/05_javascript/counties.js b/exercises/05_javascript/counties.js new file mode 100755 index 00000000..be28ef39 --- /dev/null +++ b/exercises/05_javascript/counties.js @@ -0,0 +1,16 @@ +#!/usr/bin/env node + +'use strict' + +function print() { + console.log(this) +} + +const obj1 = { name: 'Kent', print: print } +// this example uses the ES6 Object Shorthand syntax +const obj2 = { name: 'Cornwall', print } + +print() + +obj1.print() +obj2.print() From 9cc86d43bfc1a12c0c288f947c96b17375ed05ba Mon Sep 17 00:00:00 2001 From: Mark Tyers Date: Sun, 12 Jan 2020 11:03:15 +0000 Subject: [PATCH 53/70] Added Manual Mock Example --- exercises/07_unit_testing/mocking/index.js | 8 ++++++ .../07_unit_testing/mocking/jest.config.js | 19 +++++++++++++ .../07_unit_testing/mocking/modules/todo.js | 26 ++++++++++++++++++ .../07_unit_testing/mocking/package.json | 23 ++++++++++++++++ .../mocking/tests/__mocks__/mysql-promise.js | 27 +++++++++++++++++++ .../mocking/tests/todo.test.js | 16 +++++++++++ 6 files changed, 119 insertions(+) create mode 100644 exercises/07_unit_testing/mocking/index.js create mode 100644 exercises/07_unit_testing/mocking/jest.config.js create mode 100644 exercises/07_unit_testing/mocking/modules/todo.js create mode 100644 exercises/07_unit_testing/mocking/package.json create mode 100644 exercises/07_unit_testing/mocking/tests/__mocks__/mysql-promise.js create mode 100644 exercises/07_unit_testing/mocking/tests/todo.test.js diff --git a/exercises/07_unit_testing/mocking/index.js b/exercises/07_unit_testing/mocking/index.js new file mode 100644 index 00000000..42df9deb --- /dev/null +++ b/exercises/07_unit_testing/mocking/index.js @@ -0,0 +1,8 @@ + +(async () => { + const User = require('./modules/todo') + const user = await new User() + await user.addRecord('bread', 2) + console.log(JSON.stringify(await user.getAll(), null, 2)) + return +})() diff --git a/exercises/07_unit_testing/mocking/jest.config.js b/exercises/07_unit_testing/mocking/jest.config.js new file mode 100644 index 00000000..ed2be75b --- /dev/null +++ b/exercises/07_unit_testing/mocking/jest.config.js @@ -0,0 +1,19 @@ + +module.exports = { + displayName: 'test', + verbose: true, + collectCoverage: true, + coverageThreshold: { + global: { + branches: 0, + functions: 0, + lines: 0, + statements: 0 + } + }, + testPathIgnorePatterns: [ + '/node_modules/', + '/__tests__/fixtures/', + ], + roots: ['/tests'] +} diff --git a/exercises/07_unit_testing/mocking/modules/todo.js b/exercises/07_unit_testing/mocking/modules/todo.js new file mode 100644 index 00000000..850008ff --- /dev/null +++ b/exercises/07_unit_testing/mocking/modules/todo.js @@ -0,0 +1,26 @@ + +const MySQL = require('mysql-promise') + +module.exports = class User { + constructor() { + return( async() => { + this.db = await new MySQL() + this.db.configure({ "host": "localhost", "user": "root", "password": "p455w0rd", "database": "test"}) + await this.db.query('CREATE TABLE IF NOT EXISTS list(id INTEGER PRIMARY KEY AUTO_INCREMENT, item TEXT, qty INTEGER)') + return this + })() + } + async addRecord(item, qty) { + const sql = `INSERT INTO list(item, qty) VALUES("${item}", ${qty})` + await this.db.query(sql) + return true + } + async getAll() { + const sql = 'SELECT item, qty FROM list' + const data = await this.db.query(sql) + return data + } + async close() { + await this.db.end() + } +} diff --git a/exercises/07_unit_testing/mocking/package.json b/exercises/07_unit_testing/mocking/package.json new file mode 100644 index 00000000..915eb43f --- /dev/null +++ b/exercises/07_unit_testing/mocking/package.json @@ -0,0 +1,23 @@ +{ + "name": "mocking", + "version": "1.0.0", + "description": "", + "main": "index.js", + "directories": { + "test": "tests" + }, + "dependencies": { + "handlebars": "^4.5.3", + "mysql-promise": "^5.0.0", + "prompt-async": "^0.9.9", + "sqlite-async": "^1.0.12" + }, + "devDependencies": { + "jest": "^24.9.0" + }, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC" +} diff --git a/exercises/07_unit_testing/mocking/tests/__mocks__/mysql-promise.js b/exercises/07_unit_testing/mocking/tests/__mocks__/mysql-promise.js new file mode 100644 index 00000000..255fd8b9 --- /dev/null +++ b/exercises/07_unit_testing/mocking/tests/__mocks__/mysql-promise.js @@ -0,0 +1,27 @@ + +const sqlite = require('sqlite-async') + +class DB { + constructor() { + return ( async() => { + console.log('MOCK') + this.db = await sqlite.open(':memory:') + return this + })() + } + configure() { return true } + async isConfigured() { return true } + async getConnection() { return true } + async query(sql) { + sql = sql.replace('AUTO_INCREMENT', 'AUTOINCREMENT') //mysql uses an underscore! + const data = await this.db.all(sql) + return [ data, [ { db: 'test', table: 'mock'} ] ] + return data + } + async end() { + await this.db.close() + return true + } +} + +module.exports = DB diff --git a/exercises/07_unit_testing/mocking/tests/todo.test.js b/exercises/07_unit_testing/mocking/tests/todo.test.js new file mode 100644 index 00000000..7ea5944a --- /dev/null +++ b/exercises/07_unit_testing/mocking/tests/todo.test.js @@ -0,0 +1,16 @@ + +const User = require('../modules/todo') + +describe('simple test', () => { + test('adding a new record', async done => { + const user = await new User() + const id = await user.addRecord('bread', 4) + const data = await user.getAll() + await user.close() + expect(data[0]).toEqual([ { item: 'bread', qty: 4 } ]) + done() + }) +}) + +// if you get lots of handlebars warnings you need to install an older version: +// npm install handlebars@4.5.3 From d43bfb864e2967e9c1efffd2620b9beb90f5a269 Mon Sep 17 00:00:00 2001 From: Balazs Laszlo Bordas Date: Sat, 25 Jan 2020 17:29:47 +0000 Subject: [PATCH 54/70] removed unintentional inserted solutions by nathwan2 from 02/01/index.js, added content about package.json to 02 HTTP.md, created 02/01/package.json --- 02 HTTP.md | 36 +++++++++++++++++++++---- exercises/01_setup/index.js | 1 - exercises/02_http/01_url/index.js | 39 ++++++--------------------- exercises/02_http/01_url/package.json | 22 +++++++++++++++ 4 files changed, 61 insertions(+), 37 deletions(-) create mode 100644 exercises/02_http/01_url/package.json diff --git a/02 HTTP.md b/02 HTTP.md index 94fb440e..12020aa2 100644 --- a/02 HTTP.md +++ b/02 HTTP.md @@ -47,20 +47,46 @@ We will be working through some exercises that make use of all of these. Study the `index.js` script in the `exercises/02_http/01_url/` directory. -1. If you study lines 4-10 of `index.js` you will see a list of the modules we need to install. Refer the the previous lab if you get stuck at this point: +1. If you study lines 11-15 of `index.js` you will see a list of the modules we need to install. Refer the the previous lab if you get stuck at this point: 1. `koa` 2. `koa-router` 3. `koa-bodyparser` 4. `koa-static` 5. `js2xmlparser` + - **You can install all these dependencies by simply running 'npm install' in the terminal.** + - This command installs all the documented dependencies from the `package.json` file, which is already preconfigured in this case. + - **Have a look at your `package.json` file and understand its contents** + - When you are creating a new _project_, **you have to do this yourself**: + 1. Use the `npm init` command to create the package.json file + - You can leave all the options default, just leave them empty and keep pressing enter + - Alternatively you can run `npm init --yes`, it will simply leave everything default + 2. Install the dependencies for the first time using the `-S` _switch_ with `npm install` + - e.g.: `npm install -S koa koa-bodyparser` + - This would add something like this to the `package.json` file: + ``` + "dependencies": { + "koa": "^2.11.0", + "koa-bodyparser": "^4.2.1" + } + ``` + - When you next run `npm install -S `, the given package's _newest version_ will be simply added to the list, or in case of a new version for a _previously listed_ dependency, the _version number_ will be updated + - This `-S` is just a short version of the `--save` _switch_ + - **You can use the alternative `--save-dev` switch to install and save _development dependencies_** + - Something that you wouldn't want to deploy, but is necessary for development + - E.g. we will use `jest` for testing, and `eslint` for linting during the development phase, but these shouldn't be required to be installed during deployment + 3. This `package.json` file is also useful to store _scripts_: + - Look at the following line: ` "start": "nodemon index.js"` + - This lets us simply type `npm start` in the terminal to start our application via _nodemon_ + - Nodemon is a great tool that restarts the application every time we save a file in the given folder, so we don't actually have to manually stop and restart it after every modification. + 2. The first line is the _shebang_, it tells the script what application is needed to run it. -3. Lines 4-10 import the module packages we need for our script to work. Koa is a modular framework, on its own it does very little but depends on plugins (middleware) for its functionality. -4. Lines 11-15 are where we configure the koa _middleware_. +3. Lines 11-15 import the module packages we need for our script to work. Koa is a modular framework, on its own it does very little but depends on plugins (middleware) for its functionality. +4. Lines 18-22 are where we configure the koa _middleware_. 5. We need two global variables in our script, one to store a list of items and the second to store the port number we will be using: 1. The `let` keyword defines a _mutable variable_ which can change its value. 2. The `const` keyword defines an _immutable variable_. Once a value is assigned it cannot be changed, these are sometime called _constants_. 6. The main part of the script defines the _routes_ and we will be covering these in more detail as we progress through the lab. -7. Right at the end (line 161) we start the server on the defined port and _export_ the _koa object_ `app`. By exporting it we can import the script into our automated test suite (briefly covered in the previous lab). +7. Right at the end (line 138) we start the server on the defined port and _export_ the _koa object_ `app`. By exporting it we can import the script into our automated test suite (briefly covered in the previous lab). Now start the server: @@ -76,7 +102,7 @@ To do this we need to extract some data from the http object `ctx` which is the Start the server and access the `/books/1` route. What is displayed in the web browser? -1. Since we have not yet covered how to connect to a database, on line 34 we have defined a JavaScript array which contains 3 indexes, these are numbered 0-2. +1. Since we have not yet covered how to connect to a database, on line 41 we have defined a JavaScript array which contains 3 indexes, these are numbered 0-2. 2. Directly underneath this we have defined a route `/books/:index` which contains two **segments**: 1. The first matches the text `/books`, this works like all the routes we have seen previously. 2. The second, beginning with the colon (`:`) represents a **URL Parameter**. This represents one or more characters. diff --git a/exercises/01_setup/index.js b/exercises/01_setup/index.js index af07c3e0..ef00019f 100644 --- a/exercises/01_setup/index.js +++ b/exercises/01_setup/index.js @@ -10,4 +10,3 @@ const port = 8080 app.use(async ctx => ctx.body = 'Hello World') module.exports = app.listen(port, () => console.log(`listening on port ${port}`)) -//aasd \ No newline at end of file diff --git a/exercises/02_http/01_url/index.js b/exercises/02_http/01_url/index.js index 912dc44a..acf845f0 100644 --- a/exercises/02_http/01_url/index.js +++ b/exercises/02_http/01_url/index.js @@ -37,46 +37,23 @@ router.get('/anon', ctx => { // anon case }) -router.get('/books/:index/:index2', ctx => { - const books = ['The Hobbit', 'Alice in Wonderland', 'The Secret Garden','Animal Farm'] +router.get('/books/:index', ctx => { + const books = ['The Hobbit', 'Alice in Wonderland', 'The Secret Garden'] const parameters = ctx.params console.log(parameters) - - - if (parameters.index > 3 || parameters.index2 > 3) { - ctx.body = "Number cannot be greater than 3" - } - else if (isNaN(parameters.index) || isNaN(parameters.index2)){ - ctx.body = "A number must be entered" - } - else if (Number.isInteger(parameters.index)){ - ctx.body = "A whole number must be entered" - } - else{ - const title = books[parameters.index] - const title2 = books[parameters.index2] - ctx.body = title + title2 - } + const title = books[parameters.index] + ctx.body = title }) router.get('/name', ctx => ctx.body = JSON.stringify(ctx.query)) router.get('/hello/:name', ctx => { let myname = ctx.params.name - if(ctx.query.format === 'upper') myname = myname.toUpperCase() - else if (ctx.query.format === 'lower') myname = myname.toLowerCase() - else if (ctx.query.format === 'reverse'){ - var array1 = myname.split("") - console.log(array1) - var array2 = array1.reverse() - console.log(array2) - var array3 = array1.join("") - console.log(array3) - ctx.body = `hello ${array3}` - //myname = join(Array.reverse(myname.split())) - } + // only applies uppercase if formatting query exists - //ctx.body = `hello ${myname}` + if(ctx.query.format === 'upper') myname = myname.toUpperCase() + + ctx.body = `hello ${myname}` }) router.post('/form', ctx => { diff --git a/exercises/02_http/01_url/package.json b/exercises/02_http/01_url/package.json new file mode 100644 index 00000000..329d597e --- /dev/null +++ b/exercises/02_http/01_url/package.json @@ -0,0 +1,22 @@ +{ + "name": "01_url", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "start": "nodemon index.js", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC", + "dependencies": { + "js2xmlparser": "^4.0.0", + "koa": "^2.11.0", + "koa-bodyparser": "^4.2.1", + "koa-router": "^8.0.6", + "koa-static": "^5.0.0" + }, + "devDependencies": { + "nodemon": "^2.0.2" + } +} From 2bc3e3d40958e3d556c589dc682c7869f9d831d7 Mon Sep 17 00:00:00 2001 From: Balazs Laszlo Bordas Date: Sat, 25 Jan 2020 17:39:31 +0000 Subject: [PATCH 55/70] added guide about npm install -production --- 02 HTTP.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/02 HTTP.md b/02 HTTP.md index 12020aa2..b74829d0 100644 --- a/02 HTTP.md +++ b/02 HTTP.md @@ -63,7 +63,7 @@ Study the `index.js` script in the `exercises/02_http/01_url/` directory. 2. Install the dependencies for the first time using the `-S` _switch_ with `npm install` - e.g.: `npm install -S koa koa-bodyparser` - This would add something like this to the `package.json` file: - ``` + ```json "dependencies": { "koa": "^2.11.0", "koa-bodyparser": "^4.2.1" @@ -71,9 +71,11 @@ Study the `index.js` script in the `exercises/02_http/01_url/` directory. ``` - When you next run `npm install -S `, the given package's _newest version_ will be simply added to the list, or in case of a new version for a _previously listed_ dependency, the _version number_ will be updated - This `-S` is just a short version of the `--save` _switch_ - - **You can use the alternative `--save-dev` switch to install and save _development dependencies_** + - **You can use the alternative `--save-dev` switch to install and save them as _development dependencies_** - Something that you wouldn't want to deploy, but is necessary for development - E.g. we will use `jest` for testing, and `eslint` for linting during the development phase, but these shouldn't be required to be installed during deployment + - You are done with adding the dependencies, now simply use `npm install` to install all of them at once! + - If you don't want to install development dependencies, use `npm install --production` 3. This `package.json` file is also useful to store _scripts_: - Look at the following line: ` "start": "nodemon index.js"` - This lets us simply type `npm start` in the terminal to start our application via _nodemon_ From e01b52b1b008dfc30b309fb00014cac7bc5289e2 Mon Sep 17 00:00:00 2001 From: Balazs Laszlo Bordas Date: Sat, 25 Jan 2020 19:25:11 +0000 Subject: [PATCH 56/70] fixed dependencies in package.json, added start script --- exercises/07_unit_testing/todo/package.json | 61 ++++++++++----------- 1 file changed, 29 insertions(+), 32 deletions(-) diff --git a/exercises/07_unit_testing/todo/package.json b/exercises/07_unit_testing/todo/package.json index ace21014..cd3afb2c 100644 --- a/exercises/07_unit_testing/todo/package.json +++ b/exercises/07_unit_testing/todo/package.json @@ -1,32 +1,29 @@ -{ - "name": "todo", - "version": "1.0.0", - "description": "", - "main": "index.js", - "scripts": { - "linter": "node_modules/.bin/eslint .", - "test": "node_modules/.bin/jest --coverage --runInBand" - }, - "author": "", - "license": "ISC", - "dependencies": { - "handlebars": "^4.3.0", - "http-status-codes": "^1.3.2", - "koa": "^2.8.1", - "koa-bodyparser": "^4.2.1", - "koa-handlebars": "^1.0.0", - "koa-hbs-renderer": "^1.2.0", - "koa-router": "^7.4.0", - "koa-static": "^5.0.0", - "koa-views": "^6.2.1" - }, - "devDependencies": { - "jest": "^24.9.0", - "supertest": "^4.0.2" - }, - "jest": { - "projects": [ - "/jest-test.config.js" - ] - } -} +{ + "name": "todo", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "start": "nodemon index.js", + "linter": "node_modules/.bin/eslint .", + "test": "node_modules/.bin/jest --coverage --runInBand" + }, + "author": "", + "license": "ISC", + "jest": { + "projects": [ + "/jest-test.config.js" + ] + }, + "dependencies": { + "koa": "^2.11.0", + "koa-bodyparser": "^4.2.1", + "koa-hbs-renderer": "^1.2.0", + "koa-router": "^8.0.6", + "koa-static": "^5.0.0" + }, + "devDependencies": { + "jest": "^25.1.0", + "nodemon": "^2.0.2" + } +} From a5d0506ac3d285caabd19d1b057b2ffe4ac02ae2 Mon Sep 17 00:00:00 2001 From: Balazs Laszlo Bordas Date: Sat, 25 Jan 2020 19:31:07 +0000 Subject: [PATCH 57/70] removed npm-debug.log bloat file from root --- npm-debug.log | 19 ------------------- 1 file changed, 19 deletions(-) delete mode 100644 npm-debug.log diff --git a/npm-debug.log b/npm-debug.log deleted file mode 100644 index 74e9b8d4..00000000 --- a/npm-debug.log +++ /dev/null @@ -1,19 +0,0 @@ -0 info it worked if it ends with ok -1 verbose cli [ '/usr/bin/node', '/usr/bin/npm', 'run', 'test' ] -2 info using npm@3.5.2 -3 info using node@v8.10.0 -4 verbose stack Error: ENOENT: no such file or directory, open '/home/anir/foundation/package.json' -5 verbose cwd /home/anir/foundation -6 error Linux 5.0.0-23-generic -7 error argv "/usr/bin/node" "/usr/bin/npm" "run" "test" -8 error node v8.10.0 -9 error npm v3.5.2 -10 error path /home/anir/foundation/package.json -11 error code ENOENT -12 error errno -2 -13 error syscall open -14 error enoent ENOENT: no such file or directory, open '/home/anir/foundation/package.json' -15 error enoent ENOENT: no such file or directory, open '/home/anir/foundation/package.json' -15 error enoent This is most likely not a problem with npm itself -15 error enoent and is related to npm not being able to find a file. -16 verbose exit [ -2, true ] From 57865744749f9c73d4ffada9789e247cc6c09095 Mon Sep 17 00:00:00 2001 From: Balazs Laszlo Bordas Date: Sat, 25 Jan 2020 19:43:58 +0000 Subject: [PATCH 58/70] removed unnecessarily pasted example code which came from 07 Unit Testing.md --- .../todo/unit tests/todo.spec.js | 133 ++++++++---------- 1 file changed, 56 insertions(+), 77 deletions(-) diff --git a/exercises/07_unit_testing/todo/unit tests/todo.spec.js b/exercises/07_unit_testing/todo/unit tests/todo.spec.js index 2c46bac0..bd5fd3fe 100644 --- a/exercises/07_unit_testing/todo/unit tests/todo.spec.js +++ b/exercises/07_unit_testing/todo/unit tests/todo.spec.js @@ -1,77 +1,56 @@ - -'use strict' - -const todo = require('../modules/todo.js') - -beforeAll( async() => { - // stuff to do before any of the tests run -}) - -afterAll( async() => { - // runs after all the tests have completed -}) - -describe('add()', () => { - // block of tests - beforeEach( async() => { - todo.clear() - }) - afterEach( async() => { - // runs after each test completes - }) - test('add a single item', async done => { - expect.assertions(1) - try { - todo.add('bread', 3) - expect(todo.countItems()).toBe(1) - } catch(err) { - done.fail(err) - } finally { - done() - } - }) - test('qty must be a number', async done => { - expect.assertions(1) - try { - todo.add('bread', 'three') - done.fail('test failed') - } catch(err) { - expect(err.message).toBe('qty must be a number') - } finally { - done() - } - }) - - // New test goes HERE! - test('duplicates should increase qty', async done => { - expect.assertions(2) - try { - // ACT - todo.add('bread', 4) - todo.add('bread', 2) - // ASSERT - const count = todo.countItems() - expect(count).toBe(1) - const data = todo.getAll() - const qty = data[0].qty - expect(qty).toEqual(6) - } catch(err) { - done.fail('test failed') - } finally { - done() - } - }) - -}) - -describe('delete()', () => { - // any tests for the delete() function should be written here -}) - -describe('getAll()', () => { - // any tests for the getAll() function should be written here -}) - -describe('clear()', () => { - // any tests for the clear() function should be written here -}) + +'use strict' + +const todo = require('../modules/todo.js') + +beforeAll( async() => { + // stuff to do before any of the tests run +}) + +afterAll( async() => { + // runs after all the tests have completed +}) + +describe('add()', () => { + // block of tests + beforeEach( async() => { + todo.clear() + }) + afterEach( async() => { + // runs after each test completes + }) + test('add a single item', async done => { + expect.assertions(1) + try { + todo.add('bread', 3) + expect(todo.countItems()).toBe(1) + } catch(err) { + done.fail(err) + } finally { + done() + } + }) + test('qty must be a number', async done => { + expect.assertions(1) + try { + todo.add('bread', 'three') + done.fail('test failed') + } catch(err) { + expect(err.message).toBe('qty must be a number') + } finally { + done() + } + }) +}) + +describe('delete()', () => { + // any tests for the delete() function should be written here +}) + +describe('getAll()', () => { + // any tests for the getAll() function should be written here +}) + +describe('clear()', () => { + // any tests for the clear() function should be written here +}) From 3bf1be1af95ea431e9f9a19d2bd4390fcf0ecf76 Mon Sep 17 00:00:00 2001 From: Balazs Laszlo Bordas Date: Sat, 25 Jan 2020 19:46:47 +0000 Subject: [PATCH 59/70] added missing line --- exercises/07_unit_testing/todo/unit tests/todo.spec.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/exercises/07_unit_testing/todo/unit tests/todo.spec.js b/exercises/07_unit_testing/todo/unit tests/todo.spec.js index bd5fd3fe..22f13dce 100644 --- a/exercises/07_unit_testing/todo/unit tests/todo.spec.js +++ b/exercises/07_unit_testing/todo/unit tests/todo.spec.js @@ -41,6 +41,9 @@ describe('add()', () => { done() } }) + + // New test goes HERE! + }) describe('delete()', () => { From 46cab3cd9f558d320b0de05ded83f4420fcf4d68 Mon Sep 17 00:00:00 2001 From: "Mark Tyers (aa7401)" Date: Thu, 30 Jan 2020 15:45:34 +0000 Subject: [PATCH 60/70] corrected lab code --- exercises/02_http/01_url/index.js | 33 +++---------------------------- 1 file changed, 3 insertions(+), 30 deletions(-) diff --git a/exercises/02_http/01_url/index.js b/exercises/02_http/01_url/index.js index 912dc44a..b161dff2 100644 --- a/exercises/02_http/01_url/index.js +++ b/exercises/02_http/01_url/index.js @@ -37,26 +37,11 @@ router.get('/anon', ctx => { // anon case }) -router.get('/books/:index/:index2', ctx => { +router.get('/books/:index', ctx => { const books = ['The Hobbit', 'Alice in Wonderland', 'The Secret Garden','Animal Farm'] const parameters = ctx.params console.log(parameters) - - - if (parameters.index > 3 || parameters.index2 > 3) { - ctx.body = "Number cannot be greater than 3" - } - else if (isNaN(parameters.index) || isNaN(parameters.index2)){ - ctx.body = "A number must be entered" - } - else if (Number.isInteger(parameters.index)){ - ctx.body = "A whole number must be entered" - } - else{ - const title = books[parameters.index] - const title2 = books[parameters.index2] - ctx.body = title + title2 - } + ctx.body = title }) router.get('/name', ctx => ctx.body = JSON.stringify(ctx.query)) @@ -64,19 +49,7 @@ router.get('/name', ctx => ctx.body = JSON.stringify(ctx.query)) router.get('/hello/:name', ctx => { let myname = ctx.params.name if(ctx.query.format === 'upper') myname = myname.toUpperCase() - else if (ctx.query.format === 'lower') myname = myname.toLowerCase() - else if (ctx.query.format === 'reverse'){ - var array1 = myname.split("") - console.log(array1) - var array2 = array1.reverse() - console.log(array2) - var array3 = array1.join("") - console.log(array3) - ctx.body = `hello ${array3}` - //myname = join(Array.reverse(myname.split())) - } - // only applies uppercase if formatting query exists - //ctx.body = `hello ${myname}` + ctx.body = `hello ${myname}` }) router.post('/form', ctx => { From be072e11e706a74b9b04a4827790045f097af2c9 Mon Sep 17 00:00:00 2001 From: Balazs Laszlo Bordas Date: Sun, 2 Feb 2020 02:03:27 +0000 Subject: [PATCH 61/70] solutions added for 02/01/index 1.3.2 TYU --- solutions/02_http/01_url/index.js | 153 ++++++++++++++++++++++++++++++ 1 file changed, 153 insertions(+) create mode 100644 solutions/02_http/01_url/index.js diff --git a/solutions/02_http/01_url/index.js b/solutions/02_http/01_url/index.js new file mode 100644 index 00000000..01a585c0 --- /dev/null +++ b/solutions/02_http/01_url/index.js @@ -0,0 +1,153 @@ +#!/usr/bin/env node + +/* eslint max-lines-per-function: 0 */ +/* eslint complexity: 0 */ +/* eslint max-len: 0 */ +/* eslint max-lines: 0 */ + +'use strict' + +/* IMPORTING MODULES */ +const Koa = require('koa') +const Router = require('koa-router') +const bodyParser = require('koa-bodyparser') +const staticFiles = require('koa-static') +const js2xmlparser = require('js2xmlparser') + +/* CONFIGURING THE MIDDLEWARE */ +const app = new Koa() +app.use(bodyParser()) +const router = new Router() +app.use(router.routes()) +app.use(staticFiles('./public')) + +/* GLOBAL VARIABLES */ +const port = 8080 +let names = [] + +function hello(ctx) { + ctx.body = 'Hello World' +} + +router.get('/', hello) +// base case + +router.get('/anon', ctx => { + ctx.body = 'Hello World' + // anon case +}) + +router.get('/books/:index/:index2', ctx => { + const books = ['The Hobbit', 'Alice in Wonderland', 'The Secret Garden', '1984'] + const maxIndex = books.length - 1 + const parameters = ctx.params + console.log(parameters) + + if (isNaN(parameters.index) || isNaN(parameters.index2)) { + ctx.status = 400 + ctx.body = 'Two numbers must be entered' + } else if (!Number.isInteger(parseFloat(parameters.index)) + || !Number.isInteger(parseFloat(parameters.index2))) { + ctx.status = 400 + ctx.body = 'Indexes must be integers' + } else if (parameters.index1 > maxIndex || parameters.index2 > maxIndex) { + ctx.status = 400 + ctx.body = `Neither index cannot be greater than ${maxIndex}` + } else { + const title = books[parseInt(parameters.index)] + const title2 = books[parseInt(parameters.index2)] + ctx.body = `${title}\n${title2}` + } +}) + +router.get('/name', ctx => ctx.body = JSON.stringify(ctx.query)) + +router.get('/hello/:name', ctx => { + let myname = ctx.params.name + + // only applies uppercase if formatting query exists + if(ctx.query.format === 'upper') myname = myname.toUpperCase() + + ctx.body = `hello ${myname}` +}) + +router.post('/form', ctx => { + const minLength = 3 + console.log(ctx.request.body) + const body = ctx.request.body + if(body.lastname.length >= minLength) { + names.push( { firstname: body.firstname, lastname: body.lastname } ) + ctx.status = 201 + ctx.body = `your name is ${body.firstname} ${body.lastname}` + } else { + ctx.status = 422 + ctx.body = 'invalid lastname' + } + //ctx.body = 'form processed' +}) + +router.get('/names', ctx => { + let list = names + let search = 'x' + const minLength = 3 + + if(ctx.query.search && ctx.query.search.length >= minLength) { + search = ctx.query.search.toLowerCase() + } else if(ctx.headers.search && ctx.headers.search.length >= minLength) { + search = ctx.headers.search.toLowerCase() + } + + console.log(`Accept: ${ctx.get('Accept')}`) + + if(search.length >= minLength) list = names.filter( val => `${val.firstname} ${val.lastname}`.toLowerCase().includes(search)) + if(list.length === 0) { + ctx.status = 404 + ctx.body = 'No Names found' + return + } + switch (ctx.accepts('application/json', 'application/xml', 'text/html', 'text/html', 'text/csv')) { + case 'text/csv': + ctx.set('content-type', 'text/csv') + ctx.body = formatCSV(list) + break + case 'text/html': + ctx.set('content-type', 'text/html') + ctx.body = formatHTML(list) + break + case 'application/json': + ctx.set('content-type', 'application/json') + ctx.body = {names: list} + break + case 'application/xml': + ctx.set('content-type', 'application/xml') + ctx.body = js2xmlparser.parse('people', list) + break + default: + ctx.status = 406 + ctx.body = 'unsupported MIME type' + break + } +}) + +router.del('/names', ctx => { + names = [] + ctx.status = 204 + ctx.body = 'all names deleted' +}) + +function formatCSV(list) { + let data = '' + for(const name of list) data += `${name.firstname}, ${name.lastname}\n` + return data +} + +function formatHTML(list) { + let data = '' + for(const name of list) { + data += `\n` + } + data += '
${name.firstname}${name.lastname}
' + return data +} + +module.exports = app.listen(port, () => console.log(`listening on port ${port}`)) From 034f60475950b3d312ecbfe5ee586b1823247663 Mon Sep 17 00:00:00 2001 From: Balazs Bordas Date: Sat, 27 Jun 2020 01:24:37 +0200 Subject: [PATCH 62/70] fine tuned 02_HTTP.md, added solutions for 02_HTTP --- 02 HTTP.md | 27 +++++++++++++-------------- solutions/02_http/01_url/index.js | 15 ++++++++++----- 2 files changed, 23 insertions(+), 19 deletions(-) diff --git a/02 HTTP.md b/02 HTTP.md index b74829d0..4c8e91e1 100644 --- a/02 HTTP.md +++ b/02 HTTP.md @@ -115,7 +115,7 @@ Start the server and access the `/books/1` route. What is displayed in the web b 4. This index value is used to look up the title of the book in the array, the book title is stored in a constant. 5. Finally the book title is sent to the web browser. -#### 1.3.1 Core Knowledge +#### 1.2.1 Core Knowledge JavaScript objects comprise one or more **property-value pairs**. There is an example below to illustrate this. @@ -153,7 +153,7 @@ delete name.first delete name['last name'] ``` -#### 1.3.2 Test Your Understanding +#### 1.2.2 Test Your Understanding In this section you will learn about a number of JavaScript functions. In each case you will be provided with a link to the documentation. @@ -163,13 +163,13 @@ In this section you will learn about a number of JavaScript functions. In each c 2. Make sure this is triggered by restarting the server and accessing this by passing a second parameter. 3. Modify the script to print out both book titles. 3. Next you need to add some validation to make sure the script does not crash (note that if you are using GoormIDE you will not be able to test it): - 1. If the index in the URL exceeds to number of books in the array you get an error. Insert an [`if...else` statement](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/if...else) that sends a suitable message to the browser if the index number in the URL is too high. - 2. The index must be a number. Use the [`isNaN()` function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isNaN) to check and send a suitable message to the browser if it is not. if it is, use the [`parseInt()` function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt) to convert it to a number. - 3. The number needs to be a whole number (integer). All JavaScript numbers are objects and have a number of useful functions. Use the [`Number.isInteger()` function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isInteger) to check it is indeed an integer. Send a suitable message to the browser if it is not. + 1. If the index in the URL exceeds the number of books in the array, you get an error. Insert an [`if...else` statement](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/if...else) that sends a suitable message to the browser if the index number in the URL is too high. + 2. The index must be a number. Use the [`isNaN()` function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isNaN) to check and send a suitable message to the browser if it is not. if it is, use the [`parseFloat()` function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseFloat) to convert it to a number. + 3. The number needs to be a whole number (integer). All JavaScript numbers are objects and have a number of useful functions. Use the [`Number.isInteger()` function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isInteger) to check it is indeed an integer. Send a suitable message to the browser if it is not. You can convert it to an integer using the [`parseInt()` function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt). ### 1.3 URL Query Strings -Whilst URL parameters are used to define unique URLS to identify online resources, sometimes we want to be able to pass additional information and this is done through the use of **query strings**. +Whilst URL parameters are used to define unique URLs to identify online resources, sometimes we want to be able to pass additional information and this is done through the use of **query strings**. 1. Restart the server and access the `/hello/John%20Doe` route. 1. Since spaces are not permitted in a URL we have to replace spaces with special codes. This is known as **URL Encoding** and there are specific [codes](https://www.degraeve.com/reference/urlencoding.php) to use. @@ -177,7 +177,7 @@ Whilst URL parameters are used to define unique URLS to identify online resource 2. Now change the URL to `/hello/John%20Doe?format=upper`. 1. Notice that the same data has been displayed just the format has changed. -Open the `index.js` file. The route is between lines 48-52. +Open the `index.js` file. The route is between lines 50-57. 1. Notice that the query string(s) are not part of the route. 2. The query string comprises name-value pairs. @@ -203,12 +203,11 @@ Headers allow for additional information to be passed: Make sure the server is still running and use the [Chrome web browser](https://www.google.com/chrome/) to access the root URL `/`. -1. Open the [Chrome Developer Tools](https://developers.google.com/web/tools/chrome-devtools/) by clicking on the _customise and control Google Chrome tools_ button (the three dots to the extreme right of the address bar). -2. Choose **More tools** from the menu and then **Developer tools** from the submenu. -3. Locate the **Network** tab in the Chrome developer tools. -4. Reload the web page. (Press F5) -5. You should now see the resource sent in the HTTP response together with some data dealing with response times. -6. Click on the file name (as shown) to display the HTTP headers. +1. Open the [Chrome Developer Tools](https://developers.google.com/web/tools/chrome-devtools/) by clicking on the _Customise and control Chrome_ button (the three dots to the extreme right of the address bar), choosing **More tools** from the menu and then **Developer tools** from the submenu. +2. Locate the **Network** tab in the Chrome developer tools. +3. Reload the web page. (Press F5) +4. You should now see the resource sent in the HTTP response together with some data dealing with response times. +5. Click on the file name (as shown) to display the HTTP headers. ![how to show the headers in Chrome](exercises/.images/chrome_02.png) @@ -234,7 +233,7 @@ In addition to the **Response Body** (the information in the web browser window) 2. The `Date` header is a string representing the date and time the response was sent. 3. The `ETag` header contains a hash of the contents and is used to see if the content has changed since the last request. -### 1.1 Test Your Knowledge +#### 1.4.1 Test Your Knowledge As part of the worksheets you will be given some exercises to carry out to make sure you fully understand the content covered. diff --git a/solutions/02_http/01_url/index.js b/solutions/02_http/01_url/index.js index 01a585c0..e26c5ff1 100644 --- a/solutions/02_http/01_url/index.js +++ b/solutions/02_http/01_url/index.js @@ -45,14 +45,14 @@ router.get('/books/:index/:index2', ctx => { if (isNaN(parameters.index) || isNaN(parameters.index2)) { ctx.status = 400 - ctx.body = 'Two numbers must be entered' + ctx.body = `Indexes must be numbers` } else if (!Number.isInteger(parseFloat(parameters.index)) || !Number.isInteger(parseFloat(parameters.index2))) { ctx.status = 400 - ctx.body = 'Indexes must be integers' - } else if (parameters.index1 > maxIndex || parameters.index2 > maxIndex) { + ctx.body = `Indexes must be integers` + } else if (parameters.index > maxIndex || parameters.index2 > maxIndex){ ctx.status = 400 - ctx.body = `Neither index cannot be greater than ${maxIndex}` + ctx.body = `Neither index can be greater than ${maxIndex}` } else { const title = books[parseInt(parameters.index)] const title2 = books[parseInt(parameters.index2)] @@ -66,7 +66,12 @@ router.get('/hello/:name', ctx => { let myname = ctx.params.name // only applies uppercase if formatting query exists - if(ctx.query.format === 'upper') myname = myname.toUpperCase() + if (ctx.query.format === 'upper') myname = myname.toUpperCase() + if (ctx.query.format === 'upper') myname = myname.toLowerCase() + + if (ctx.query.reverse === 'true') { + myname = myname.split('').reverse().join('') + } ctx.body = `hello ${myname}` }) From 77a9bdf7b9f708d5be681acd24caab9fcc5a2af3 Mon Sep 17 00:00:00 2001 From: Balazs Bordas Date: Wed, 1 Jul 2020 15:23:04 +0200 Subject: [PATCH 63/70] moved npm chapter to 01_Setup.md --- 01 Setup.md | 40 +++++++++++++++++++++++++++++---- 02 HTTP.md | 28 ++--------------------- exercises/01_setup/package.json | 18 +++++++++++++++ 3 files changed, 56 insertions(+), 30 deletions(-) create mode 100644 exercises/01_setup/package.json diff --git a/01 Setup.md b/01 Setup.md index 7f94b616..065039bd 100644 --- a/01 Setup.md +++ b/01 Setup.md @@ -141,14 +141,46 @@ $ node index.js Now we have the server up and running so the final task is to view the web page using the web browser. Simply open the Chrome browser and navigate to localhost:8080 where you should see a message. If this works you are ready to start the lab exercises. -## 5 Pushing the Changes to GitHub +## 5 Using npm and its package.json + +**Have a look at your `package.json` file and understand its contents** +- When you are starting a new _project_, **you have to create this yourself**: + 1. Use the `npm init` command to create the package.json file + - You can leave all the options default, just leave them empty and keep pressing enter + - Alternatively you can run `npm init --yes`, it will simply leave everything default + 2. Install the dependencies for the first time using the `-S` _switch_ with `npm install` + - e.g.: `npm install -S koa koa-bodyparser` + - This would add something like this to the `package.json` file: + ```json + "dependencies": { + "koa": "^2.11.0", + "koa-bodyparser": "^4.2.1" + } + ``` + - When you next run `npm install -S `, the given package's _newest version_ will be simply added to the list, or in case of a new version for a _previously listed_ dependency, the _version number_ will be updated + - This `-S` is just a short version of the `--save` _switch_ + - **You can use the alternative `--save-dev` switch to install and save them as _development dependencies_** + - Something that you wouldn't want to deploy, but is necessary for development + - E.g. we will use `jest` for testing, and `eslint` for linting during the development phase, but these shouldn't be required to be installed during deployment + - You are done with adding the dependencies, now simply use `npm install` to install all of them at once! + - If you don't want to install development dependencies, use `npm install --production` + 3. This `package.json` file is also useful to store _scripts_: + - Look at the following line: ` "start": "nodemon index.js"` + - This lets us simply type `npm start` in the terminal to start our application via _nodemon_ + - Nodemon is a great tool that restarts the application every time we save a file in the given folder, so we don't actually have to manually stop and restart it after every modification. + + + + + +## 6 Pushing the Changes to GitHub As you work through the lab activities two things are likely to happen: 1. You make changes to the code that you want to push to the forked copy of your repository. 2. You will need to pull any bug fixes from the original repository. -### 5.1 Configuring the Repository +### 6.1 Configuring the Repository Before you start interacting with the GitHub server you need to configure the local repository. Open the Bash Shell and run the following commands: @@ -159,7 +191,7 @@ git config user.email 'doej@coventry.ac.uk' remember to replace the values with you own name and your university email (but without the uni part). -### 5.2 Pushing Changes +### 6.2 Pushing Changes **NOTE: You only need to carry out this step when you have make changes to the code! This will normally need to take place each time you complete a "Test Your Understanding" section.** @@ -177,7 +209,7 @@ Now you should click on the **Sync** icon (shown below) to push the new commit u At this point you should be able to refresh your GitHub repository page to see the changes. -### 5.3 Pulling from Upstream +### 6.3 Pulling from Upstream As new materials and resources are added to the original repository (and bugs fixed) you will want to merge these into your forked repository. Before you can do this you will need to add a link to the upstream repository. Open a bash shell: diff --git a/02 HTTP.md b/02 HTTP.md index 4c8e91e1..39e3792d 100644 --- a/02 HTTP.md +++ b/02 HTTP.md @@ -55,32 +55,8 @@ Study the `index.js` script in the `exercises/02_http/01_url/` directory. 5. `js2xmlparser` - **You can install all these dependencies by simply running 'npm install' in the terminal.** - This command installs all the documented dependencies from the `package.json` file, which is already preconfigured in this case. - - **Have a look at your `package.json` file and understand its contents** - - When you are creating a new _project_, **you have to do this yourself**: - 1. Use the `npm init` command to create the package.json file - - You can leave all the options default, just leave them empty and keep pressing enter - - Alternatively you can run `npm init --yes`, it will simply leave everything default - 2. Install the dependencies for the first time using the `-S` _switch_ with `npm install` - - e.g.: `npm install -S koa koa-bodyparser` - - This would add something like this to the `package.json` file: - ```json - "dependencies": { - "koa": "^2.11.0", - "koa-bodyparser": "^4.2.1" - } - ``` - - When you next run `npm install -S `, the given package's _newest version_ will be simply added to the list, or in case of a new version for a _previously listed_ dependency, the _version number_ will be updated - - This `-S` is just a short version of the `--save` _switch_ - - **You can use the alternative `--save-dev` switch to install and save them as _development dependencies_** - - Something that you wouldn't want to deploy, but is necessary for development - - E.g. we will use `jest` for testing, and `eslint` for linting during the development phase, but these shouldn't be required to be installed during deployment - - You are done with adding the dependencies, now simply use `npm install` to install all of them at once! - - If you don't want to install development dependencies, use `npm install --production` - 3. This `package.json` file is also useful to store _scripts_: - - Look at the following line: ` "start": "nodemon index.js"` - - This lets us simply type `npm start` in the terminal to start our application via _nodemon_ - - Nodemon is a great tool that restarts the application every time we save a file in the given folder, so we don't actually have to manually stop and restart it after every modification. - + - Refer to the `01_Setup.md` document's `Using npm and its package.json` chapter for more information + 2. The first line is the _shebang_, it tells the script what application is needed to run it. 3. Lines 11-15 import the module packages we need for our script to work. Koa is a modular framework, on its own it does very little but depends on plugins (middleware) for its functionality. 4. Lines 18-22 are where we configure the koa _middleware_. diff --git a/exercises/01_setup/package.json b/exercises/01_setup/package.json new file mode 100644 index 00000000..1d289bea --- /dev/null +++ b/exercises/01_setup/package.json @@ -0,0 +1,18 @@ +{ + "name": "01_setup", + "version": "1.0.0", + "description": "", + "main": "index.js", + "scripts": { + "start": "nodemon index.js", + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "", + "license": "ISC", + "dependencies": { + "koa": "^2.13.0" + }, + "devDependencies": { + "nodemon": "^2.0.4" + } +} From f68c14cd6cfdd0520f2be68690a232e6a03d31d7 Mon Sep 17 00:00:00 2001 From: Balazs Bordas Date: Mon, 13 Jul 2020 18:58:55 +0200 Subject: [PATCH 64/70] updated and corrected the content in 03_HTML.md and exercises/03_HTML/ --- 03 HTML5.md | 34 ++++---- exercises/03_html/02_lists/commodore64.html | 10 --- exercises/03_html/02_lists/computers80.html | 11 +-- .../03_hypermedia/views/commodore64.html | 14 ++-- .../03_html/03_hypermedia/views/index.html | 23 +++--- exercises/03_html/04_tables/comparison.html | 6 +- .../03_html/05_semantic/public/java_cafe.png | Bin 0 -> 116805 bytes .../05_semantic/public/waiting_room.jpg | Bin 8561 -> 0 bytes exercises/03_html/05_semantic/views/cafe.html | 45 ++++++++--- .../03_html/05_semantic/views/review.html | 75 ++++++++++++------ exercises/03_html/template.html | 18 ++--- 11 files changed, 135 insertions(+), 101 deletions(-) delete mode 100644 exercises/03_html/02_lists/commodore64.html create mode 100644 exercises/03_html/05_semantic/public/java_cafe.png delete mode 100644 exercises/03_html/05_semantic/public/waiting_room.jpg diff --git a/03 HTML5.md b/03 HTML5.md index 32ba6bae..ce5419c8 100644 --- a/03 HTML5.md +++ b/03 HTML5.md @@ -58,7 +58,7 @@ See what happens, when you change the list type to ordered list (`ol`). Next, try a definition list. Add the following piece of code at the very end of the document, right before the `` end tag: ```html -

There are two types of memory:

+

There are two types of memory:

- -
+

Disclaimer: All opinions in this page reflect the views of their author(s), not the organization.

- - - + \ No newline at end of file diff --git a/exercises/04_css/01_formatting/views/hello-world.html b/exercises/04_css/01_formatting/views/hello-world.html deleted file mode 100644 index 32dc15b0..00000000 --- a/exercises/04_css/01_formatting/views/hello-world.html +++ /dev/null @@ -1,24 +0,0 @@ - - - - - Document - - - - - - - - - - -
- -
    -
  • -
  • -
  • -
  • -
  • -
\ No newline at end of file diff --git a/exercises/04_css/01_formatting/views/hello.html b/exercises/04_css/01_formatting/views/hello.html index de2ff46d..cce2dd6e 100644 --- a/exercises/04_css/01_formatting/views/hello.html +++ b/exercises/04_css/01_formatting/views/hello.html @@ -1,16 +1,15 @@ - - + - - - Let's see CSS at Work - - - - - -

Hello CSS!

-

Use this file to see how CSS can be used to change the appearance of a web page.

- + + Let's see CSS at Work + + + + + + +

Hello CSS!

+

Use this file to see how CSS can be used to change the appearance of a web page.

+ \ No newline at end of file diff --git a/exercises/04_css/01_formatting/views/selectors.html b/exercises/04_css/01_formatting/views/selectors.html index 771ea37f..c06c258b 100644 --- a/exercises/04_css/01_formatting/views/selectors.html +++ b/exercises/04_css/01_formatting/views/selectors.html @@ -1,9 +1,10 @@ - + + Selectors - - + +

Classes and identifiers.

@@ -17,6 +18,5 @@

Classes and identifiers.

This paragraph should be uniquely formatted. It is assigned an identifier.

This paragraph is in 'alert' class, too.

- \ No newline at end of file diff --git a/exercises/04_css/01_formatting/views/targets.html b/exercises/04_css/01_formatting/views/targets.html index 5738cf46..001e9655 100644 --- a/exercises/04_css/01_formatting/views/targets.html +++ b/exercises/04_css/01_formatting/views/targets.html @@ -1,40 +1,35 @@ - + + Selecting elements - - + + -

Element selection demo

-

The sources of energy are:

  1. protein
  2. carbohydrates
  3. fat
-

Sources of carbohydrates:

  • Fruits and berries
  • Wheat and pasta
  • Sweet products
      -
    • Candies
        -
      • Jelly beans
      • -
      • Irish toffee
      • -
      • Fruit drops
      • - -
    • - +
    • Candies +
        +
      • Jelly beans
      • +
      • Irish toffee
      • +
      • Fruit drops
      • +
      +
    • Pastries
  • -
- - \ No newline at end of file diff --git a/exercises/04_css/02_layout/public/css/floatstyles.css b/exercises/04_css/02_layout/public/css/floatstyles.css index 92edd7b0..12f64d84 100644 --- a/exercises/04_css/02_layout/public/css/floatstyles.css +++ b/exercises/04_css/02_layout/public/css/floatstyles.css @@ -1,10 +1,4 @@ - body { - font-family: Arial, Verdana, sans-serif; + font-family: Arial, Helvetica, sans-serif; margin-left: 200px; -} - - - - - +} \ No newline at end of file diff --git a/exercises/04_css/02_layout/public/css/menustyles.css b/exercises/04_css/02_layout/public/css/menustyles.css index 78aadc59..c90a2fcc 100644 --- a/exercises/04_css/02_layout/public/css/menustyles.css +++ b/exercises/04_css/02_layout/public/css/menustyles.css @@ -1,7 +1,5 @@ - - body { - font-family: Arial, Verdana, sans-serif; + font-family: Arial, Helvetica, sans-serif; } nav ul { diff --git a/exercises/04_css/02_layout/views/boxmodel.html b/exercises/04_css/02_layout/views/boxmodel.html index 5f488c4e..93224c08 100644 --- a/exercises/04_css/02_layout/views/boxmodel.html +++ b/exercises/04_css/02_layout/views/boxmodel.html @@ -1,27 +1,25 @@ - + + Illustration of CSS box model - + +

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce in malesuada libero. Etiam consectetur enim enim, id porta neque facilisis non. Proin consequat a sapien eu consectetur. Quisque bibendum lorem tortor, nec facilisis risus venenatis vel. Nullam et nunc varius, elementum mi vitae, mattis lacus. Mauris et lacinia magna. Nam faucibus purus ac felis vulputate suscipit. Sed vitae est egestas, euismod neque eu, molestie leo. +

+ +

+ Fusce viverra enim ante, vel dapibus metus maximus et. Proin ac metus justo. Donec nec scelerisque ante. Vestibulum a lectus nisl. Curabitur dictum a purus non sagittis. Cras semper ipsum ut eros lobortis vestibulum. Aenean eu urna nulla. Quisque mattis ex nec odio sollicitudin, a pulvinar nibh faucibus. Nullam quis rutrum purus, nec condimentum est. Aenean sagittis feugiat ante, sit amet dignissim elit vulputate ac. Aenean nec erat blandit, posuere orci malesuada, aliquam sem. Ut rutrum neque nec sapien consectetur dignissim. +

+ +

+ Nam odio lectus, accumsan vitae dignissim vitae, condimentum eu ipsum. Ut tristique vel leo at condimentum. Quisque tincidunt et tellus ut feugiat. Proin consectetur nulla eu fringilla cursus. Vivamus mi tellus, consectetur vitae commodo vitae, placerat sit amet nisl. Vestibulum et porttitor est. Cras varius quam a enim commodo consequat. Ut egestas dapibus est, a varius enim tincidunt ac. Quisque scelerisque ante quis porta mollis. Mauris nec maximus orci. Nunc ac justo ut nisl euismod vehicula in lacinia ante. Nulla sollicitudin nisi posuere, volutpat lorem nec, sagittis purus. Duis suscipit vulputate purus ac vulputate. Pellentesque suscipit ornare mi, et finibus tortor rutrum eget. +

- -

-Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce in malesuada libero. Etiam consectetur enim enim, id porta neque facilisis non. Proin consequat a sapien eu consectetur. Quisque bibendum lorem tortor, nec facilisis risus venenatis vel. Nullam et nunc varius, elementum mi vitae, mattis lacus. Mauris et lacinia magna. Nam faucibus purus ac felis vulputate suscipit. Sed vitae est egestas, euismod neque eu, molestie leo. -

- -

-Fusce viverra enim ante, vel dapibus metus maximus et. Proin ac metus justo. Donec nec scelerisque ante. Vestibulum a lectus nisl. Curabitur dictum a purus non sagittis. Cras semper ipsum ut eros lobortis vestibulum. Aenean eu urna nulla. Quisque mattis ex nec odio sollicitudin, a pulvinar nibh faucibus. Nullam quis rutrum purus, nec condimentum est. Aenean sagittis feugiat ante, sit amet dignissim elit vulputate ac. Aenean nec erat blandit, posuere orci malesuada, aliquam sem. Ut rutrum neque nec sapien consectetur dignissim. -

- -

-Nam odio lectus, accumsan vitae dignissim vitae, condimentum eu ipsum. Ut tristique vel leo at condimentum. Quisque tincidunt et tellus ut feugiat. Proin consectetur nulla eu fringilla cursus. Vivamus mi tellus, consectetur vitae commodo vitae, placerat sit amet nisl. Vestibulum et porttitor est. Cras varius quam a enim commodo consequat. Ut egestas dapibus est, a varius enim tincidunt ac. Quisque scelerisque ante quis porta mollis. Mauris nec maximus orci. Nunc ac justo ut nisl euismod vehicula in lacinia ante. Nulla sollicitudin nisi posuere, volutpat lorem nec, sagittis purus. Duis suscipit vulputate purus ac vulputate. Pellentesque suscipit ornare mi, et finibus tortor rutrum eget. -

- -

-In at ipsum id ligula vehicula porttitor. Suspendisse in risus vitae nunc lacinia lacinia. Cras finibus diam odio, vel posuere justo vestibulum tempor. Integer sed pharetra lacus. Integer elit mauris, vehicula ut tortor ut, vehicula iaculis odio. Integer tincidunt tincidunt quam, a laoreet sem mollis porta. Sed consequat sagittis urna quis aliquet. Proin vitae orci ultrices nisi rutrum blandit. -

- +

+ In at ipsum id ligula vehicula porttitor. Suspendisse in risus vitae nunc lacinia lacinia. Cras finibus diam odio, vel posuere justo vestibulum tempor. Integer sed pharetra lacus. Integer elit mauris, vehicula ut tortor ut, vehicula iaculis odio. Integer tincidunt tincidunt quam, a laoreet sem mollis porta. Sed consequat sagittis urna quis aliquet. Proin vitae orci ultrices nisi rutrum blandit. +

\ No newline at end of file diff --git a/exercises/04_css/02_layout/views/columns.html b/exercises/04_css/02_layout/views/columns.html index 7f84098d..012ff8cc 100644 --- a/exercises/04_css/02_layout/views/columns.html +++ b/exercises/04_css/02_layout/views/columns.html @@ -1,61 +1,59 @@ - + + Test file for CSS formatting - + + -

Text to be formatted in columns

- - -

-Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris efficitur nisi nulla, condimentum suscipit tellus ullamcorper in. In vulputate leo vitae orci lacinia, at feugiat leo ullamcorper. Morbi malesuada consectetur dolor, et luctus massa lacinia id. Ut interdum egestas luctus. Vivamus ac orci tristique, mattis dui ut, auctor leo. Nulla commodo, ante id blandit tempor, diam ante pellentesque lectus, ac iaculis enim tortor a mi. Morbi orci quam, dictum id nibh eget, mollis ultricies erat. Pellentesque porttitor leo ut laoreet convallis. Praesent porttitor sapien nec lacus ullamcorper, sed euismod risus sagittis. Curabitur non ultricies diam. Suspendisse ac eros in ante fringilla interdum et nec justo. Proin ac massa eleifend, tincidunt purus sit amet, hendrerit leo. Fusce ac nisl tempus, pellentesque lacus eu, mattis quam. Quisque et erat tortor. Sed at egestas erat. -

- -

-Cras pharetra feugiat orci, sed aliquam felis condimentum vel. Quisque id nunc nulla. Aliquam efficitur sagittis pulvinar. In aliquam ac lacus et consequat. In dapibus condimentum vulputate. Aliquam dictum ut sapien nec condimentum. Vestibulum non facilisis nisi. Donec dictum risus et est rutrum consectetur. Integer nec aliquet ex, egestas convallis velit. Sed egestas dolor id suscipit imperdiet. Vestibulum malesuada tincidunt urna, eu rutrum orci luctus ac. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Praesent iaculis aliquam elit eu porttitor. Phasellus tincidunt massa id sem placerat, nec cursus ipsum porta. Integer diam magna, consequat eget sodales id, placerat in ante. Nam et enim at ipsum sodales commodo. -

- -

-Curabitur faucibus elit in sapien dapibus, vel tristique ligula lacinia. Morbi non ex dapibus, viverra mi eget, efficitur dui. Fusce hendrerit turpis eget justo consequat, in tempus mauris vestibulum. Sed sed rutrum odio. Curabitur eget ipsum imperdiet, accumsan lectus vitae, fermentum justo. Integer quam ex, rhoncus sit amet sem ut, tincidunt fermentum eros. In hac habitasse platea dictumst. Duis posuere lectus nec ex suscipit accumsan. Vivamus lectus ante, porttitor a semper id, ullamcorper et erat. Phasellus sed velit ac risus ultrices porttitor non vel neque. Proin porttitor turpis vitae pretium vehicula. Proin pellentesque urna at iaculis tristique. -

- -

-Fusce suscipit, ex ac pretium pretium, magna mauris condimentum nisi, id porta sapien est ac turpis. Nulla sit amet blandit metus. Morbi a arcu facilisis, consequat dui vitae, dapibus lacus. Etiam vestibulum nisl consequat enim condimentum lobortis. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vestibulum elementum ac metus ac aliquam. Nulla quis massa venenatis diam convallis sodales. Duis quis lobortis nibh. Sed dolor justo, condimentum non orci sit amet, efficitur maximus est. Sed gravida vulputate condimentum. Maecenas libero ex, condimentum quis blandit quis, tincidunt vitae risus. Morbi ultricies eu arcu nec faucibus. -

- -

-Donec a vehicula neque, ac efficitur augue. In malesuada laoreet fringilla. Proin est massa, mattis at iaculis eu, auctor eu nibh. Sed tempus, felis eget dapibus commodo, enim neque ultricies ex, nec convallis dui nisl quis neque. Suspendisse potenti. Curabitur ac finibus ipsum, sit amet egestas felis. Sed cursus, est faucibus tempor lobortis, nisl ante blandit lectus, sit amet tincidunt justo tortor eget elit. Aliquam erat volutpat. Aenean enim nisl, tincidunt eleifend nisl ut, egestas laoreet massa. -

- -

-Sed vitae venenatis diam. Nulla consectetur nisl justo, vel rutrum diam volutpat eu. Proin dictum mi eu elementum gravida. Nunc tristique, lorem sit amet placerat ornare, libero tortor iaculis nibh, non accumsan turpis nulla nec elit. Nunc sed dui lorem. Quisque velit sem, sagittis eget mauris a, bibendum viverra ligula. Nam posuere tincidunt leo. Aenean a volutpat lacus. Maecenas condimentum, purus sit amet accumsan varius, arcu sem fringilla enim, nec sodales urna odio eu ante. Morbi ut suscipit mi. Ut rutrum urna purus, sit amet tristique diam mattis vel. Nunc pharetra, risus ac rutrum consequat, arcu quam dignissim nibh, eget pretium enim metus cursus felis. Pellentesque purus dui, imperdiet at nulla sed, accumsan posuere diam. Vestibulum varius condimentum ex, vulputate tempus mauris congue id. Sed ullamcorper mauris sed diam convallis dapibus. Vestibulum dictum sit amet mauris eu hendrerit. -

- -

-Vestibulum condimentum dui ac mi accumsan, eu interdum augue sollicitudin. Donec rutrum iaculis turpis et ultrices. Interdum et malesuada fames ac ante ipsum primis in faucibus. Vestibulum consequat feugiat elit, sed malesuada tortor tristique eget. Quisque et elementum lacus. Sed nec tincidunt nisl. Curabitur tincidunt lorem a dolor tincidunt mattis. Nullam vehicula vulputate enim, eu lacinia ex imperdiet semper. Cras sollicitudin magna quis orci lacinia facilisis. Vivamus mauris odio, pharetra a est et, tempus congue purus. Mauris urna felis, ornare quis sem blandit, scelerisque molestie nunc. Sed pulvinar sagittis nulla sit amet dapibus. Nunc hendrerit, metus vel rutrum pharetra, tellus magna accumsan felis, quis venenatis dolor dui vel leo. Aliquam erat volutpat. Sed egestas in lorem id malesuada. -

- -

-Cras risus sem, euismod nec porta sagittis, ornare vitae orci. Sed tristique, neque sit amet interdum eleifend, massa augue varius magna, sed tempor neque risus et lacus. Curabitur a ullamcorper lorem, vel gravida eros. Phasellus vitae convallis diam. Proin tempor, diam nec congue aliquet, libero dolor rhoncus magna, at dapibus quam purus nec orci. Proin sed vehicula tortor, id consequat ligula. Maecenas nunc magna, rutrum non malesuada id, facilisis eget tortor. Curabitur quis lacus non lectus interdum dapibus. Donec interdum varius tempus. Nunc convallis suscipit placerat. Integer facilisis sapien ut risus placerat, id vehicula neque pretium. Ut non bibendum risus. -

- -

-Vivamus sagittis augue turpis, quis convallis risus sagittis eu. Donec suscipit pharetra elit, non faucibus purus accumsan a. Suspendisse at tincidunt elit, vel aliquam felis. Curabitur pretium, quam nec volutpat bibendum, purus nisl rhoncus nibh, ut posuere ex odio non orci. Mauris eget lobortis nisl. Mauris sapien justo, tristique vulputate velit mollis, convallis mollis magna. In ante leo, pretium eget nibh at, malesuada scelerisque erat. Vestibulum finibus ultrices sollicitudin. Vivamus odio ex, vestibulum nec commodo sed, sagittis in orci. Donec aliquam arcu varius faucibus mattis. Mauris eleifend eros at volutpat auctor. Aenean vel ligula at velit sodales consectetur in a massa. In vitae rhoncus felis, non fringilla lorem. Maecenas vel pharetra dui, vel sodales est. In sodales nulla orci, id consectetur felis malesuada at. -

- -

-Donec elementum, arcu quis maximus congue, neque ante convallis leo, quis cursus enim augue vitae justo. Nam mattis sed arcu eget ornare. Integer dignissim dui nec egestas tristique. Aliquam erat volutpat. Cras eget tortor diam. In hac habitasse platea dictumst. Integer tempus egestas felis eget mollis. Nam a neque accumsan erat auctor condimentum. Etiam quis venenatis lectus. Praesent sed lacus in massa lacinia tempor. Pellentesque laoreet metus vel augue gravida, in iaculis velit ultricies. Donec porta faucibus volutpat. Vestibulum in risus velit. -

- -

-Aenean lacinia justo efficitur tellus mattis, ac pellentesque elit finibus. Curabitur et diam turpis. Curabitur lobortis nec ipsum nec eleifend. Proin pulvinar, neque eget consectetur ornare, sem eros posuere neque, vel mattis dui risus vitae nisl. Nulla non sollicitudin lacus, sed faucibus ligula. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. In fermentum eget elit sed fringilla. Curabitur viverra justo diam, quis vehicula turpis tristique quis. Proin ultrices elit risus. Praesent scelerisque metus ut augue suscipit, id pretium enim consectetur. Ut pulvinar malesuada rutrum. -

- -

-Nunc vel quam consequat, eleifend lectus porttitor, fringilla sapien. Integer id semper arcu, ut luctus nulla. Duis id risus ac erat mollis auctor sed in leo. Mauris dignissim ligula at nulla gravida tempor. Integer fringilla venenatis accumsan. In semper facilisis nisi sit amet commodo. Nulla dapibus nunc eu hendrerit suscipit. -

- +

Text to be formatted in columns

+

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris efficitur nisi nulla, condimentum suscipit tellus ullamcorper in. In vulputate leo vitae orci lacinia, at feugiat leo ullamcorper. Morbi malesuada consectetur dolor, et luctus massa lacinia id. Ut interdum egestas luctus. Vivamus ac orci tristique, mattis dui ut, auctor leo. Nulla commodo, ante id blandit tempor, diam ante pellentesque lectus, ac iaculis enim tortor a mi. Morbi orci quam, dictum id nibh eget, mollis ultricies erat. Pellentesque porttitor leo ut laoreet convallis. Praesent porttitor sapien nec lacus ullamcorper, sed euismod risus sagittis. Curabitur non ultricies diam. Suspendisse ac eros in ante fringilla interdum et nec justo. Proin ac massa eleifend, tincidunt purus sit amet, hendrerit leo. Fusce ac nisl tempus, pellentesque lacus eu, mattis quam. Quisque et erat tortor. Sed at egestas erat. +

+ +

+ Cras pharetra feugiat orci, sed aliquam felis condimentum vel. Quisque id nunc nulla. Aliquam efficitur sagittis pulvinar. In aliquam ac lacus et consequat. In dapibus condimentum vulputate. Aliquam dictum ut sapien nec condimentum. Vestibulum non facilisis nisi. Donec dictum risus et est rutrum consectetur. Integer nec aliquet ex, egestas convallis velit. Sed egestas dolor id suscipit imperdiet. Vestibulum malesuada tincidunt urna, eu rutrum orci luctus ac. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Praesent iaculis aliquam elit eu porttitor. Phasellus tincidunt massa id sem placerat, nec cursus ipsum porta. Integer diam magna, consequat eget sodales id, placerat in ante. Nam et enim at ipsum sodales commodo. +

+ +

+ Curabitur faucibus elit in sapien dapibus, vel tristique ligula lacinia. Morbi non ex dapibus, viverra mi eget, efficitur dui. Fusce hendrerit turpis eget justo consequat, in tempus mauris vestibulum. Sed sed rutrum odio. Curabitur eget ipsum imperdiet, accumsan lectus vitae, fermentum justo. Integer quam ex, rhoncus sit amet sem ut, tincidunt fermentum eros. In hac habitasse platea dictumst. Duis posuere lectus nec ex suscipit accumsan. Vivamus lectus ante, porttitor a semper id, ullamcorper et erat. Phasellus sed velit ac risus ultrices porttitor non vel neque. Proin porttitor turpis vitae pretium vehicula. Proin pellentesque urna at iaculis tristique. +

+ +

+ Fusce suscipit, ex ac pretium pretium, magna mauris condimentum nisi, id porta sapien est ac turpis. Nulla sit amet blandit metus. Morbi a arcu facilisis, consequat dui vitae, dapibus lacus. Etiam vestibulum nisl consequat enim condimentum lobortis. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Vestibulum elementum ac metus ac aliquam. Nulla quis massa venenatis diam convallis sodales. Duis quis lobortis nibh. Sed dolor justo, condimentum non orci sit amet, efficitur maximus est. Sed gravida vulputate condimentum. Maecenas libero ex, condimentum quis blandit quis, tincidunt vitae risus. Morbi ultricies eu arcu nec faucibus. +

+ +

+ Donec a vehicula neque, ac efficitur augue. In malesuada laoreet fringilla. Proin est massa, mattis at iaculis eu, auctor eu nibh. Sed tempus, felis eget dapibus commodo, enim neque ultricies ex, nec convallis dui nisl quis neque. Suspendisse potenti. Curabitur ac finibus ipsum, sit amet egestas felis. Sed cursus, est faucibus tempor lobortis, nisl ante blandit lectus, sit amet tincidunt justo tortor eget elit. Aliquam erat volutpat. Aenean enim nisl, tincidunt eleifend nisl ut, egestas laoreet massa. +

+ +

+ Sed vitae venenatis diam. Nulla consectetur nisl justo, vel rutrum diam volutpat eu. Proin dictum mi eu elementum gravida. Nunc tristique, lorem sit amet placerat ornare, libero tortor iaculis nibh, non accumsan turpis nulla nec elit. Nunc sed dui lorem. Quisque velit sem, sagittis eget mauris a, bibendum viverra ligula. Nam posuere tincidunt leo. Aenean a volutpat lacus. Maecenas condimentum, purus sit amet accumsan varius, arcu sem fringilla enim, nec sodales urna odio eu ante. Morbi ut suscipit mi. Ut rutrum urna purus, sit amet tristique diam mattis vel. Nunc pharetra, risus ac rutrum consequat, arcu quam dignissim nibh, eget pretium enim metus cursus felis. Pellentesque purus dui, imperdiet at nulla sed, accumsan posuere diam. Vestibulum varius condimentum ex, vulputate tempus mauris congue id. Sed ullamcorper mauris sed diam convallis dapibus. Vestibulum dictum sit amet mauris eu hendrerit. +

+ +

+ Vestibulum condimentum dui ac mi accumsan, eu interdum augue sollicitudin. Donec rutrum iaculis turpis et ultrices. Interdum et malesuada fames ac ante ipsum primis in faucibus. Vestibulum consequat feugiat elit, sed malesuada tortor tristique eget. Quisque et elementum lacus. Sed nec tincidunt nisl. Curabitur tincidunt lorem a dolor tincidunt mattis. Nullam vehicula vulputate enim, eu lacinia ex imperdiet semper. Cras sollicitudin magna quis orci lacinia facilisis. Vivamus mauris odio, pharetra a est et, tempus congue purus. Mauris urna felis, ornare quis sem blandit, scelerisque molestie nunc. Sed pulvinar sagittis nulla sit amet dapibus. Nunc hendrerit, metus vel rutrum pharetra, tellus magna accumsan felis, quis venenatis dolor dui vel leo. Aliquam erat volutpat. Sed egestas in lorem id malesuada. +

+ +

+ Cras risus sem, euismod nec porta sagittis, ornare vitae orci. Sed tristique, neque sit amet interdum eleifend, massa augue varius magna, sed tempor neque risus et lacus. Curabitur a ullamcorper lorem, vel gravida eros. Phasellus vitae convallis diam. Proin tempor, diam nec congue aliquet, libero dolor rhoncus magna, at dapibus quam purus nec orci. Proin sed vehicula tortor, id consequat ligula. Maecenas nunc magna, rutrum non malesuada id, facilisis eget tortor. Curabitur quis lacus non lectus interdum dapibus. Donec interdum varius tempus. Nunc convallis suscipit placerat. Integer facilisis sapien ut risus placerat, id vehicula neque pretium. Ut non bibendum risus. +

+ +

+ Vivamus sagittis augue turpis, quis convallis risus sagittis eu. Donec suscipit pharetra elit, non faucibus purus accumsan a. Suspendisse at tincidunt elit, vel aliquam felis. Curabitur pretium, quam nec volutpat bibendum, purus nisl rhoncus nibh, ut posuere ex odio non orci. Mauris eget lobortis nisl. Mauris sapien justo, tristique vulputate velit mollis, convallis mollis magna. In ante leo, pretium eget nibh at, malesuada scelerisque erat. Vestibulum finibus ultrices sollicitudin. Vivamus odio ex, vestibulum nec commodo sed, sagittis in orci. Donec aliquam arcu varius faucibus mattis. Mauris eleifend eros at volutpat auctor. Aenean vel ligula at velit sodales consectetur in a massa. In vitae rhoncus felis, non fringilla lorem. Maecenas vel pharetra dui, vel sodales est. In sodales nulla orci, id consectetur felis malesuada at. +

+ +

+ Donec elementum, arcu quis maximus congue, neque ante convallis leo, quis cursus enim augue vitae justo. Nam mattis sed arcu eget ornare. Integer dignissim dui nec egestas tristique. Aliquam erat volutpat. Cras eget tortor diam. In hac habitasse platea dictumst. Integer tempus egestas felis eget mollis. Nam a neque accumsan erat auctor condimentum. Etiam quis venenatis lectus. Praesent sed lacus in massa lacinia tempor. Pellentesque laoreet metus vel augue gravida, in iaculis velit ultricies. Donec porta faucibus volutpat. Vestibulum in risus velit. +

+ +

+ Aenean lacinia justo efficitur tellus mattis, ac pellentesque elit finibus. Curabitur et diam turpis. Curabitur lobortis nec ipsum nec eleifend. Proin pulvinar, neque eget consectetur ornare, sem eros posuere neque, vel mattis dui risus vitae nisl. Nulla non sollicitudin lacus, sed faucibus ligula. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. In fermentum eget elit sed fringilla. Curabitur viverra justo diam, quis vehicula turpis tristique quis. Proin ultrices elit risus. Praesent scelerisque metus ut augue suscipit, id pretium enim consectetur. Ut pulvinar malesuada rutrum. +

+

+ Nunc vel quam consequat, eleifend lectus porttitor, fringilla sapien. Integer id semper arcu, ut luctus nulla. Duis id risus ac erat mollis auctor sed in leo. Mauris dignissim ligula at nulla gravida tempor. Integer fringilla venenatis accumsan. In semper facilisis nisi sit amet commodo. Nulla dapibus nunc eu hendrerit suscipit. +

\ No newline at end of file diff --git a/exercises/04_css/02_layout/views/floating.html b/exercises/04_css/02_layout/views/floating.html index d45bda94..cfb936a6 100644 --- a/exercises/04_css/02_layout/views/floating.html +++ b/exercises/04_css/02_layout/views/floating.html @@ -1,53 +1,48 @@ - + + Illustration of a floating element - - + + +

Onions

+
+

Onions in cooking

+ +
+ Onions +
Image: Petr Kratochvil, public domain via www.publicdomainpictures.net.
+
+ +

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce in malesuada libero. Etiam consectetur enim enim, id porta neque facilisis non. Proin consequat a sapien eu consectetur. Quisque bibendum lorem tortor, nec facilisis risus venenatis vel. Nullam et nunc varius, elementum mi vitae, mattis lacus. Mauris et lacinia magna. Nam faucibus purus ac felis vulputate suscipit. Sed vitae est egestas, euismod neque eu, molestie leo. +

+ +

+ Fusce viverra enim ante, vel dapibus metus maximus et. Proin ac metus justo. Donec nec scelerisque ante. Vestibulum a lectus nisl. Curabitur dictum a purus non sagittis. Cras semper ipsum ut eros lobortis vestibulum. Aenean eu urna nulla. Quisque mattis ex nec odio sollicitudin, a pulvinar nibh faucibus. Nullam quis rutrum purus, nec condimentum est. Aenean sagittis feugiat ante, sit amet dignissim elit vulputate ac. Aenean nec erat blandit, posuere orci malesuada, aliquam sem. Ut rutrum neque nec sapien consectetur dignissim. +

+ +

+ Nam odio lectus, accumsan vitae dignissim vitae, condimentum eu ipsum. Ut tristique vel leo at condimentum. Quisque tincidunt et tellus ut feugiat. Proin consectetur nulla eu fringilla cursus. Vivamus mi tellus, consectetur vitae commodo vitae, placerat sit amet nisl. Vestibulum et porttitor est. Cras varius quam a enim commodo consequat. Ut egestas dapibus est, a varius enim tincidunt ac. Quisque scelerisque ante quis porta mollis. Mauris nec maximus orci. Nunc ac justo ut nisl euismod vehicula in lacinia ante. Nulla sollicitudin nisi posuere, volutpat lorem nec, sagittis purus. Duis suscipit vulputate purus ac vulputate. Pellentesque suscipit ornare mi, et finibus tortor rutrum eget. +

+ +

+ In at ipsum id ligula vehicula porttitor. Suspendisse in risus vitae nunc lacinia lacinia. Cras finibus diam odio, vel posuere justo vestibulum tempor. Integer sed pharetra lacus. Integer elit mauris, vehicula ut tortor ut, vehicula iaculis odio. Integer tincidunt tincidunt quam, a laoreet sem mollis porta. Sed consequat sagittis urna quis aliquet. Proin vitae orci ultrices nisi rutrum blandit. +

+ +

+ Mauris dapibus auctor diam sit amet euismod. Sed in nibh augue. Mauris porttitor consequat egestas. Mauris consectetur commodo blandit. Suspendisse faucibus tristique nulla, in maximus elit feugiat nec. Mauris sagittis orci eu elit mattis lacinia. Donec molestie risus sed urna maximus eleifend. Nunc accumsan facilisis eros et vestibulum. +

+ +

+ Sed dui turpis, pellentesque egestas eleifend eget, accumsan id dolor. Vestibulum suscipit in urna at semper. Curabitur luctus eros et luctus rhoncus. Sed ac ipsum dolor. Integer ex sapien, egestas quis sapien vel, fringilla aliquam libero. In sapien eros, feugiat quis auctor at, facilisis sit amet magna. Fusce leo ex, viverra quis gravida sit amet, faucibus a quam. Cras tempus lorem vitae metus cursus malesuada. +

-

Onions

- -
- -

Onions in cooking

- -
-Onions -
Image: Petr Kratochvil, public domain via www.publicdomainpictures.net.
-
- -

-Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce in malesuada libero. Etiam consectetur enim enim, id porta neque facilisis non. Proin consequat a sapien eu consectetur. Quisque bibendum lorem tortor, nec facilisis risus venenatis vel. Nullam et nunc varius, elementum mi vitae, mattis lacus. Mauris et lacinia magna. Nam faucibus purus ac felis vulputate suscipit. Sed vitae est egestas, euismod neque eu, molestie leo. -

- -

-Fusce viverra enim ante, vel dapibus metus maximus et. Proin ac metus justo. Donec nec scelerisque ante. Vestibulum a lectus nisl. Curabitur dictum a purus non sagittis. Cras semper ipsum ut eros lobortis vestibulum. Aenean eu urna nulla. Quisque mattis ex nec odio sollicitudin, a pulvinar nibh faucibus. Nullam quis rutrum purus, nec condimentum est. Aenean sagittis feugiat ante, sit amet dignissim elit vulputate ac. Aenean nec erat blandit, posuere orci malesuada, aliquam sem. Ut rutrum neque nec sapien consectetur dignissim. -

- -

-Nam odio lectus, accumsan vitae dignissim vitae, condimentum eu ipsum. Ut tristique vel leo at condimentum. Quisque tincidunt et tellus ut feugiat. Proin consectetur nulla eu fringilla cursus. Vivamus mi tellus, consectetur vitae commodo vitae, placerat sit amet nisl. Vestibulum et porttitor est. Cras varius quam a enim commodo consequat. Ut egestas dapibus est, a varius enim tincidunt ac. Quisque scelerisque ante quis porta mollis. Mauris nec maximus orci. Nunc ac justo ut nisl euismod vehicula in lacinia ante. Nulla sollicitudin nisi posuere, volutpat lorem nec, sagittis purus. Duis suscipit vulputate purus ac vulputate. Pellentesque suscipit ornare mi, et finibus tortor rutrum eget. -

- -

-In at ipsum id ligula vehicula porttitor. Suspendisse in risus vitae nunc lacinia lacinia. Cras finibus diam odio, vel posuere justo vestibulum tempor. Integer sed pharetra lacus. Integer elit mauris, vehicula ut tortor ut, vehicula iaculis odio. Integer tincidunt tincidunt quam, a laoreet sem mollis porta. Sed consequat sagittis urna quis aliquet. Proin vitae orci ultrices nisi rutrum blandit. -

- -

-Mauris dapibus auctor diam sit amet euismod. Sed in nibh augue. Mauris porttitor consequat egestas. Mauris consectetur commodo blandit. Suspendisse faucibus tristique nulla, in maximus elit feugiat nec. Mauris sagittis orci eu elit mattis lacinia. Donec molestie risus sed urna maximus eleifend. Nunc accumsan facilisis eros et vestibulum. -

- -

-Sed dui turpis, pellentesque egestas eleifend eget, accumsan id dolor. Vestibulum suscipit in urna at semper. Curabitur luctus eros et luctus rhoncus. Sed ac ipsum dolor. Integer ex sapien, egestas quis sapien vel, fringilla aliquam libero. In sapien eros, feugiat quis auctor at, facilisis sit amet magna. Fusce leo ex, viverra quis gravida sit amet, faucibus a quam. Cras tempus lorem vitae metus cursus malesuada. -

- -

-Nullam egestas id augue nec eleifend. Curabitur facilisis malesuada orci at venenatis. Duis at porttitor felis, ac varius elit. Sed pellentesque ligula eros, eu sollicitudin dolor placerat quis. Vestibulum suscipit, leo sit amet tristique hendrerit, ante velit congue lorem, sit amet volutpat ante ligula eget ex. Sed at ultrices turpis. Nulla sit amet egestas sapien. Donec sed lacinia mauris. Morbi suscipit erat nec orci vehicula iaculis. Fusce rhoncus at nunc vitae pretium. Nam consectetur luctus est, sit amet rhoncus ex consectetur ac. Nam in pretium nisl. Vivamus ultricies interdum elit a mattis. Phasellus lectus tellus, molestie in ultricies a, volutpat in ipsum. Aenean maximus viverra congue. -

- -
- - +

+ Nullam egestas id augue nec eleifend. Curabitur facilisis malesuada orci at venenatis. Duis at porttitor felis, ac varius elit. Sed pellentesque ligula eros, eu sollicitudin dolor placerat quis. Vestibulum suscipit, leo sit amet tristique hendrerit, ante velit congue lorem, sit amet volutpat ante ligula eget ex. Sed at ultrices turpis. Nulla sit amet egestas sapien. Donec sed lacinia mauris. Morbi suscipit erat nec orci vehicula iaculis. Fusce rhoncus at nunc vitae pretium. Nam consectetur luctus est, sit amet rhoncus ex consectetur ac. Nam in pretium nisl. Vivamus ultricies interdum elit a mattis. Phasellus lectus tellus, molestie in ultricies a, volutpat in ipsum. Aenean maximus viverra congue. +

+
\ No newline at end of file diff --git a/exercises/04_css/02_layout/views/menu.html b/exercises/04_css/02_layout/views/menu.html index 5e1cddd3..518127f9 100644 --- a/exercises/04_css/02_layout/views/menu.html +++ b/exercises/04_css/02_layout/views/menu.html @@ -1,32 +1,33 @@ + HTML Menus - - + + -

HTML/CSS Menu demonstration

- - - + \ No newline at end of file diff --git a/solutions/03_html/01_syntax/coventry.html b/solutions/03_html/01_syntax/coventry.html index 8f9ce227..7174d23c 100644 --- a/solutions/03_html/01_syntax/coventry.html +++ b/solutions/03_html/01_syntax/coventry.html @@ -3,9 +3,8 @@ History of a City: Coventry - + -

History of a City: Coventry

diff --git a/solutions/03_html/02_lists/computers80.html b/solutions/03_html/02_lists/computers80.html index 93706753..2767b833 100644 --- a/solutions/03_html/02_lists/computers80.html +++ b/solutions/03_html/02_lists/computers80.html @@ -1,11 +1,10 @@ - + 1980s' home computers - + -
A computer with a monitor @@ -91,5 +90,4 @@

There are two types of memory:

- \ No newline at end of file diff --git a/solutions/03_html/03_hypermedia/views/commodore64.html b/solutions/03_html/03_hypermedia/views/commodore64.html index 96ee476f..334fd38e 100644 --- a/solutions/03_html/03_hypermedia/views/commodore64.html +++ b/solutions/03_html/03_hypermedia/views/commodore64.html @@ -1,17 +1,15 @@ - + Commodore 64 -
- A commodore 64 computer + A commodore 64 computer
Photo: Bill Bertram, CC via https://commons.wikimedia.org/

Read the Wikipedia article for Retrocomputing.

Back

- \ No newline at end of file diff --git a/solutions/03_html/03_hypermedia/views/index.html b/solutions/03_html/03_hypermedia/views/index.html index 53141651..30a36d96 100644 --- a/solutions/03_html/03_hypermedia/views/index.html +++ b/solutions/03_html/03_hypermedia/views/index.html @@ -1,13 +1,13 @@ - + - - - Retro Computers - - - - + + + Retro Computers + + + +

Retro Computers

  1. Commodore 64
  2. @@ -15,19 +15,19 @@

    Retro Computers

3.4.1 Test Your Understanding

Embedded local video

Embedded youtube video via iframe

Embedded youtube video via object

- + \ No newline at end of file diff --git a/solutions/03_html/03_hypermedia/views/spectrum.html b/solutions/03_html/03_hypermedia/views/spectrum.html index 22b82ba0..332d19a8 100644 --- a/solutions/03_html/03_hypermedia/views/spectrum.html +++ b/solutions/03_html/03_hypermedia/views/spectrum.html @@ -1,10 +1,9 @@ - + Sinclair ZX Spectrum -

Sinclair ZX Spectrum

diff --git a/solutions/04_css/01_formatting/comparison.css b/solutions/04_css/01_formatting/comparison.css new file mode 100644 index 00000000..995aa2d0 --- /dev/null +++ b/solutions/04_css/01_formatting/comparison.css @@ -0,0 +1,47 @@ +body { + font-family: Arial, Helvetica, sans-serif; +} + +p { + text-align: center; +} + +table { + border: 1px solid black; + border-collapse: collapse; + margin-left: auto; + margin-right: auto; +} + +caption { + text-transform: uppercase; + border: 0.5px solid black; + font-weight: bold; + letter-spacing: 0.2em; +} + +thead { + background-color: red; + color: white; +} + +th { + text-transform: uppercase; + font-weight: bold; + padding-left: 0.5em; + padding-right: 0.5em; +} +th:first-child { + border-right: 1px solid black; + text-align: left; +} + +td { + padding-left: 0.5em; + padding-right: 0.5em; +} + +em { + font-weight: bold; + font-style: normal; +} \ No newline at end of file diff --git a/exercises/04_css/01_formatting/html/comparison.html b/solutions/04_css/01_formatting/comparison.html similarity index 76% rename from exercises/04_css/01_formatting/html/comparison.html rename to solutions/04_css/01_formatting/comparison.html index 42b0dda9..67f01085 100644 --- a/exercises/04_css/01_formatting/html/comparison.html +++ b/solutions/04_css/01_formatting/comparison.html @@ -1,13 +1,13 @@ - + Comparison of three computers - + + - -

A comparison of technical data of three popular 80's home computers:

+

A comparison of technical data of three popular 80's home computers:

@@ -21,28 +21,24 @@ - + - + - +
Technical comparison
CPUCPU MOS Technology 6510 Zilog Z80 MOS Technology 6502
RAMRAM 64 kilobytes 16 or 64 kilobytes 5 kilobytes
ROMROM 20 kilobytes 16 kilobytes 16 kilobytes
- -
- - \ No newline at end of file diff --git a/exercises/04_css/01_formatting/html/csstest.html b/solutions/04_css/01_formatting/csstest.html similarity index 74% rename from exercises/04_css/01_formatting/html/csstest.html rename to solutions/04_css/01_formatting/csstest.html index 0791d1a4..73a04ea9 100644 --- a/exercises/04_css/01_formatting/html/csstest.html +++ b/solutions/04_css/01_formatting/csstest.html @@ -1,18 +1,21 @@ - - + + Vintage Home Computers - + + + +

This is different from all the other paragraphs

1980's Home Computers

In early 1980's, home computers became mainstream. For the first time, computers could be purchased by an average family household.

- A computer with a monitor -
Photo: Piotr Siedlecki, public domain via http://www.publicdomainpictures.net.
+ A computer with a monitor +
Photo: Piotr Siedlecki, public domain via http://www.publicdomainpictures.net.

Novel uses

The main usage for a home computer was, of course, games. As cool games may not be a valid reason for purchasing an expensive gadget, @@ -46,11 +49,14 @@

Key concepts

Read-only memory. This was normally smaller in size than RAM and roughly corresponded to the hardware implementation of the operating system.
- - -
-

Disclaimer: All opinions in this page reflect the views of their author(s), not the organization.

- +

Basic programming

+

Basic was a common language for programming 80s' home computers +


+        10 PRINT "Hello, World"
+        20 INPUT "Continue (y/n)?", R$
+        30 IF R$="y" THEN GOTO 10
+        
+
+

Disclaimer: All opinions in this page reflect the views of their author(s), not the organization.

- - + \ No newline at end of file diff --git a/solutions/04_css/01_formatting/selectors.css b/solutions/04_css/01_formatting/selectors.css new file mode 100644 index 00000000..f34d61f7 --- /dev/null +++ b/solutions/04_css/01_formatting/selectors.css @@ -0,0 +1,23 @@ +body { + font-family: Arial, Helvetica, sans-serif; +} + +p { + color: blue; +} + +h1.alert { + font-size: 3em; +} + +.alert { + color: red; +} + +p#unique { + font-size: 0.8em; +} + +.underlined { + text-decoration: underline; +} \ No newline at end of file diff --git a/exercises/04_css/01_formatting/html/selectors.html b/solutions/04_css/01_formatting/selectors.html similarity index 53% rename from exercises/04_css/01_formatting/html/selectors.html rename to solutions/04_css/01_formatting/selectors.html index 771ea37f..a789d4bc 100644 --- a/exercises/04_css/01_formatting/html/selectors.html +++ b/solutions/04_css/01_formatting/selectors.html @@ -1,22 +1,22 @@ - + + Selectors - - + +

Classes and identifiers.

-

This is a regular paragraph.

+

This is a regular paragraph.

This is a regular paragraph, too.

-

This paragraph belongs to a special group of paragraphs. It is a member of 'alert' class.

+

This paragraph belongs to a special group of paragraphs. It is a member of 'alert' class.

This paragraph should be uniquely formatted. It is assigned an identifier.

-

This paragraph is in 'alert' class, too.

- +

This paragraph is in 'alert' class, too.

\ No newline at end of file diff --git a/solutions/04_css/01_formatting/test.css b/solutions/04_css/01_formatting/test.css new file mode 100644 index 00000000..f877a654 --- /dev/null +++ b/solutions/04_css/01_formatting/test.css @@ -0,0 +1,60 @@ +body { + background-color: lightcyan; + color: rgba(65, 105, 225, 0.7); +} + +h1 { + color: orange; +} + +p { + text-indent: 10pt; +} + +ol, ul { + border-style: solid; + border-width: 1pt; + text-indent: 10pt; +} + +li { + color: darkgray; +} + +figcaption { + font-size: smaller; + font-weight: bold; +} + +p.copyright-notice { + font-size: 0.8em; +} + +#special { + font-size: 0.8em; + color: yellowgreen; + font-style: italic; + border-left: 2px solid black; + margin-left: 40px; + padding-left: 10px; +} + +pre { + white-space: pre-wrap; +} + +p::first-letter { + font-size:8em; +} + +p::first-line { + font-weight: bold; +} + +p::before { + content: "Note! "; +} + +p::after { + content: url(/images/tickmark.png); +} \ No newline at end of file diff --git a/solutions/04_css/02_layout/berries.css b/solutions/04_css/02_layout/berries.css new file mode 100644 index 00000000..e8abcd43 --- /dev/null +++ b/solutions/04_css/02_layout/berries.css @@ -0,0 +1,56 @@ +body { + font-family: Arial, Helvetica, sans-serif; + text-align: center; +} + +img { + border: 2px solid lightblue; +} + +figcaption { + font-weight: bold; + margin-top: 1em; + margin-bottom: 3em; +} + +h1, h2, h3 { + padding-top: 0em; + padding-bottom: 0em; + margin: 0em; + font-weight: normal; +} + +h1 { + font-size: 6em; +} + +h2 { + padding-top: 8pt; + font-size: 2em; +} + +h3 { + padding-bottom: 8pt; + font-style: italic; + font-size: 1em; +} + +div { + width: 15em; + margin: auto; +} + +div div { + border-bottom: thin solid black; +} + +div div:first-child { + border-top: thin solid black; + background-color: lightblue; +} +div:last-child { + background-color: pink; +} +div:nth-child(2) { + background-color: beige; +} \ No newline at end of file diff --git a/solutions/04_css/02_layout/berries.html b/solutions/04_css/02_layout/berries.html new file mode 100644 index 00000000..b49c6289 --- /dev/null +++ b/solutions/04_css/02_layout/berries.html @@ -0,0 +1,30 @@ + + + + + Berries + + + + +

Berries

+
+ berries +
Image: Scott Bauer, USDA ARS, public domain
+
+
+
+

Blueberry

+

Vaccinium corymbosum

+
+
+

Cloudberry

+

Rubus chamaemorus

+
+
+

Lingonberry

+

Vaccinium vitis-idaea

+
+
+ + \ No newline at end of file diff --git a/solutions/04_css/02_layout/boxstyles.css b/solutions/04_css/02_layout/boxstyles.css new file mode 100644 index 00000000..92198cb0 --- /dev/null +++ b/solutions/04_css/02_layout/boxstyles.css @@ -0,0 +1,25 @@ +p.one { + border: 1px solid black; + padding: 3em; + margin: 1em; + margin-bottom: 0em; +} + +p.two { + border: 1px solid black; + margin: 5em; + margin-top: 0em; +} + +p.three { + border-left: 3px solid black; + padding: 1em; + padding-top: 0em; + margin-top: 2em; + margin-bottom: 8em; +} + +p.four { + border: 5px dashed red; + border-radius: 1em; +} \ No newline at end of file diff --git a/solutions/04_css/02_layout/columnstyles.css b/solutions/04_css/02_layout/columnstyles.css new file mode 100644 index 00000000..eb5b85d9 --- /dev/null +++ b/solutions/04_css/02_layout/columnstyles.css @@ -0,0 +1,13 @@ +body { + column-count: 3; + /*alternatively: column-width: 15em; */ + column-gap: 2em; + column-rule-style: solid; + column-rule-width: 1px; + column-rule-color: red; + /*alternatively: column-rule: 1px solid red; */ +} + +h1 { + column-span: all; +} \ No newline at end of file diff --git a/solutions/04_css/02_layout/floating.html b/solutions/04_css/02_layout/floating.html new file mode 100644 index 00000000..1f3d8aa8 --- /dev/null +++ b/solutions/04_css/02_layout/floating.html @@ -0,0 +1,64 @@ + + + + + Illustration of a floating element + + + + +

Onions

+ +
+

Did you know?

+
    +
  • The latin name for onion plant is Allium Cepa.
  • +
  • Onions have been used in cooking for thousands of years.
  • +
  • 89% of onions' content is water.
  • +
+
+ +
+

Onions in cooking

+ +
+ Onions +
Image: Petr Kratochvil, public domain via www.publicdomainpictures.net.
+
+ +

+ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Fusce in malesuada libero. Etiam consectetur enim enim, id porta neque facilisis non. Proin consequat a sapien eu consectetur. Quisque bibendum lorem tortor, nec facilisis risus venenatis vel. Nullam et nunc varius, elementum mi vitae, mattis lacus. Mauris et lacinia magna. Nam faucibus purus ac felis vulputate suscipit. Sed vitae est egestas, euismod neque eu, molestie leo. +

+ +

+ Fusce viverra enim ante, vel dapibus metus maximus et. Proin ac metus justo. Donec nec scelerisque ante. Vestibulum a lectus nisl. Curabitur dictum a purus non sagittis. Cras semper ipsum ut eros lobortis vestibulum. Aenean eu urna nulla. Quisque mattis ex nec odio sollicitudin, a pulvinar nibh faucibus. Nullam quis rutrum purus, nec condimentum est. Aenean sagittis feugiat ante, sit amet dignissim elit vulputate ac. Aenean nec erat blandit, posuere orci malesuada, aliquam sem. Ut rutrum neque nec sapien consectetur dignissim. +

+ +

+ Nam odio lectus, accumsan vitae dignissim vitae, condimentum eu ipsum. Ut tristique vel leo at condimentum. Quisque tincidunt et tellus ut feugiat. Proin consectetur nulla eu fringilla cursus. Vivamus mi tellus, consectetur vitae commodo vitae, placerat sit amet nisl. Vestibulum et porttitor est. Cras varius quam a enim commodo consequat. Ut egestas dapibus est, a varius enim tincidunt ac. Quisque scelerisque ante quis porta mollis. Mauris nec maximus orci. Nunc ac justo ut nisl euismod vehicula in lacinia ante. Nulla sollicitudin nisi posuere, volutpat lorem nec, sagittis purus. Duis suscipit vulputate purus ac vulputate. Pellentesque suscipit ornare mi, et finibus tortor rutrum eget. +

+ +

+ In at ipsum id ligula vehicula porttitor. Suspendisse in risus vitae nunc lacinia lacinia. Cras finibus diam odio, vel posuere justo vestibulum tempor. Integer sed pharetra lacus. Integer elit mauris, vehicula ut tortor ut, vehicula iaculis odio. Integer tincidunt tincidunt quam, a laoreet sem mollis porta. Sed consequat sagittis urna quis aliquet. Proin vitae orci ultrices nisi rutrum blandit. +

+ +

+ Mauris dapibus auctor diam sit amet euismod. Sed in nibh augue. Mauris porttitor consequat egestas. Mauris consectetur commodo blandit. Suspendisse faucibus tristique nulla, in maximus elit feugiat nec. Mauris sagittis orci eu elit mattis lacinia. Donec molestie risus sed urna maximus eleifend. Nunc accumsan facilisis eros et vestibulum. +

+ +

+ Sed dui turpis, pellentesque egestas eleifend eget, accumsan id dolor. Vestibulum suscipit in urna at semper. Curabitur luctus eros et luctus rhoncus. Sed ac ipsum dolor. Integer ex sapien, egestas quis sapien vel, fringilla aliquam libero. In sapien eros, feugiat quis auctor at, facilisis sit amet magna. Fusce leo ex, viverra quis gravida sit amet, faucibus a quam. Cras tempus lorem vitae metus cursus malesuada. +

+ +

+ Nullam egestas id augue nec eleifend. Curabitur facilisis malesuada orci at venenatis. Duis at porttitor felis, ac varius elit. Sed pellentesque ligula eros, eu sollicitudin dolor placerat quis. Vestibulum suscipit, leo sit amet tristique hendrerit, ante velit congue lorem, sit amet volutpat ante ligula eget ex. Sed at ultrices turpis. Nulla sit amet egestas sapien. Donec sed lacinia mauris. Morbi suscipit erat nec orci vehicula iaculis. Fusce rhoncus at nunc vitae pretium. Nam consectetur luctus est, sit amet rhoncus ex consectetur ac. Nam in pretium nisl. Vivamus ultricies interdum elit a mattis. Phasellus lectus tellus, molestie in ultricies a, volutpat in ipsum. Aenean maximus viverra congue. +

+
+ + + \ No newline at end of file diff --git a/solutions/04_css/02_layout/floatstyles.css b/solutions/04_css/02_layout/floatstyles.css new file mode 100644 index 00000000..26efd179 --- /dev/null +++ b/solutions/04_css/02_layout/floatstyles.css @@ -0,0 +1,22 @@ +body { + font-family: Arial, Helvetica, sans-serif; + margin-left: 200px; +} + +figure#floating { + float: right; +} + +section#factbox { + float: left; + border: 1px solid black; + margin: 2em; + padding: 1em; +} + +nav { + position: absolute; + top: 120px; + left: 40px; + width: 100px; +} \ No newline at end of file diff --git a/solutions/04_css/02_layout/menu.html b/solutions/04_css/02_layout/menu.html new file mode 100644 index 00000000..32cf35e2 --- /dev/null +++ b/solutions/04_css/02_layout/menu.html @@ -0,0 +1,54 @@ + + + + + HTML Menus + + + + +

HTML/CSS Menu demonstration

+ + + \ No newline at end of file diff --git a/solutions/04_css/02_layout/menustyles.css b/solutions/04_css/02_layout/menustyles.css new file mode 100644 index 00000000..e97b659f --- /dev/null +++ b/solutions/04_css/02_layout/menustyles.css @@ -0,0 +1,53 @@ +body { + font-family: Arial, Helvetica, sans-serif; +} + +nav ul { + list-style: none; + font-size: 16pt; + padding: 0px; +} + +nav > ul > li{ + background-color: green; + font-weight: bold; + padding: 3pt; + float: left; +} + +nav ul li { + width: 100pt; + color: white; +} + +nav ul li ul { + list-style-position: inside; + visibility: hidden; + position: absolute; + border: 2pt solid black; + background-color: white; + font-weight: normal; + color: black; + margin-left: -2pt; +} + +nav > ul > li > ul { + margin-top: 3pt; + border-top: none; +} + +nav ul li:hover > ul { + visibility:visible; +} + +ul li ul li ul { + margin-top: -20.5pt; + margin-left: 100.5pt; +} +nav a { + color: white; + text-decoration: none; +} +nav ul li ul a { + color: black; +} \ No newline at end of file From 078678a1661867cd06b615c901e53cc9d0d0d497 Mon Sep 17 00:00:00 2001 From: Balazs Bordas Date: Tue, 29 Sep 2020 19:31:51 +0200 Subject: [PATCH 68/70] fixed errors and added all solutions up to the end of 05_javascript --- 05 JavaScript.md | 363 +++++++++++++----------- exercises/05_javascript/currency.js | 21 +- exercises/05_javascript/employee.js | 8 +- exercises/05_javascript/weather.js | 7 +- solutions/05_javascript/contact.js | 81 ++++++ solutions/05_javascript/employee.js | 78 +++++ solutions/05_javascript/maths.js | 106 +++++++ solutions/05_javascript/quotes.js | 12 + solutions/05_javascript/quotes.json | 42 +++ solutions/05_javascript/university.json | 17 ++ solutions/05_javascript/vehicles.js | 49 ++++ solutions/05_javascript/weather.js | 22 ++ 12 files changed, 636 insertions(+), 170 deletions(-) create mode 100644 solutions/05_javascript/contact.js create mode 100644 solutions/05_javascript/employee.js create mode 100644 solutions/05_javascript/maths.js create mode 100644 solutions/05_javascript/quotes.js create mode 100644 solutions/05_javascript/quotes.json create mode 100644 solutions/05_javascript/university.json create mode 100644 solutions/05_javascript/vehicles.js create mode 100644 solutions/05_javascript/weather.js diff --git a/05 JavaScript.md b/05 JavaScript.md index 02081352..b6e863ad 100644 --- a/05 JavaScript.md +++ b/05 JavaScript.md @@ -17,9 +17,9 @@ Lets start with a simple example. ```javascript function largestNumber(a, b) { - if (a > b) return a - if (b > a) return b - return null + if (a > b) return a + if (b > a) return b + return null } const biggest = largestNumber(5, 8) @@ -31,45 +31,45 @@ const biggest = largestNumber(5, 8) - These are variables with local scope (they can't be accessed outside the function) - When the function is called, you need to pass two **values** which get assigned to the two parameters. - If you pass too many values the extra ones get _ignored_. - - If you don't pass enough values the remainder are assigned a value of `null`. `Null` is an assignment value (means a value of no value). + - If you don't pass enough values the remainder are assigned a value of [`undefined`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/undefined). + >`undefined` is a [`primitive`](https://developer.mozilla.org/en-US/docs/Glossary/Primitive), which is data that is not an object and has no methods. 3. The function returns a value. - If the numbers are not the same it returns the largest. - - If they are the same it returns `null`. + - If they are the same, it returns [`null`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/null). #### 1.1.1 Test Your Understanding Start by running the `maths.js` script and map the output it generates against the `console.log` statements in the script. 1. Create a new function called `multiply()` that takes two parameters, `a` and `b` and returns the _product_ of the two. - - what happens if you call it with only a single parameter? -2. Write an _arrow function expression_ stored in a constant called `squareRoot` which calculates and returns the square root of the supplied number. You will need to use the `sqrt()` method which is part of the `Math` object. - -Open the `contact.js` script, implement the `validateEmail()` function and thoroughly test it, you should avoid using regular expressions at this stage: - -1. Check that the string is at least 5 character long -2. Check that there is a `@` character and that it is not at the start of the string (HINT: use the [indexOf](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/String/indexOf) String prototype method. -3. Check that there is a period (.) character after the `@` character but before the end of the string. + - what happens if you call it with only a single parameter? +2. Open the `contact.js` script, implement the `validateEmail()` function and thoroughly test it, you should avoid using regular expressions at this stage: + 1. Check that the string is at least 5 character long + 2. Check that there is a `@` character and that it is not at the start of the string (HINT: use the [`lastIndexOf`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/String/lastIndexOf) String prototype method. + 3. Check that there are no spaces (`' '`) + 4. Check that there are no double dots (`'..'`) + 5. Check that there is a period (.) character after the `@` character but before the end of the string. #### 1.1.2 Function Parameters In the JavaScript language although we define a function with a set of specified _parameters_, when we call the function we don't need to pass these arguments: -We can choose to pass fewer arguments than are specified in the function parameters. Any parameters that don't have a matching argument are set to `undefined`. For example, the following code will print `undefined`. +We can choose to pass fewer arguments than are specified in the function parameters. Any parameters that don't have a matching argument are set to `undefined`. For example, in the following code num has a value of [`undefined`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/undefined), so it can't be squared. ```javascript function sqr(num) { - return num * num + return num * num } sql() // returns NaN (not a number) ``` -This can cause issues in your code so to prevent this we provide [Default Parameters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Default_parameters). If an arguement is missing when a function is called this specified a default value to use. For example consider this version of the function: +This can cause issues in your code so to prevent this we provide [Default Parameters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Default_parameters). If an arguement is missing when a function is called this specifies a default value to use. For example consider this version of the function: ```javascript function sqr(num = null) { - return num * num + return num * num } -sqr() // returns 0 +sqr() // returns 0 ``` In JavaScript: @@ -81,48 +81,47 @@ It is also possible to pass in more arguements than there are parameters in the ```javascript function add(num1, num2) { - return num1 + num2 + return num1 + num2 } -add(4, 2, 1) // returns 6 +console.log(add(4, 2, 1)) // returns 6 ``` -As you can see, if there are too many arguments, the extra ones are ignored however JavaScript provides a mechanism to access all the arguments passed to a function regardless of whether they match the parameter list by using the _array-like_ `arguments` object, for example: +As you can see, if there are too many arguments, the extra ones are ignored, however, JavaScript provides a mechanism to access all the arguments passed to a function regardless of whether they match the parameter list by using the _array-like_ `arguments` object, for example: ```javascript function add() { - let total = 0 - for(arg of arguments) total += arg - return total + let total = 0 + for(const arg of arguments) total += arg + return total } -add(4, 2, 1) // returns 7 +console.log(add(4, 2, 1)) // returns 7 ``` Using _hidden_ or _magic_ variables that magically come into existence can make your code hard to understand so ECMA6 introduced [Rest Parameters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters), parameters that can hold any arguments that don't match the parameters in the function declaration. Take the following code: ```javascript function add(num1, num2, ...others) { - let total = num1 + num2 - for(arg of others) total += arg - return total + let total = num1 + num2 + for(const arg of others) total += arg + return total } -add(4, 2,1) // returns 7 +console.log(add(4, 2, 1)) // returns 7 ``` This demonstrates how the rest parameter _mops up_ any surplus arguments and could be written as: ```javascript function add(...numbers) { - let total = 0 - for(arg of numbers) total += arg - return total + let total = 0 + for(const arg of numbers) total += arg + return total } - -console.log(add(4, 2, 1)) // returns 7 +console.log(add(4, 2, 1)) // returns 7 ``` #### 1.1.3 Test Your Understanding -1. create a function called `divideThis()` that takes two arguments, a number to be divided, `dividend` and the number to divide by, `divisor`. The function should return the _quotient_. +1. In the `maths.js` file, create a function called `divideThis()` that takes two arguments, a number to be divided, `dividend` and the number to divide by, `divisor`. The function should return the _quotient_. 2. What happens if you don't pass a parameter for the `divisor` parameter? Can you fix this by supplying a suitable _default parameter_? 3. Call the `multiply()` function from the previous task omitting the second parameter. Can you modify the function so it uses a default parameter to multiply by 1 if the second parameter is missing. - What happens if you don't supply _any_ parameters? @@ -137,8 +136,8 @@ Functions are a data type in JavaScript (they are objects but more on that later ```javascript const remainder = function(dividend, divisor) { - const quotient = Math.floor(dividend / divisor) - return dividend - quotient + const quotient = Math.floor(dividend / divisor) + return dividend - quotient } ``` @@ -150,12 +149,12 @@ To execute the function you simply reference the variable and append `()`. const rem = remainder(8, 5) ``` -ECMA6 introduced a better way to handle function expressions, called an **arrow function expression**. This has a much shorter (and cleaner) syntax. Here is the same function expression written using this new syntax, make a careful note of the differences. +ECMA6 introduced a better way to handle function expressions, called an [**`arrow function expression`**](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions). This has a much shorter (and cleaner) syntax. Here is the same function expression written using this new syntax, make a careful note of the differences. ```javascript const remainder2 = (dividend, divisor) => { - const quotient = Math.floor(dividend / divisor) - return dividend - quotient + const quotient = Math.floor(dividend / divisor) + return dividend - quotient } ``` @@ -174,25 +173,33 @@ const sqr = num => num * num ### 1.2.1 Test Your Understanding 1. Refactor the `remainder2` function expression to take advantage of the implicit return (you will need to reduce it to a single line of code). -2. Compare this to the original version: which is more _readable_? + - Compare this to the original version: which is more _readable_? +2. Write an _arrow function expression_ stored in a constant called `squareRoot` which calculates and returns the square root of the supplied number. You will need to use the `sqrt()` method which is part of the `Math` object. 3. Create a function expression that takes two string parameters and returns the longest string and assign this to a constant called `longest. check this works correctly. -4. Modify the function expression so that it can handle any number of string parameters (use a _rest parameter_). (hint: you will need to use a [`for...in`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in) statement to loop through the strings. How does this differ from a [`for...of`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of) statement?) -5. Use a [ternary operator](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator) instead of the `if` statement in the loop. -6. Finally use the [`reduce()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce) method to replace the `for...in` loop to reduce the function to a single line. + - Modify the function expression so that it can handle any number of string parameters (use a _rest parameter_). (hint: you will need to use a [`for...of`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of) statement to loop through the strings. How does this differ from a [`for...in`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in) statement?) + - Make sure there are no errors thrown and `null` is returned when the function is called without any arguments + - Use a [`ternary operator`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Conditional_Operator) instead of the `if` statement in the loop. + - Finally use the [`reduce()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce) method to replace the `for...of` loop to reduce the function to a single line. ## 2 Callbacks -Since JavaScript supports _first class functions_, we can use a function in any place where we could use a literal, object or variable. Open the `currency.js` script and look at line 17. As you can see the `request` object has a key called `get` that stores a function (we have already covered this). This takes two parameters: +Since JavaScript supports [_first class functions_](https://developer.mozilla.org/en-US/docs/Glossary/First-class_Function), we can use a function in any place where we could use a literal, object or variable. Open the `currency.js` script and look at line 22. As you can see the `fs` object has a key called `readFile` that stores a function (we have already covered this). This takes two parameters: -1. A string representing the url to be accessed. -2. A function that will be called once the data has been retrived from the url. This was defined earlier in the script and takes 3 parameters. +1. A string representing the path of the file to be read. +2. A function that will be called once the file has been read. This was defined earlier in the script and takes 2 parameters. ```javascript -const printRates = (err, res, body) => { - const data = JSON.parse(body) - console.log(`for each EUR you will get ${data.rates[symbol]} ${symbol} today`) +const printRates = (err, data) => { + if (err) throw err + const parsedData = JSON.parse(data) // this converts the formatted string into a javascript object + for (const country of parsedData) { + if (country.code === symbol) { + console.log(`For each GBP you will get ${country.rate} ${symbol} today.`) + return + } + } } -request.get(url, printRates) +fs.readFile(filePath, printRates) ``` This is a common construct used in JavaScript/NodeJS. The second function parameter is known as a **callback**. @@ -206,9 +213,15 @@ Because callbacks are such a fundamental part of NodeJS you need to spend time t Although this code works, you will rarely see callbacks written in this manner. Creating a function literal is a bit clunky and we can clean up the code by simply passing an anonymous function. ```javascript -request.get( url, (err, res, body) => { - const data = JSON.parse(body) - console.log(`for each EUR you will get ${data.rates[symbol]} ${symbol} today`) +fs.readFile(filePath, (err, data) => { + if (err) throw err + const parsedData = JSON.parse(data) // this converts the formatted string into a javascript object + for (const country of parsedData) { + if (country.code === symbol) { + console.log(`For each GBP you will get ${country.rate} ${symbol} today.`) + return + } + } }) ``` @@ -219,10 +232,13 @@ Take a few moments to make sure you fully understand the syntax, you will be see You are now going to apply you knowledge of JavaScript callbacks by connecting to the [Open Weather API](https://openweathermap.org/api). Start by opening the `weather.js` file: 1. Read through the code to make sure you understand how it works. -2. Register for an API key and add this to the script where indicated. -3. Run the script and check the output, can you explain the first two lines of output, why are the data types as shown? -4. Can you make sense of the other data? -5. Use the [Open Weather API](https://openweathermap.org/api) to retrieve and display the hourly forcast. + - An API key was already registered and is stored in the `apiKey` variable + - Run the script and check the output, can you explain the first two lines of output, why are the data types as shown? + - Can you make sense of the other data? +2. Use the `Open Weather API` to retrieve and display the [hourly forecast](https://openweathermap.org/api/one-call-api). + - Look at the format of the API calls, and substitute the `{lat}`, `{lon}` and `{API key}` placeholders + >`https://api.openweathermap.org/data/2.5/onecall?lat={lat}&lon={lon}&appid={API key}` + - What's the easiest place to put the new request? Why? Why is this problematic? ## 2.2 Defining Functions with Callbacks @@ -238,7 +254,7 @@ Start by opening the `files.js` script and study it carefully: ## 3 Objects -Lets start by creating an manipulating objects using **object literals**. Open the `employee.js` file, read through it and see if you can work out what it does. Now run it to see if you were correct. +Lets start by creating and manipulating objects using **object literals**. Open the `employee.js` file, read through it and see if you can work out what it does. Now run it to see if you were correct. ### 3.1 Creating Object Literals @@ -246,12 +262,13 @@ The simplest way to create new objects is by creating an _object literal_ which ```javascript const employee = { - firstName: 'Colin', - 'last name': 'Stephen' + firstName: 'Colin', + 'last name': 'Stephen', + startYear: 2010 } ``` -As you can see from the simple example above, the data is stored in name-value pairs, referred to as **Properties**. This example is defining an object with **2** properties. +As you can see from the simple example above, the data is stored in name-value pairs, referred to as **Properties**. This example is defining an object with **3** properties. The _name_ part of each property is a JavaScript string which may be enclosed in single quotes. These quotes are optional if the _property name_ is a valid _JavaScript variable_ but they are required if this is not the case. @@ -290,9 +307,9 @@ Whilst it is possible (and useful) to log an entire object to the console, norma ```javascript const employee = { - firstName: 'Colin', - 'last name': 'Stephen', - 'department': 'Computing' + firstName: 'Colin', + 'last name': 'Stephen', + 'department': 'Computing' } console.log(employee) @@ -301,9 +318,9 @@ const lastName = employee['last name'] const grade = employee.grade ``` -Passing the object name to `console.log()` will print out the string representation of the object. To retrieve a specific property value there are two options. If the name is a _legal JS variable name_ the dot `.` notation can be used. This is used to log the `firstName` property in the example above. +Passing the object name to `console.log()` will print out the string representation of the object. To retrieve a specific property value there are two options. If the name is a _legal JS variable name_ the dot `.` notation can be used. This is used to extract the `firstName` property in the example above. -If the name is not a valid JavaScript variable name we need to turn it into a string by using quotes `''` and enclose it in square braces `[]`. This is used to log the `last name` property. +If the name is not a valid JavaScript variable name, we need to turn it into a string by using quotes `''` and enclose it in square brackets `[]`. This is used for the `last name` property. The `grade` variable will be `undefined` because `employee.grade` does not exist. If you want to avoid this and assign a default value if the property is missing you can use the **OR** operator `||`. @@ -317,8 +334,7 @@ This will retrieve the value of the grade property if defined and store it in th 1. Create a new object called `university` which should contain three properties, `year1`, `year2` and `year3`. Each of these properties should store an object whos keys are the module codes and values the titles of the modules. 2. Create a variable called `study01` containing the `year1` object. -3. Use the `for...in` statement to iterate over this `study01` object printing out all of the _module codes_. -4. Use the `for...of` statement to print out all of the _module names_. +3. Use the `for...in` statement to iterate over this `study01` object printing out all of the _module codes_ and the _module names_. ### 3.3 Context @@ -335,7 +351,7 @@ You should start by opening the `counties.js` file and studying it carefully. Th If you look at the console output you will notice that, when we access `this` from _inside_ an object, it is bound to the object from where it was called. -Because we are operating in _strict mode_, when we try to access `this` in the global context it returns `undefined`. +Because we are operating in [_strict mode_](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Strict_mode), when we try to access `this` in the global context it returns `undefined`. ### 3.4 JSON Data @@ -358,9 +374,9 @@ In the same way that we can convert a JSON string into a JavaScript object we ca ```javascript const employee = { - firstName: 'Colin', - 'last name': 'Stephen', - 'department': 'Computing' + firstName: 'Colin', + 'last name': 'Stephen', + 'department': 'Computing' } const jsonstring = JSON.stringify(employee) console.log(jsonstring) @@ -373,9 +389,9 @@ In this example `jsonstring` is a **String**. If we print out this string we wil const jsonstring = JSON.stringify(employee, null, 2) /* { - "firstName": "Colin", - "last name": "Stephen", - "department": "Computing" + "firstName": "Colin", + "last name": "Stephen", + "department": "Computing" } *? ``` @@ -388,20 +404,20 @@ Lets apply our knowledge of callbacks to implement a simple quotes tool. 1. Create a json-formatted text file called `quotes.json` containing 10 quotes, you can find lots of these on websites such as [brainyquotes](https://www.brainyquote.com/topics/inspirational). Each quote should include the quote and the author. 2. Create a new script called `quotes.js` and use the [`fs.readfile()`](https://nodejs.org/api/fs.html#fs_fs_readfile_path_options_callback) function to read the contents of the file and display it in the terminal. -3. The contents of the file is a utf8 string, use `JSON.parse()` to convert this into a JavaScript object (array) and print this to the terminal instead. +3. The contents of the file is a `UTF-8` string, use `JSON.parse()` to convert this into a JavaScript object (array) and print this to the terminal instead. 4. Create a loop to iterate through the array, printing the contents of each index. -5. Modify the code so that it only prints the quotes string (not the entire object). +5. Modify the code so that it only prints the quote string (not the entire object). 6. Convert the `university` object from the previous exercise into a JSON string and save it to the filesystem as `university.json`. ### 3.5 ECMA6 Object Destructuring -There are situations where we want to retrieve multiple object properties and store then in different variables, for example: +There are situations where we want to retrieve multiple object properties and store them in different variables, for example: ```javascript const employee = { - firstName: 'Colin', - 'last name': 'Stephen', - 'department': 'Computing' + firstName: 'Colin', + 'last name': 'Stephen', + 'department': 'Computing' } const first = employee.firstName const last = employee['last name'] @@ -412,9 +428,9 @@ In ECMA6 it is possible to extract multiple pieces of data into separate variabl ```javascript const employee = { - firstName: 'Colin', - 'last name': 'Stephen', - 'department': 'Computing' + firstName: 'Colin', + 'last name': 'Stephen', + 'department': 'Computing' } const {firstName: first, 'last name': last, department: dept} = employee @@ -424,31 +440,33 @@ console.log(dept) // prints 'Computing' #### 3.5.1 Test Your Understanding -1. Take the `university` object you created in an earlier exercise and use a single line destructuring assignment to create three variables, `year1`, `year2` and `year3`. +1. Take the `university` object inside `employee.js` that you created in an earlier exercise and use a single line destructuring assignment to create three variables, `year1`, `year2` and `year3`. ### 3.6 Getters and Setters -Most object properties are simple values and you can simply assign a value. Sometimes however properties need to be calculated. One solution is to store a function as one of the properties however we would need to call a function to retrieve the value: +Most object properties are simple values and you can simply assign a value. Sometimes however properties need to be calculated. One solution is to store a function as one of the properties, however, we would need to call a function to retrieve the value: ```javascript const employee = { - firstName: 'Colin', - 'last name': 'Stephen', - getName: () => `${this.firstName} ${this['last name']}` + firstName: 'Colin', + 'last name': 'Stephen', + getName: function() { + return `${this.firstName} ${this["last name"]}` + } } const name = employee.getName() ``` -Whilst this works fine it looks a little clunky. Thankfully in the newer versions of JavaScript you can use a **getter** which makes the code far more intuitive. +Whilst this works fine, it looks a little clunky. Thankfully in the newer versions of JavaScript you can use a [**`getter`**](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/get) which makes the code far more intuitive. ```javascript const employee = { - firstName: 'Colin', - 'last name': 'Stephen', - get name() { - return `${this.firstName} ${this['last name']}` - } + firstName: 'Colin', + 'last name': 'Stephen', + get name() { + return `${this.firstName} ${this['last name']}` + } } const name = employee.name @@ -458,29 +476,29 @@ In the same manner, some properties when set may need to change other properties ```javascript const employee = { - firstName: 'Colin', - 'last name': 'Stephen', - setName: function(fullname) { - const words = fullname.toString().split(' ') - this.firstName = words[0] || '' - this['last name'] = words[1] || '' - } + firstName: 'Colin', + 'last name': 'Stephen', + setName: function(fullname) { + const words = fullname.toString().split(' ') + this.firstName = words[0] || '' + this['last name'] = words[1] || '' + } } employee.setName('Micky Mouse') ``` -By using a **setter**, it behaves just like any other property. +By using a [**`setter`**](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/set), it behaves just like any other property. ```javascript const employee = { - firstName: 'Colin', - 'last name': 'Stephen', - set name(fullname) { - const words = fullname.toString().split(' ') - this.firstName = words[0] || '' - this['last name'] = words[1] || '' - } + firstName: 'Colin', + 'last name': 'Stephen', + set name(fullname) { + const words = fullname.toString().split(' ') + this.firstName = words[0] || '' + this['last name'] = words[1] || '' + } } employee.name = 'Micky Mouse' @@ -488,8 +506,20 @@ employee.name = 'Micky Mouse' #### 3.6.1 Test Your Understanding -1. Print the person's details in an easy to understand sentence. -2. Add a getter to return the number of years the employee has been working for the company, you will need to round this down to a whole number. You should make use of one of the static methods of the built-in [Math](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math) object. +1. In `employee.js`, print the person's details in an easy to understand sentence. + - Notice how `JSON.stringify` also doesn't omit the getter from the string representation of the object, but displays its current output after the property name: + ```json + { + "firstName": "Micky", + "last name": "Mouse", + "startYear": 2010, + "gender": "male", + "date of birth": "1980-01-01", + "details": "firstName: Micky, lastName: Mouse, startYear: 2010, gender: male, DoB: 1980-01-01" + } + ``` +2. Add a getter to return the number of years the employee has been working for the company, you will need to create a [`Date`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) object containing the current time, and then its [`getFullYear()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/getFullYear) method to get the year value. +3. Create a proper setter that updates the employee's `firstName` and `last name` properties the same way as the one provided does ### 3.7 Modifying Objects @@ -503,9 +533,9 @@ Once an object has been created, additional properties cane be added by setting ```javascript const employee = { - firstName: 'Colin', - 'last name': 'Stephen', - 'department': 'Computing' + firstName: 'Colin', + 'last name': 'Stephen', + 'department': 'Computing' } employee.grade = 4 @@ -519,9 +549,9 @@ Properties can be removed from an object literal using the `delete` operator. Th ```javascript const employee = { - firstName: 'Colin', - 'last name': 'Stephen', - 'department': 'Computing' + firstName: 'Colin', + 'last name': 'Stephen', + 'department': 'Computing' } delete employee.department @@ -530,23 +560,40 @@ delete employee.department ### 3.8 Undefined Values Undefined Objects - -If you try to retrieve a value from an object that is undefined, JS throws a TypeError exception: +- If you try to retrieve a non-existent object, JS throws a `ReferenceError` + - Same thing happens when you try to access "one of its properties" (quotes because the object doesn't exist) +- If you try to retrieve one of `undefined`'s properties, JS throws a `TypeError` +- If you retrieve an existing object's non-existent property, it returns `undefined` + - If you try to retrieve the `undefined` property's property, JS throws a `TypeError` as with any other `undefined` ```javascript -const nonExistentObject.postCode // throws "TypeError" -const addressObject = employee.address // returns undefined -const postCode = employee.address.postCode // throws "TypeError" +nonExistingObject // throws ReferenceError +nonExistentObject.whatever // throws ReferenceError +undefined.whatever // throws TypeError +const existingObject = {} +existingObject.nonExistentProperty // returns undefined +existingObject.nonExistentProperty.whatever // throws TypeError ``` -To see what a `typeError` looks like, try uncommenting the three lines at the end of the `employee.js` file. So how can we avoid this? +To see what a `TypeError` looks like, try uncommenting lines marked with `"TypeError:"` in the `employee.js` file. So how can we avoid this? -The **AND** operator `&&` can be used to guard against this problem. +The [**`Logical AND`** `(&&)`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Logical_AND) operator can be used to guard against this problem. +- As this operator doesn't evaluate the second value if the first one is [`falsy`](https://developer.mozilla.org/en-US/docs/Glossary/falsy), we can be sure it won't try to retrieve a property of `undefined`. ```javascript const postCode = employee.address && employee.address.postCode console.log(postCode) // returns undefined ``` +- `postCode` gets the value of `employee.address` if it's [`falsy`](https://developer.mozilla.org/en-US/docs/Glossary/falsy) (e.g. `undefined` (as it's in this case), `false`, `0`, or `''` (empty string)) +- but would get the value of `employee.address.postCode` if `employee.address` is [`truthy`](https://developer.mozilla.org/en-US/docs/Glossary/truthy) (e.g. `true`, `1`, `'a'` (non-empty string), or an existing object (even empty object)) + +General examples: +```javascript +'' && 'foo' // returns '' +false && 'foo' // returns false +{} && 'foo' // returns 'foo' +1 && 0 // returns 0 +``` #### 3.8.1 Test Your Understanding @@ -556,14 +603,13 @@ console.log(postCode) // returns undefined ### 3.9 Object Prototypes -All JavaScript object (such as String, Number, Array, etc.) inherit properties and methods from a **prototype**. This also applies to any new objects you create. Since JavaScript does not support _traditional_ classes, this becomes the way to add new functionality. Let's look at a simple example. +All JavaScript objects (such as `String`, `Number`, `Array`, etc.) inherit properties and methods from a [**`prototype`**](https://developer.mozilla.org/en-US/docs/Glossary/Prototype-based_programming). This also applies to any new objects you create. Since JavaScript does not support _traditional_ classes, this becomes the way to add new functionality. Let's look at a simple example. The `String` object does not have a way to convert a string into an array of characters so we will add this. After it is added we can see that _all strings_ have this new behaviour. ```javascript String.prototype.toArray = function() { - const strArr = this.split('') - return strArr + return this.split('') } const nameArray = 'John Doe'.toArray() @@ -582,14 +628,14 @@ There are a couple of important concepts here. ## 4 Object Constructors -As you have seen from the previous section, each object (String, Number, etc) has its own _prototype_, but what about the custom objects you created? It turns out that these also have a prototype, _Object_. Any functionality you add to this will get added to _all the objects in your application!_. To get round this problem NodeJS has the `new` keyword. When this is used we can isolate any changes to the targeted object. +As you have seen from the previous section, each object (String, Number, etc) has its own _prototype_, but what about the custom objects you created? It turns out that these also have a prototype, _Object_. Any functionality you add to this will get added to _all the objects in your application!_. To get around this problem NodeJS has the `new` keyword. When this is used, we can isolate any changes to the targeted object. ### 4.1 Object Constructor Functions -Until ECMA6, there wa a way to achieve this by using a **constructor function**. Whilst this is not now considered the optimal way to achieve our goal there are so many examples of this approach it is important you understand both the syntax and how it works. When we use this approach using the `new` keyword triggers four steps: +Until ECMA6, there was a way to achieve this by using a **constructor function**. While now this isn't considered the optimal way to achieve our goal, there are so many examples of this approach, that it's important you understand both the syntax and how it works. When we use this approach, using the `new` keyword triggers four steps: 1. We create an empty object. -2. We set the its prototype property to the constructor function's prototype function. +2. We set its prototype property to the constructor function's prototype function. 3. We bind its `this` object to the new object. 4. We then return the new object. @@ -621,7 +667,7 @@ Whilst this syntax is not using traditional classes, one object can _extend_ ano ```javascript function Student(name, startYear, course) { Person.call(this, name, startYear) - this.subject = course || 'not enrolled' + this.course = course || 'not enrolled' } const emily = new Student('emily', 2017, 'architecture') @@ -639,14 +685,14 @@ Whilst constructor functions are not particularly elegant they do provide a way ```javascript class Person { - const currentYear = 2019 - - constructor(name, startYear) { - this.name = name - this.startYear = startYear || currentYear - this.years = currentYear - this.startYear - return this - } + constructor(name, startYear) { + const currentYear = 2019 + + this.name = name + this.startYear = startYear || currentYear + this.years = currentYear - this.startYear + return this + } } ``` @@ -654,10 +700,10 @@ Since this is syntactic sugar for the constructor function we can extend this to ```javascript class Student extends Person { - constructor(name, startYear, course) { - super(name, startYear) - this.subject = course || 'not enrolled' - } + constructor(name, startYear, course) { + super(name, startYear) + this.subject = course || 'not enrolled' + } } ``` @@ -667,16 +713,16 @@ We can also make use of **getters** and **setters** to retrieve and modify objec ```javascript class Student extends Person { - constructor(name, startYear, course) { - super(name, startYear) - this.subject = course || 'not enrolled' - } - get course() { - return this.subject - } - set course(newCourse) { - this.subject = newCourse - } + constructor(name, startYear, course) { + super(name, startYear) + this.subject = course || 'not enrolled' + } + get course() { + return this.subject + } + set course(newCourse) { + this.subject = newCourse + } } ``` @@ -686,13 +732,13 @@ Currently each instance of a prototype function is completely self-contained. Wh ```javascript class ECMA6Student extends Person { - constructor(name, startYear, course) { + constructor(name, startYear, course) { super(name, startYear) this.subject = course || 'not enrolled' if(ECMA6Student.count === undefined) ECMA6Student.count = 0 ECMA6Student.count++ - } - static studentCount() { + } + static studentCount() { return ECMA6Student.count } } @@ -718,6 +764,7 @@ You should take time to understand the [pros and cons](https://2ality.com/2016/0 ### 4.6 Test Your Understanding +In a new file called `vehicles.js`: 1. Create a **constructor function** called `OldVehicle` that includes `make`, `model` and `price` information. Use this to create two vehicles of your choice. 2. Use this to create a second **constructor function** class called `OldPickup` that includes `payload` and `seats` fields and use this to create two pickup objects. 3. Now use the same information to create a class called `NewVehicle` and extend this to create a class called `NewPickup` and use this to create two or more pickup objects. diff --git a/exercises/05_javascript/currency.js b/exercises/05_javascript/currency.js index 0725b1f2..82551691 100644 --- a/exercises/05_javascript/currency.js +++ b/exercises/05_javascript/currency.js @@ -2,16 +2,21 @@ 'use strict' -const request = require('request') +const fs = require('fs') -const symbol = 'GBP' +const symbol = 'EUR' -const printRates = (err, res, body) => { - if (err) throw 'could not complete request' - const data = JSON.parse(body) // this converts the formatted string into a javascript object - console.log(`for each EUR you will get ${data.rates[symbol]} ${symbol} today`) +const printRates = (err, data) => { + if (err) throw err + const parsedData = JSON.parse(data) // this converts the formatted string into a javascript object + for (const country of parsedData) { + if (country.code === symbol) { + console.log(`For each GBP you will get ${country.rate} ${symbol} today.`) + return + } + } } -const url = 'currency.json' +const filePath = 'currency.json' -request.get( url, printRates) +fs.readFile(filePath, printRates) \ No newline at end of file diff --git a/exercises/05_javascript/employee.js b/exercises/05_javascript/employee.js index 507492a0..04133976 100644 --- a/exercises/05_javascript/employee.js +++ b/exercises/05_javascript/employee.js @@ -7,7 +7,9 @@ const employee = { firstName: 'Colin', 'last name': 'Stephen', startYear: 2010, - getName: () => `${this.firstName} ${this['last name']}`, + getName: function() { + return `${this.firstName} ${this["last name"]}` + }, setName: function(fullname) { console.log(fullname) const words = fullname.toString().split(' ') @@ -23,3 +25,7 @@ console.log(jsonString) employee.setName('Micky Mouse') console.log(JSON.stringify(employee, null, 2)) + +// TypeError: +// const postCode = employee.address.postCode +// console.log(postCode) \ No newline at end of file diff --git a/exercises/05_javascript/weather.js b/exercises/05_javascript/weather.js index f139cc00..e72b7bac 100755 --- a/exercises/05_javascript/weather.js +++ b/exercises/05_javascript/weather.js @@ -4,12 +4,13 @@ const request = require('request') -const url = 'https://api.openweathermap.org/data/2.5/weather?q=coventry,uk&appid=44c39f3fa462f86b3fc88f5678e5c5ff' +const apiKey = '44c39f3fa462f86b3fc88f5678e5c5ff' +const cityName = 'coventry,uk' -request(url, (err, response, body) => { +request(`https://api.openweathermap.org/data/2.5/weather?q=${cityName}&appid=${apiKey}`, (err, response, body) => { if(err) console.log(err.message) console.log(`the body variable contains a ${typeof body}`) const data = JSON.parse(body) console.log(`the data variable contains an ${typeof data}`) console.log(data) -}) +}) \ No newline at end of file diff --git a/solutions/05_javascript/contact.js b/solutions/05_javascript/contact.js new file mode 100644 index 00000000..3d358404 --- /dev/null +++ b/solutions/05_javascript/contact.js @@ -0,0 +1,81 @@ +#!/usr/bin/env node + +'use strict' + +/* This script demonstrates how JavaScript can be used to handle exceptions. */ + +const readline = require('readline-sync') + +/* any code that could throw an exception needs to be wrapped in a try block. If any line of code in the try block throws an exception the program immediately jumps to the catch block, passing the Error object thrown. Regardless of whether an error was thrown or not, the code in the finally block is run. */ +try { + const email = String(readline.question('enter email address: ')) + console.log('email is a '+typeof email+' and contains '+email) + validateEmail(email) + const score = Number(readline.question('assign score 1-10: ')) + console.log('score is a '+typeof score+' and contains '+score) + validateScore(score) + const comment = String(readline.question('enter your comment : ')) + validateComment(comment) + console.log(`Thank you ${email}. You gave us a rating of ${score}/10 with the comment "${comment}"`) +} catch(err) { + console.log(`${err.name} thrown`) + console.log(`The error message is: ${err.message}`) + console.log(err.stack) +} finally { + console.log('the script has finished') +} + +/** + * Checks to see if the supplied parameter is formatted as a valid email + * address. + * @param {string} email - The email address to be checked. + * @returns {bool} the validity of the email address string + * @throws {TypeError} if the parameter is not a valid email address. + */ +function validateEmail(email) { + console.log(email) + const atIndex = email.lastIndexOf('@') + const dotIndex = email.lastIndexOf('.') + if ( email.length < 5 + || atIndex < 1 + || email.indexOf(' ') !== -1 + || email.indexOf('..') !== -1 + || dotIndex < atIndex + || dotIndex === email.length - 1 ) { + throw TypeError + } + return true +} + +/** + * Checks to see if the supplied parameter is a valid integer in the range 1-10. + * @param {string} score - The user-specified score. + * @returns {bool} whether the parameter is a valid integer in range + * @throws {TypeError} if the parameter is not a valid integer. + * @throws {RangeError} if the parameter is not in the range 1-10. + */ +function validateScore(score) { + const minScore = 0 + const maxScore = 10 + if (Number.isNaN(score) || score % 1 !== minScore) { + throw new TypeError('parameter is not a valid integer') + } + if (score < 1 || score > maxScore) { + throw new RangeError('parameter should be in the range 1-10') + } + return true +} + +/** + * Checks to see if the supplied comment is 'valid'. + * @param {string} comment - The user-specified score. + * @returns {bool} whether the comment is 'valid' + * @throws {RangeError} if the comment is not long enough. + */ +function validateComment(comment) { + const minLen = 5 + if (comment.length < minLen) { + throw new RangeError('comment should be at least 5 characters long') + } + return true +} diff --git a/solutions/05_javascript/employee.js b/solutions/05_javascript/employee.js new file mode 100644 index 00000000..54429d58 --- /dev/null +++ b/solutions/05_javascript/employee.js @@ -0,0 +1,78 @@ +#!/usr/bin/env node +/* eslint no-magic-numbers: 0 */ + +'use strict' + +const employee = { + firstName: 'Colin', + 'last name': 'Stephen', + startYear: 2010, + gender: 'male', + 'date of birth': '1980-01-01', + getName: function() { + return `${this.firstName} ${this["last name"]}` + }, + setName: function(fullname) { + console.log(fullname) + const words = fullname.toString().split(' ') + console.log(words) + console.log(this) + this.firstName = words[0] || '' + this['last name'] = words[1] || '' + }, + get details() { + return `firstName: ${this.firstName}, lastName: ${this["last name"]}, startYear: ${this.startYear}, gender: ${this.gender}, DoB: ${this["date of birth"]}` + }, + get yearsWorked() { + return (new Date().getFullYear() - this.startYear) + }, + set name(fullname) { + const names = fullname.toString().split(' ') + this.firstName = names[0] + this["last name"] = names[1] + } +} + +const jsonString = JSON.stringify(employee, null, 2) +console.log(jsonString) + +employee.setName('Micky Mouse') +console.log(JSON.stringify(employee, null, 2)) + +// TypeError: +// const postCode = employee.address.postCode +// console.log(postCode) + +const university = { + year1: { + a101: 'something11', + b104: 'something12', + c134: 'something13' + }, + year2: { + d201: 'something21', + e204: 'something22', + f234: 'something23' + }, + year3: { + g301: 'something31', + h304: 'something32', + i334: 'something33' + } +} + +const study01 = university.year1 +for(const code in study01) console.log(`${code} ${study01[code]}`) + +const {year1: year1, year2: year2, year3: year3} = university + +delete employee.startYear +employee.startYear = '2010' + +String.prototype.toArray = function() { + return this.split('') +} +Array.prototype.toStr = function() { + return this.join('') +} +console.log('foobar'.toArray().toStr()) \ No newline at end of file diff --git a/solutions/05_javascript/maths.js b/solutions/05_javascript/maths.js new file mode 100644 index 00000000..e7e6e769 --- /dev/null +++ b/solutions/05_javascript/maths.js @@ -0,0 +1,106 @@ +#!/usr/bin/env node +/* eslint no-magic-numbers: 0 */ + +'use strict' + +function largestNumber(a, b) { + if (a > b) return a + if (b > a) return b + return null +} + +const biggest = largestNumber(5, 8) +console.log(biggest) +// the code below achieves the same using the 'spread operator' +const nums = [5, 8] +const biggest2 = largestNumber(...nums) +console.log(biggest2) + +// example using the arguments object +function add() { + let total = 0 + console.log(arguments) + console.log(arguments['1']) + for(const arg of arguments) { + total += arg + } + return total +} + +const addNums = add(1, 2, 3, 4) +console.log(addNums) + + +// example using a rest parameter +function add2(...values) { + let total = 0 + console.log(values) + for (let i=0; i dividend - Math.floor(dividend / divisor) * divisor +console.log('remainder2: ' + remainder2(13, 4)) + +// function expression using arrow syntax and one parameter +const sqr = num => num * num +console.log(sqr(4)) + +function multiply(a = 1, b = 1) { + return a * b +} +console.log(multiply(3, 5)) + +function divideThis(dividend, divisor = 1) { + return dividend / divisor +} +console.log(divideThis(5, 2)) + +function average(...numbers) { + if (numbers.length === 0) return 0 + let sum = 0 + for (const number of numbers) sum += number + return sum / numbers.length +} +console.log(`average of [2, 4, 6]: ${average(2, 4, 6)}`) + +const squareRoot = a => Math.sqrt(a) +console.log(`squareRoot of 4096: ${squareRoot(4096)}`) + +const longest = (...strings) => strings.length === 0 ? null : strings.reduce((longestString, currentString) => currentString.length > longestString.length ? currentString : longestString) +// simple version without using reduce: +// const longest = (...strings) => { +// if (strings.length === 0) return null +// let longest = strings[0] +// for (const string of strings) if (string > longest) longest = string +// return longest +// } +console.log(`longest of ['a', 'aaa', 'aa']: ${longest('a', 'aaa', 'aa')}`) \ No newline at end of file diff --git a/solutions/05_javascript/quotes.js b/solutions/05_javascript/quotes.js new file mode 100644 index 00000000..45b2c6e4 --- /dev/null +++ b/solutions/05_javascript/quotes.js @@ -0,0 +1,12 @@ +#!/usr/bin/env node + +'use strict' + +require('fs').readFile('quotes.json', (err, data) => { + if (err) console.log(err) + const quotesArray = JSON.parse(data) + console.log(quotesArray) + for (const quoteObject of quotesArray) { + console.log(quoteObject.quote) + } +}) \ No newline at end of file diff --git a/solutions/05_javascript/quotes.json b/solutions/05_javascript/quotes.json new file mode 100644 index 00000000..bd394721 --- /dev/null +++ b/solutions/05_javascript/quotes.json @@ -0,0 +1,42 @@ +[ + { + "quote":"We know what we are, but know not what we may be.", + "author":"William Shakespeare" + }, + { + "quote":"Perfection is not attainable, but if we chase perfection we can catch excellence.", + "author":"Vince Lombardi" + }, + { + "quote":"Do your little bit of good where you are; it's those little bits of good put together that overwhelm the world.", + "author":"Desmond Tutu" + }, + { + "quote":"My mission in life is not merely to survive, but to thrive; and to do so with some passion, some compassion, some humor, and some style.", + "author":"Maya Angelou" + }, + { + "quote":"We must let go of the life we have planned, so as to accept the one that is waiting for us.", + "author":"Joseph Campbell" + }, + { + "quote":"The measure of who we are is what we do with what we have.", + "author":"Vince Lombardi" + }, + { + "quote":"Don't judge each day by the harvest you reap but by the seeds that you plant.", + "author":"Robert Louis Stevenson" + }, + { + "quote":"I hated every minute of training, but I said, 'Don't quit. Suffer now and live the rest of your life as a champion.'", + "author":"Muhammad Ali" + }, + { + "quote":"Thousands of candles can be lighted from a single candle, and the life of the candle will not be shortened. Happiness never decreases by being shared.", + "author":"Buddha" + }, + { + "quote":"How wonderful it is that nobody need wait a single moment before starting to improve the world.", + "author":"Anne Frank" + } +] \ No newline at end of file diff --git a/solutions/05_javascript/university.json b/solutions/05_javascript/university.json new file mode 100644 index 00000000..50ce27a3 --- /dev/null +++ b/solutions/05_javascript/university.json @@ -0,0 +1,17 @@ +{ + "year1": { + "a101": "something11", + "b104": "something12", + "c134": "something13" + }, + "year2": { + "d201": "something21", + "e204": "something22", + "f234": "something23" + }, + "year3": { + "g301": "something31", + "h304": "something32", + "i334": "something33" + } +} \ No newline at end of file diff --git a/solutions/05_javascript/vehicles.js b/solutions/05_javascript/vehicles.js new file mode 100644 index 00000000..d0dfeaf1 --- /dev/null +++ b/solutions/05_javascript/vehicles.js @@ -0,0 +1,49 @@ +#!/usr/bin/env node + +'use strict' + +function OldVehicle(make, model, price) { + this.make = make + this.model = model + this.price = price +} + +const OldVehicle1 = new OldVehicle('Jaguar', 'E-type', 5600) +console.log(OldVehicle1) +const OldVehicle2 = new OldVehicle('Volkswagen', 'Beetle', 3200) +console.log(OldVehicle2) + +function OldPickup(make, model, price, payload, seats) { + OldVehicle.call(this, make, model, price) + this.payload = payload + this.seats = seats +} + +const OldPickup1 = new OldPickup('GMC', 'Sonoma', 14000, 1500, 2) +console.log(OldPickup1) +const OldPickup2 = new OldPickup('Jeep', 'Comanche', 15900, 1800, 2) +console.log(OldPickup2) + +class NewVehicle { + constructor(make, model, price) { + this.make = make + this.model = model + this.price = price + } +} + +class NewPickup extends NewVehicle { + static totalValue = 0 + constructor(make, model, price, payload, seats) { + super(make, model, price) + this.payload = payload + this.seats = seats + NewPickup.totalValue += price + } +} + +const NewPickup1 = new NewPickup('Ford', 'F-150', 46900, 3000, 5) +console.log(NewPickup1) +const NewPickup2 = new NewPickup('Chevrolet', 'Silverado', 44900, 2500, 5) +console.log(NewPickup2) +console.log(NewPickup.totalValue) \ No newline at end of file diff --git a/solutions/05_javascript/weather.js b/solutions/05_javascript/weather.js new file mode 100644 index 00000000..d8f45dab --- /dev/null +++ b/solutions/05_javascript/weather.js @@ -0,0 +1,22 @@ +#!/usr/bin/env node + +'use strict' + +const request = require('request') + +const apiKey = '44c39f3fa462f86b3fc88f5678e5c5ff' +const cityName = 'coventry,uk' + +request(`https://api.openweathermap.org/data/2.5/weather?q=${cityName}&appid=${apiKey}`, (err, response, body) => { + if(err) console.log(err.message) + console.log(`the body variable contains a ${typeof body}`) + const data = JSON.parse(body) + console.log(`the data variable contains an ${typeof data}`) + console.log(data) + + request(`https://api.openweathermap.org/data/2.5/onecall?lat=${data.coord.lat}&lon=${data.coord.lon}&appid=${apiKey}`, (err, response, body) => { + if(err) console.log(err.message) + const data = JSON.parse(body) + console.log(data) + }) +}) \ No newline at end of file From 059e611b3275533e6487d045d574abfef5aff25a Mon Sep 17 00:00:00 2001 From: Balazs Bordas Date: Wed, 7 Oct 2020 12:39:51 +0200 Subject: [PATCH 69/70] fixed errors and added solutions for 06_code_quality --- 06 Code Quality.md | 167 ++++++++++--------- exercises/06_code_quality/asyncFunctions.js | 2 +- exercises/06_code_quality/todo/jsdoc.conf | 24 +++ solutions/06_code_quality/asyncFunctions.js | 67 ++++++++ solutions/06_code_quality/nestedCallbacks.js | 52 ++++++ solutions/06_code_quality/promises.js | 70 ++++++++ solutions/06_code_quality/todo/index.js | 80 +++++++++ solutions/06_code_quality/todo/list.js | 53 ++++++ 8 files changed, 433 insertions(+), 82 deletions(-) create mode 100644 exercises/06_code_quality/todo/jsdoc.conf create mode 100644 solutions/06_code_quality/asyncFunctions.js create mode 100644 solutions/06_code_quality/nestedCallbacks.js create mode 100644 solutions/06_code_quality/promises.js create mode 100644 solutions/06_code_quality/todo/index.js create mode 100644 solutions/06_code_quality/todo/list.js diff --git a/06 Code Quality.md b/06 Code Quality.md index dff65bfa..70301121 100644 --- a/06 Code Quality.md +++ b/06 Code Quality.md @@ -34,11 +34,11 @@ The package manifest includes a `scripts` object which can be used to store your ```json "scripts": { - "linter": "./node_modules/.bin/eslint ." - } + "linter": "./node_modules/.bin/eslint ." +} ``` -Don't wory about understanding what a linter is for the moment. Since you have already installed all the module dependencies in the previous section you can run the script using: +Don't worry about understanding what a linter is for the moment. Since you have already installed all the module dependencies in the previous section you can run the script using: ```shell $ npm run linter @@ -81,11 +81,11 @@ The object property value shorthand notation is useful if the keys have the same ```javascript module.exports = { - List: List + List: List } ``` -Now look at the top of the `index.js` file. Lines 18-19 import the module and create an instance of the List prototype. Notice that we are only importing the `List` prototype from the module. This `List` object prototype is then used to create a new object. This object is called `list` and provides access to all the functionality defined in the object prototype. Foe example to add an item we can use: +Now look at the top of the `index.js` file. Lines 18-19 import the module and create an instance of the List prototype. Notice that we are only importing the `List` prototype from the module. This `List` object prototype is then used to create a new object. This object is called `list` and provides access to all the functionality defined in the object prototype. For example to add an item we can use: ```javascript list.add('bread', 42) @@ -116,10 +116,10 @@ Locate the `06_code_quality/todo/` directory and study the `index.js` file. You You should start by ensuring you have installed `eslint` which is considered the industry standard and that you have a copy of the approved configuration file `.eslintrc.json` in the root directory of your project. -Now navigate to the `06_code_quality/` directory using terminal and run the linter on the `index.js` code in the `todo/` directory: +Now navigate to the `06_code_quality/todo` directory using terminal and run the linter on the `index.js` script: ```shell -$ node_modules/.bin/eslint todo/index.js +$ node_modules/.bin/eslint index.js ``` You will see a list of issues that the linter has flagged in your code. Notice that some of these are flagged as errors (serious) and some as warnings (recommendations). Each message includes: @@ -133,7 +133,7 @@ The latter can be used to quickly look up the rules in the [comprehensive docume Instead of running separate checks on every file, we can specify the directory we want to check and it will automatically scan all the subdirectories. For example to scan all the files in the `modules/` directory we could run: ```shell -$ node_modules/.bin/eslint todo/ +$ node_modules/.bin/eslint modules/ ``` ### 3.1 Test Your Understanding @@ -144,7 +144,7 @@ $ node_modules/.bin/eslint todo/ ## 4 Documentation -In this third and last topic we will be using the [JSDoc](http://usejsdoc.org) tool to build a detailed code documentation website by extracting special comments inserted into our source code. +In this topic we will be using the [JSDoc](http://usejsdoc.org) tool to build a detailed code documentation website by extracting special comments inserted into our source code. The default set of documentation tools provided in JSDoc are not suitable for documenting Koa routes and so we will be using a plugin called [jsdoc-route-plugin](https://www.npmjs.com/package/jsdoc-route-plugin). This should have been installed by the package manifest however you should check that you are using the current version of the `package.json` file and update if needed, rerunning the `npm install` command to ensure all packages are installed. You should also check that you have the latest version of the `jsdoc.conf` configuration file. @@ -162,6 +162,11 @@ If you run this command you should see a new directory called `docs/` which will You will probably have noticed that only a couple of the functions include complete JSDoc comments and so the documentation website is incomplete. Your task is to use the existing comments for guidance and complete the task of documenting your code. You will find the [JSDoc](http://usejsdoc.org) and [jsdoc-route-plugin](https://www.npmjs.com/package/jsdoc-route-plugin) documentation helpful. +To run `jsdoc` as preconfigured with the `jsdoc.conf` file, including the plugin, simply use: +```shell +./node_modules/.bin/jsdoc -c jsdoc.conf +``` + ## 5 Improved Async Code Since NodeJS has a single thread that handles all incoming requests it is vital that we push long-running tasks into their own threads, typically through the use of _callback functions_. In this section of the lab you will learn about the limitations of callbacks and explore more powerful ways to handle multi-threading. @@ -170,15 +175,15 @@ Since NodeJS has a single thread that handles all incoming requests it is vital Because the code to be run after a callback is run needs to be _inside_ the callback code it is very challenging to build a script that contains several long-running tasks you get into a situation where you nest callbacks inside callbacks (inside callbacks) which makes the code very difficult to write, debug and read and means its very difficult to split into separate functions, a situation commonly known as **Callback Hell**. -Open the file `nestedCallbacks.js` which asks for a _base_ currency code then prints out all the exchange rates against other currencies. Notice that there are four functions defined, three of which include a callback. Our script is designed to capture user input using `stdin` (needing a callback), identify whether a currency code is valid (requiring a second callback) and then getting the currency conversion rates for the specified currency (requiring a third callback). +Open the file `nestedCallbacks.js` which asks for a _base_ currency code then prints out all the exchange rates against other currencies. Notice that there are four functions defined, each of them including a callback. Our script is designed to capture user input using `stdin` (needing a callback), identify whether a currency code is valid (requiring a second callback) and then getting the currency conversion rates for the specified currency (requiring a third callback). -1. The script starts be calling the `read.question()` function (line 13) which takes a callback function as its second parameter. +1. The script starts by calling the `read.question()` function (line 13) which takes a callback function as its second parameter. 2. We want the first `request()` function (line 18) to be run after the initial `read.question()` function has completed. - 1. To do this it needs to be called from inside the `read.question()` callback function. + - To do this it needs to be called from inside the `read.question()` callback function. 3. The second `request()` function should run after the first one has completed and the data has been processed. - 1. To do this it needs to be called from inside the callback function of the first `request()` call. + - To do this it needs to be called from inside the callback function of the first `request()` call. 4. The final step is to call the `read.question()` function again (line 38)) which should be run once the second request has completed. - 1. Therefore this needs to be in the callback function from the second `request()` function. + - Therefore this needs to be in the callback function from the second `request()` function. As you can see, each step has to be nested inside the previous step's callback, creating an ever increasing level of nested code sometime referred to as [Callback Hell](http://callbackhell.com/) or the [Pyramid of Doom](https://en.wikipedia.org/wiki/Pyramid_of_doom_(programming)). @@ -189,21 +194,21 @@ Callbacks are the simplest possible mechanism for asynchronous code in JavaScrip The callbacks are already nested 4 deep. You are now going to add some additional functionality and, in doing this, are going to have to make use of additional nested callbacks! 1. The deepest callback is a prompt asking the user for the currency they want to convert into. Add the logic to retrieve the correct exchange rate from the data returned from the previous API call. -2. Instead of printing the exchange rate, ask for the amount to be converted and them return the equivalent in the chosen currency +2. Instead of printing the exchange rate, ask for the amount to be converted and then return the equivalent in the chosen currency 3. The `currencies.json` file contains a map between the currency code and the country name. Load this file into the script using the [`fs`](https://nodejs.org/api/fs.html) module, convert to a JavaScript object using the [`JSON`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON) object and use it to display the full name of the chosen currency. Below is some code to get you started. You will need to import the `fs` module and use the `fs.readFile()` function which takes a callback! ```javascript fs.readFile('currencies.json', 'utf8', (err, contents) => { - if(err) console.log('you need to handle this properly') - console.log(contents) + if(err) console.log('you need to handle this properly') + console.log(contents) }) ``` Even though the script is still simple you are probably already getting in a tangle! Imagine a more complex script with conditions, it would quickly get out of hand and become practically impossible to debug. -Thankfully there are a number of advance features in NodeJS that are designed to flatten out these callbacks and to treat asynchronous code in a more _synchronous_ manner. These care called _Generators_, _Promises_ and _Async Functions_ and are described below. Even though you don't technically _need_ to know these, its worth learning them to keep your code manageable. +Thankfully there are a number of advanced features in NodeJS that are designed to flatten out these callbacks and to treat asynchronous code in a more _synchronous_ manner. These are called _Generators_, _Promises_ and _Async Functions_ and are described below. Even though you don't technically _need_ to know these, its worth learning them to keep your code manageable. ## 6 Promises @@ -222,10 +227,10 @@ Promises are created using the `new` keyword. This function is called immediatel ```javascript const url = 'https://api.exchangeratesapi.io/latest?base=GBP' const getData = url => new Promise( (resolve, reject) => { - request(url, (err, res, body) => { - if (err) reject(new Error('invalid API call')) - resolve(body) - }) + request(url, (err, res, body) => { + if (err) reject(new Error('invalid API call')) + resolve(body) + }) }) ``` @@ -248,7 +253,7 @@ aPromise.then( data => console.log(data)) aPromise.catch( err => console.error(`error: ${err.message}`) ) ``` -In this example we create a _new Promise_ and store it in a variable. It get executed _immediately_. The second line calls its `then()` method which will get executed if the promise state becomes _fulfilled_ (the API call is successful). The parameter will be assigned the value passed when the `resolve()` function is called in the promise, in this case it will contain the JSON data returned by the API call. +In this example we create a _new Promise_ and store it in a variable. It gets executed _immediately_. The second line calls its `then()` method which will get executed if the promise state becomes _fulfilled_ (the API call is successful). The parameter will be assigned the value passed when the `resolve()` function is called in the promise, in this case it will contain the JSON data returned by the API call. If the state of the promise changes to _rejected_, the `catch()` method is called. The parameter will be set to the value passed to the `reject()` function inside the promise. In this example it will contain an `Error` object. @@ -256,41 +261,41 @@ This code can be written in a more concise way by _chaining_ the promise methods ```javascript getData('https://api.exchangeratesapi.io/latest?base=GBP') - .then( data => console.log(data)) - .catch( err => console.error(`error: ${err.message}`)) + .then( data => console.log(data)) + .catch( err => console.error(`error: ${err.message}`)) ``` Because the Promise is executed immediately we don't need to store it in a variable. The `.then()` and `.catch()` methods are simply chained onto the promise. This form is much more compact and allows us to chain multiple promises together to solve more complex tasks. ### 6.3 Chaining Promises -The real power of promises comes from their ability to be _chained_. This allows the results from a promise to be passed to another promise. All you need to do is pass another promise to the `next()` method. +The real power of promises comes from their ability to be _chained_. This allows the results from a promise to be passed to another promise. All you need to do is pass another promise to the `then()` method. ```javascript const getData = url => new Promise( (resolve, reject) => { - request(url, (err, res, body) => { - if (err) reject(new Error('invalid API call')) - resolve(body) - }) + request(url, (err, res, body) => { + if (err) reject(new Error('invalid API call')) + resolve(body) + }) }) const printObject = data => new Promise( resolve => { - const indent = 2 - data = JSON.parse(data) - const str = JSON.stringify(data, null, indent) - console.log(str) - resolve() + const indent = 2 + data = JSON.parse(data) + const str = JSON.stringify(data, null, indent) + console.log(str) + resolve() }) const exit = () => new Promise( () => { - process.exit() + process.exit() }) getData('https://api.exchangeratesapi.io/latest?base=GBP') - .then( data => printObject(data)) - .then( () => exit()) - .catch(err => console.error(`error: ${err.message}`)) - .then( () => exit()) + .then( data => printObject(data)) + .then( () => exit()) + .catch(err => console.error(`error: ${err.message}`)) + .then( () => exit()) ``` Notice that we pass the `printObject` promise to the `then()` method. The data passed back from the `getData` promise is passed to the `printObject` promise. @@ -303,32 +308,32 @@ If a promise only takes a single parameter and this matches the data passed back ```javascript getData('https://api.exchangeratesapi.io/latest?base=GBP') - .then(printObject) - .then(exit) - .catch(err => console.error(`error: ${err.message}`)) - .then(exit) + .then(printObject) + .then(exit) + .catch(err => console.error(`error: ${err.message}`)) + .then(exit) ``` There are some situations where you can't simply pass the output from one promise to the input of the next one. Sometimes you need to store data for use further down the promise chain. This can be achieved by storing the data in the `this` object. ```javascript getData('https://api.exchangeratesapi.io/latest?base=GBP') - .then( data => this.jsonData = data) - .then( () => printObject(this.jsonData)) - .then(exit) - .catch(err => console.error(`error: ${err.message}`)) - .then(exit) + .then( data => this.jsonData = data) + .then( () => printObject(this.jsonData)) + .then(exit) + .catch(err => console.error(`error: ${err.message}`)) + .then(exit) ``` In the example above we store the data returned from the `getData` promise in the `this` object. This is then used when we call the `printObject` promise. ### 6.4 Test Your Knowledge -Run the `promises.js` script. Its functionality should be familiar to the `currency.js` script you worked with in chapter 3. +Run the `promises.js` script. Its functionality should be familiar to the `currency.js` script you worked with in chapter 5. Study the code carefully. Notice that it defines 5 promises and chains them together. You are going to extend the functionality by defining some additional promises and adding them to the promise chain. -1. Modify the script to ask for the currency to convert to and display only the one conversion rate. +1. Modify the script to display only the one conversion rate from the user input. 2. Instead of printing the exchange rate, ask for the amount to be converted and them return the equivalent in the chosen currency. 3. The `currencies.json` file contains a map between the currency code and the country name. Load this file into the script using the [`fs`](https://nodejs.org/api/fs.html) module, convert to a JavaScript object using the [`JSON`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON) object and use it to display the full name of the chosen currency. @@ -337,8 +342,8 @@ Study the code carefully. Notice that it defines 5 promises and chains them toge In the async examples we have seen so far, each async function needs to complete before the next async call is run. The diagram below shows how this looks. ``` - 1 2 3 - ───⬤─────⬤─────⬤ + 1 2 3 + ────⬤─────⬤─────⬤ ``` The program flow is. @@ -367,7 +372,7 @@ dataArray.forEach( curr => { In the example above we loop through the `dataArray`, creating a new promise object that we push onto our `promiseArray`. - Once we have an array of promises there are two possible scenarios. +Once we have an array of promises there are two possible scenarios. 1. We want _all_ the promises in the array to be fulfilled before continuing the promise chain. 2. We want _one_ of the promises to be fulfilled but we don't care which one. @@ -378,8 +383,8 @@ In the first scenario we want _all_ the promises to be fulfilled before continui ```javascript Promise.all(itemPromises) - .then( results => results.forEach( item => console.log(item))) - .catch( err => console.log(`error: ${err.message}`)) + .then( results => results.forEach( item => console.log(item))) + .catch( err => console.log(`error: ${err.message}`)) ``` When the `Promise.all()` method fulfills it returns an array of results. In the example above we loop through these and print each to the terminal. @@ -413,52 +418,52 @@ Here is a simple example. ```javascript const getData = url => new Promise( (resolve, reject) => { - request(url, (err, res, body) => { - if (err) reject(new Error('invalid API call')) - resolve(body) - }) + request(url, (err, res, body) => { + if (err) reject(new Error('invalid API call')) + resolve(body) + }) }) const printObject = data => new Promise( resolve => { - console.log(JSON.stringify(JSON.parse(data), null, 2)) - resolve() + console.log(JSON.stringify(JSON.parse(data), null, 2)) + resolve() }) async function main() { - try { - const data = await getData('https://api.exchangeratesapi.io/latest?base=GBP') - await printObject(data) - process.exit() - } catch (err) { - console.log(`error: ${err.message}`) - process.exit() - } + try { + const data = await getData('https://api.exchangeratesapi.io/latest?base=GBP') + await printObject(data) + process.exit() + } catch (err) { + console.log(`error: ${err.message}`) + process.exit() + } } main() ``` Async functions are declared using the `async` keyword in the function declaration, all errors are handled using the standard `try-catch` block. Because the main block of code needs to be in an _async function_, this has to be explicitly executed at the end of the script. -The `getData()` function returns a _promise_. it is called using the `await` keyword, this pauses the execution of the `main()` function until `getData()` is either _fulfilled_ or _rejected_. If it is _fulfilled_, the data returned is stored in the `data` variable and control moves to the next line, if it is _rejected_ code execution jumps to the `catch()` block. +The `getData()` function returns a _promise_. It is called using the `await` keyword, this pauses the execution of the `main()` function until `getData()` is either _fulfilled_ or _rejected_. If it is _fulfilled_, the data returned is stored in the `data` variable and control moves to the next line, if it is _rejected_ code execution jumps to the `catch()` block. ### 7.2 Simplified Promises Async functions are implicitly wrapped in a `Promise.resolve()` and any uncaught errors are wrapped in a `Promise.reject()`. This means that an _async function_ can be substituted for a _promise_. let's look at a simple example. ```javascript -const printObjectPromise = data => new Promise( (resolve) => { - const indent = 2 - data = JSON.parse(data) - const str = JSON.stringify(data, null, indent) - console.log(str) - resolve() +const printObjectPromise = data => new Promise( resolve => { + const indent = 2 + data = JSON.parse(data) + const str = JSON.stringify(data, null, indent) + console.log(str) + resolve() }) const printObjectAsync = async data => { - const indent = 2 - data = JSON.parse(data) - const str = JSON.stringify(data, null, indent) - console.log(str) + const indent = 2 + data = JSON.parse(data) + const str = JSON.stringify(data, null, indent) + console.log(str) } ``` diff --git a/exercises/06_code_quality/asyncFunctions.js b/exercises/06_code_quality/asyncFunctions.js index cca2bfda..a272cf25 100644 --- a/exercises/06_code_quality/asyncFunctions.js +++ b/exercises/06_code_quality/asyncFunctions.js @@ -30,7 +30,7 @@ const checkValidCurrencyCode = code => new Promise( (resolve, reject) => { request(baseURL, (err, res, body) => { if (err) reject(new Error('invalid API call')) const rates = JSON.parse(body).rates - if (!rates.hasOwnProperty(code)) it.throw(new Error(`invalid currency code ${code}`)) + if (!rates.hasOwnProperty(code)) throw new Error(`invalid currency code ${code}`) resolve() }) }) diff --git a/exercises/06_code_quality/todo/jsdoc.conf b/exercises/06_code_quality/todo/jsdoc.conf new file mode 100644 index 00000000..a8b02479 --- /dev/null +++ b/exercises/06_code_quality/todo/jsdoc.conf @@ -0,0 +1,24 @@ +{ + "plugins": ["jsdoc-route-plugin"], + "recurseDepth": 10, + "source": { + "include": [ "." ], + "exclude": [ "node_modules" ], + "includePattern": ".+\\.js(doc|x)?$", + "excludePattern": "(^|\\/|\\\\)_" + }, + "sourceType": "module", + "tags": { + "allowUnknownTags": true, + "dictionaries": ["jsdoc","closure"] + }, + "templates": { + "cleverLinks": false, + "monospaceLinks": false + }, + "opts": { + "encoding": "utf8", + "destination": "./docs/jsdoc", + "recurse": true + } +} \ No newline at end of file diff --git a/solutions/06_code_quality/asyncFunctions.js b/solutions/06_code_quality/asyncFunctions.js new file mode 100644 index 00000000..eaa1d1b3 --- /dev/null +++ b/solutions/06_code_quality/asyncFunctions.js @@ -0,0 +1,67 @@ + +'use strict' + +const request = require('request') +const readline = require('readline-sync') +const fs = require('fs') + +const baseURL = 'https://api.exchangeratesapi.io/latest' + +async function main() { + try { + const base = await getInput('enter base currency') + await checkValidCurrencyCode(base) + const data = await getData(`${baseURL}?base=${base}`) + const rates = JSON.parse(data).rates + await printObject(data) + const to = await getInput('convert to') + await checkValidCurrencyCode(to) + console.log(to) + const amount = await getInput('enter exchange amount') + const decoder = await readObjectFromFile('currencies.json') + console.log(`${amount} ${decoder[base]} (${base}) is worth ${ + (rates[to] * amount).toFixed(4)} ${decoder[to]} (${to})`) + process.exit() + } catch (err) { + console.log(`error: ${err.message}`) + } +} + +const getInput = async prompt => readline.question(`${prompt}: `) + +const checkValidCurrencyCode = code => new Promise( (resolve, reject) => { + code = code.trim() + request(baseURL, (err, res, body) => { + if (err) reject(new Error('invalid API call')) + const rates = JSON.parse(body).rates + if (!rates.hasOwnProperty(code)) throw new Error(`invalid currency code ${code}`) + resolve() + }) +}) + +const getData = url => new Promise( (resolve, reject) => { + request(url, (err, res, body) => { + if (err) reject(new Error('invalid API call')) + resolve(body) + }) +}) + +const printObject = async data => { + const indent = 2 + data = await JSON.parse(data) + const str = JSON.stringify(data, null, indent) + await new Promise( resolve => { + console.log(str) + resolve() + }) + +} + +const readObjectFromFile = fileName => new Promise( (resolve, reject) => { + fs.readFile(fileName, 'utf-8', (err, content) => { + if (err) reject(new Error(err)) + return resolve(JSON.parse(content)) + }) +}) + +main() diff --git a/solutions/06_code_quality/nestedCallbacks.js b/solutions/06_code_quality/nestedCallbacks.js new file mode 100644 index 00000000..789ae5c1 --- /dev/null +++ b/solutions/06_code_quality/nestedCallbacks.js @@ -0,0 +1,52 @@ +#!/usr/bin/env node + +/* eslint max-lines-per-function: 0 */ + +'use strict' + +const request = require('request') +const readline = require('readline') +const fs = require('fs') + +const io = { input: process.stdin, output: process.stdout } + +const read = readline.createInterface(io) +read.question('input base currency: ', base => { + console.log(`You entered ${base}`) + read.close() + base = base.trim() + // now we need to check the code is valid + request('https://api.exchangeratesapi.io/latest', (err, res, body) => { + if (err) { + console.error(err.message) + process.exit() + } + const rates = JSON.parse(body).rates + if (!rates.hasOwnProperty(base)) { + console.error(`invalid currency code ${base}`) + process.exit() + } + // now we can get the currency rates + request(`https://api.exchangeratesapi.io/latest?base=${base}`, (err, res, body) => { + if (err) { + console.error(err.message) + process.exit() + } + body = JSON.parse(body) + console.log(body) + // lets ask another question + const read = readline.createInterface(io) + read.question('convert to: ', convertTo => { + read.question('amount to convert: ', amount => { + read.close() + fs.readFile('currencies.json', 'utf8', (err, content) => { + if(err) console.error(error.message) + const decoder = JSON.parse(content) + console.log(`${amount} ${decoder[base]} (${base}) is worth ${ + (body.rates[convertTo] * amount).toFixed(4)} ${decoder[convertTo]} (${convertTo})`) + }) + }) + }) + }) + }) +}) diff --git a/solutions/06_code_quality/promises.js b/solutions/06_code_quality/promises.js new file mode 100644 index 00000000..82a6d831 --- /dev/null +++ b/solutions/06_code_quality/promises.js @@ -0,0 +1,70 @@ + +'use strict' + +const request = require('request') +const readline = require('readline') +const fs = require('fs') + +const baseURL = 'https://api.exchangeratesapi.io/latest' + +const getInput = prompt => new Promise(resolve => { + const read = readline.createInterface({ input: process.stdin, output: process.stdout }) + read.question(`${prompt}: `, value => { + console.log(`You entered ${value}`) + read.close() + return resolve(value) + }) +}) + +const checkValidCurrencyCode = code => new Promise( (resolve, reject) => { + code = code.trim() + request(baseURL, (err, res, body) => { + if (err) reject(new Error('invalid API call')) + const rates = JSON.parse(body).rates + if (!rates.hasOwnProperty(code)) reject(new Error(`invalid currency code ${code}`)) + return resolve(code) + }) +}) + +const getData = code => new Promise( (resolve, reject) => { + request(`${baseURL}?base=${code}`, (err, res, body) => { + if (err) reject(new Error('invalid API call')) + return resolve(body) + }) +}) + +const printObject = data => new Promise( resolve => { + const indent = 2 + data = JSON.parse(data) + const str = JSON.stringify(data, null, indent) + console.log(str) + return resolve() +}) + +const exit = () => new Promise( () => { + process.exit() +}) + +const readObjectFromFile = fileName => new Promise( (resolve, reject) => { + fs.readFile(fileName, 'utf-8', (err, content) => { + if (err) reject(new Error(err)) + return resolve(JSON.parse(content)) + }) +}) + +getInput('enter base currency') + .then(checkValidCurrencyCode) + .then(code => this.base = code) + .then( () => getData(this.base)) + .then( body => this.rates = JSON.parse(body).rates) + .then( () => getInput('convert to')) + .then(checkValidCurrencyCode) + .then( code => this.convertTo = code) + .then( () => readObjectFromFile('currencies.json')) + .then(fileObject => this.decoder = fileObject) + .then( () => getInput('enter exchange amount')) + .then( amount => console.log(`${amount} ${this.decoder[this.base]} (${this.base}) is worth ${ + (this.rates[this.convertTo] * amount).toFixed(4)} ${this.decoder[this.convertTo]} (${this.convertTo})`)) + .then(exit) + .catch(err => console.error(`error: ${err.message}`)) + .then(exit) diff --git a/solutions/06_code_quality/todo/index.js b/solutions/06_code_quality/todo/index.js new file mode 100644 index 00000000..2c514484 --- /dev/null +++ b/solutions/06_code_quality/todo/index.js @@ -0,0 +1,80 @@ +#!/usr/bin/env node + +/** + * Server index module + * @module index + */ + +const Koa = require('koa') +const Router = require('koa-router') +const stat = require('koa-static') +const bodyParser = require('koa-bodyparser') +const handlebars = require('koa-hbs-renderer') + +const app = new Koa() +const router = new Router() +app.use(stat('public')) +app.use(bodyParser()) +app.use(handlebars({ paths: { views: `${__dirname}/views` } })) +app.use(router.routes()) + +// The through which the server will communicate +const port = 8080 + +const List = require('./modules/list').List +const list = new List() + +/** + * Get the home page + * @name Home + * @route {GET} / + */ +router.get('/', ctx => { + try { + const items = list.getAll() + console.log(items) + const data = {items} + ctx.render('home', data) + } catch(err) { + console.log(err.message) + ctx.render('home', {msg: err.message}) + } +}) + +/** + * Add an item to the list + * @name Add item + * @route {POST} / + */ +router.post('/', ctx => { + try { + const body = ctx.request.body + console.log(body) + list.add(body.item, body.qty) + ctx.redirect('/') + } catch(err) { + console.log(err.message) + ctx.redirect(`/?msg=${err.message}`) + } +}) + +/** + * Delete an item from the list + * @name Delete item + * @route {get} /delete/:key + */ +router.get('/delete/:key', ctx => { + try { + const key = ctx.params.key + console.log(`key: ${key}`) + list.delete(key) + ctx.redirect('/?msg=item deleted') + } catch(err) { + console.log(err.message) + ctx.redirect(`/${err.message}`) + } +}) + +module.exports = app.listen(port, () => { + console.log(`listening on port ${port}`) +}) diff --git a/solutions/06_code_quality/todo/list.js b/solutions/06_code_quality/todo/list.js new file mode 100644 index 00000000..33b8dc9b --- /dev/null +++ b/solutions/06_code_quality/todo/list.js @@ -0,0 +1,53 @@ + +/** + * Class representing a list of items. + * */ +class List { + + /** + * Create a list. + */ + constructor() { + this.items = [] + } + + /** + * Add an item to the list. + * @param {String} item - The name of the eitem. + * @param {Number} qty - The number of items to add. + */ + add(item, qty) { + const data = {item: item, qty: qty} + this.items.push(data) + } + + /** + * Return the list of items. + * @return {Array.<{item: String, qty: Number}>} An array containing the items. + */ + getAll() { + return this.items.map( (element, index) => ({key: index, item: element.item, qty: element.qty})) + } + + /** + * Delete an item from the list. + * @param {Number} id - The index of the deletable item + */ + delete(id) { + this.items.splice(id, 1) + } + + /** + * Return the number of items in the list + * @return {Number} The number of items in the list + */ + count() { + return this.items.count + } + +} + +// exporting the class by name adds the name to the documentation +module.exports = { + List +} From 276525ad90f0824b1384fb4ee23ec7cd9e544ff4 Mon Sep 17 00:00:00 2001 From: Balazs Bordas Date: Sun, 25 Oct 2020 20:26:32 +0100 Subject: [PATCH 70/70] sample solutions and error fixes for 07_unit_testing --- 07 Unit Testing.md | 20 +- .../07_unit_testing/database/modules/todo.js | 7 +- solutions/07_unit_testing/database/todo.js | 59 +++++ .../07_unit_testing/database/todo.spec.js | 163 ++++++++++++ solutions/07_unit_testing/todo/todo.js | 43 ++++ solutions/07_unit_testing/todo/todo.spec.js | 242 ++++++++++++++++++ 6 files changed, 521 insertions(+), 13 deletions(-) create mode 100644 solutions/07_unit_testing/database/todo.js create mode 100644 solutions/07_unit_testing/database/todo.spec.js create mode 100644 solutions/07_unit_testing/todo/todo.js create mode 100644 solutions/07_unit_testing/todo/todo.spec.js diff --git a/07 Unit Testing.md b/07 Unit Testing.md index 6242a6e7..8b2d41ba 100644 --- a/07 Unit Testing.md +++ b/07 Unit Testing.md @@ -17,7 +17,7 @@ We will be using a tool called [Jest](https://jestjs.io) which was originally de READ THE FOLLOWING CAREFULLY -**In the previous labs you have opened the `foundation` directory in VS Code and hd access to all the files and subfolders. The testing tools require you to open the folder containing the project we want to test directly so you will need to use the file menu and open the `foundation/exercises/07_unit_testing/todo/` directory.** +**In the previous labs you have opened the `foundation` directory in VS Code and had access to all the files and subfolders. The testing tools require you to open the folder containing the project we want to test directly so you will need to use the file menu and open the `foundation/exercises/07_unit_testing/todo/` directory.** The project has a number of node package dependencies which are listed in the `package.json` file. Start by installing all of these and then you should start the server and have a look at the website. As you can see it is a simple todo list, try adding a few items and deleting them, you will see that only some of the functionality has been implemented! @@ -110,7 +110,7 @@ Any code highlighted in red is not covered by your test suite. ### 1.4 Running the Tests Using Visual Studio Code -In the previous section you learned how to run a test suite and check code coverage just using the CLI (terminal) and this will work regardless of the environment you are using. In this section you will learn how to run your test suite using VS Code together with a feww useful extensions. +In the previous section you learned how to run a test suite and check code coverage just using the CLI (terminal) and this will work regardless of the environment you are using. In this section you will learn how to run your test suite using VS Code together with a few useful extensions. ### 1.5 Visual Studio Code Extensions @@ -268,11 +268,11 @@ Here is a possible solution: ```javascript module.exports.add = (item, qty) => { qty = Number(qty) - if(isNaN(qty)) throw new Error('the quantity must be a number') + if(isNaN(qty)) throw new Error('qty must be a number') let flag = false for(let index in data) { if (data[index].item === item) { - data[index].qty+= qty + data[index].qty += qty flag = true } } @@ -295,11 +295,11 @@ There is not a lot we can do to the program code: ```javascript module.exports.add = (item, qty) => { qty = Number(qty) - if(isNaN(qty)) throw new Error('the quantity must be a number') + if(isNaN(qty)) throw new Error('qty must be a number') let flag = false for(const index in data) { if (data[index].item === item) { - data[index].qty+= qty + data[index].qty += qty flag = true } } @@ -327,7 +327,7 @@ Run the test suite to check there are no errors. }) ``` -Again, check that all the test still pass. As a final check start the web server and see if it works in the browser. Congratulations, you have now completed your first TDD iteration. +Again, check that all the tests still pass. As a final check start the web server and see if it works in the browser. Congratulations, you have now completed your first TDD iteration. ### 1.8 Test Your Understanding @@ -378,7 +378,7 @@ In this version we export a NodeJS [Class](https://developer.mozilla.org/en-US/d The `unit tests/todo.js` script contains the same tests as the array-based version but each test now: -1. Uses an object constructor to get a `ToDo` object asynchronouly. +1. Uses an object constructor to get a `ToDo` object asynchronously. 2. Calls the appropriate async method(s). ### 2.2 In-Memory Databases @@ -419,10 +419,10 @@ You will now complete a few more TDD iterations: 1. What happens if you leave the item box empty? This should throw an error, not add a blank item. 2. What happens if you leave the qty box empty? Solve this in a similar way. -3. What happens if you click on one of the **Delete** links? Implement this feature. Remember that since this is testing the `delete()` function you need to create a new _test suite_ called `delete()` in the same test suite. +3. What happens if you click on one of the **Delete** links? Implement this feature. Remember that since this is testing the `delete()` function you need to create a new _test suite_ called `delete()` in the same unit test script. 4. Can you write one or more tests for the `getAll()` function? 5. And for the `clear()` function as well. As before, are you gettting 100% code coverage? If not, write more tests. Are you covering the edge cases and checking for correct handling of bad data? -Note that there appears to be a bug in the VS Code debugger when stepping through a function that returns a promise. If the debugger sends you to a script called `async_hooks.js` you can get stuck in an loop. When the debugger is highlighting the closing brace of an async function press the **Step Out** button a few times (typically) to return to the parent function. Remember you can add breakpoints to the test as well as the module code. +Note that there appears to be a bug in the VS Code debugger when stepping through a function that returns a promise. If the debugger sends you to a script called `async_hooks.js` you can get stuck in a loop. When the debugger is highlighting the closing brace of an async function press the **Step Out** button a few times (typically) to return to the parent function. Remember you can add breakpoints to the test as well as the module code. diff --git a/exercises/07_unit_testing/database/modules/todo.js b/exercises/07_unit_testing/database/modules/todo.js index 8e6309e7..3b74179d 100644 --- a/exercises/07_unit_testing/database/modules/todo.js +++ b/exercises/07_unit_testing/database/modules/todo.js @@ -17,9 +17,7 @@ module.exports = class ToDo { async add(item, qty) { qty = Number(qty) if(isNaN(qty)) throw new Error('the quantity must be a number') - let sql = 'SELECT * FROM items;' - // const dataAll = await this.db.all(sql) - sql = `SELECT * FROM items WHERE ITEM = "${item}"` + let sql = `SELECT * FROM items WHERE ITEM = "${item}"` const data = await this.db.all(sql) if(data.length === 0) { sql = `INSERT INTO items(item, qty) VALUES("${item}", ${qty})` @@ -49,4 +47,7 @@ module.exports = class ToDo { return data.items } + async clear() { + await this.db.run('DELETE FROM items') + } } diff --git a/solutions/07_unit_testing/database/todo.js b/solutions/07_unit_testing/database/todo.js new file mode 100644 index 00000000..106f408d --- /dev/null +++ b/solutions/07_unit_testing/database/todo.js @@ -0,0 +1,59 @@ + +'use strict' + +const sqlite = require('sqlite-async') + +module.exports = class ToDo { + + constructor(dbName = ':memory:') { + return (async() => { + this.db = await sqlite.open(dbName) + const sql = 'CREATE TABLE IF NOT EXISTS items(id INTEGER PRIMARY KEY AUTOINCREMENT, item TEXT, qty NUMERIC)' + await this.db.run(sql) + return this + })() + } + + async add(item, qty) { + if (item === '') throw new Error('item cannot be empty') + if (qty === '') throw new Error('qty cannot be empty') + qty = Number(qty) + if(isNaN(qty)) throw new Error('the quantity must be a number') + let sql = `SELECT * FROM items WHERE ITEM = "${item}"` + const data = await this.db.all(sql) + if(data.length === 0) { + sql = `INSERT INTO items(item, qty) VALUES("${item}", ${qty})` + await this.db.run(sql) + } else { + const newQty = data[0].qty + qty + sql = `UPDATE items SET qty=${newQty} WHERE ITEM = "${item}"` + await this.db.run(sql) + } + } + + async getAll() { + const sql = 'SELECT * FROM items' + const data = await this.db.all(sql) + console.log(data) + return data + } + + async delete(id) { + if (id === undefined) throw new Error('id cannot be undefined') + id = Number(id) + if (isNaN(id)) throw new Error('id must be a number') + const sql = `DELETE FROM items WHERE id=${id}` + if ((await this.db.run(sql)).changes === 0) throw new Error('id has to exist') + } + + async countItems() { + const sql = 'SELECT COUNT(*) as items FROM items' + const data = await this.db.get(sql) + return data.items + } + + async clear() { + await this.db.run('DELETE FROM items') + } + +} diff --git a/solutions/07_unit_testing/database/todo.spec.js b/solutions/07_unit_testing/database/todo.spec.js new file mode 100644 index 00000000..7a3663af --- /dev/null +++ b/solutions/07_unit_testing/database/todo.spec.js @@ -0,0 +1,163 @@ + +'use strict' + +const ToDo = require('../modules/todo.js') + +beforeAll( async() => { + // stuff to do before any of the tests run +}) + +afterAll( async() => { + // runs after all the tests have completed +}) + +describe('add()', () => { + // block of tests + // beforeEach( async() => { + // todo.clear() + // }) + afterEach( async() => { + // runs after each test completes + }) + test('add a single item', async done => { + expect.assertions(1) + // ARRANGE + const todo = await new ToDo() // DB runs in-memory if no name supplied + // ACT + await todo.add('bread', 3) + const count = await todo.countItems() + // ASSERT + expect(count).toBe(1) + done() + }) + + test('qty must be a number', async done => { + expect.assertions(1) + const todo = await new ToDo() + await expect( todo.add('bread', 'three') ).rejects.toEqual( Error('the quantity must be a number') ) + done() + }) + + test('duplicates should increase qty', async done => { + expect.assertions(2) + // ARRANGE + const todo = await new ToDo() + // ACT + await todo.add('bread', 4) + await todo.add('bread', 2) + const data = await todo.getAll() + const qty = data[0].qty + // ASSERT (note there are two assertions as stated on line 42) + expect(data).toHaveLength(1) + expect(qty).toEqual(6) + done() + }) + + test('item cannot be empty', async done => { + expect.assertions(1) + const todo = await new ToDo() + await expect( todo.add('', 1) ).rejects.toEqual( Error('item cannot be empty') ) + done() + }) + + test('qty cannot be empty', async done => { + expect.assertions(1) + const todo = await new ToDo() + await expect( todo.add('bread', '') ).rejects.toEqual( Error('qty cannot be empty') ) + done() + }) + +}) + +describe('delete()', () => { + beforeEach( async() => { + this.todo = await new ToDo() + await this.todo.add('bread', 5) + }) + + test('id cannot be undefined', async done => { + expect.assertions(1) + await expect( this.todo.delete() ).rejects.toEqual( Error('id cannot be undefined') ) + done() + }) + + test('id must be a number', async done => { + expect.assertions(1) + await expect( this.todo.delete('a') ).rejects.toEqual( Error('id must be a number') ) + done() + }) + + test('id has to exist', async done => { + expect.assertions(1) + await expect( this.todo.delete(2) ).rejects.toEqual( Error('id has to exist') ) + done() + }) + + test('delete an item', async done => { + expect.assertions(2) + await this.todo.delete(1) + expect(await this.todo.countItems()).toEqual(0) + expect(await this.todo.getAll()).toEqual([]) + done() + }) +}) + +describe('getAll()', () => { + beforeEach( async() => { + this.todo = await new ToDo() + }) + + test('getAll() with no items', async done => { + expect.assertions(1) + expect(await this.todo.getAll()).toEqual([]) + done() + }) + + test('getAll() with a single item', async done => { + expect.assertions(1) + await this.todo.add('bread', 2) + expect(await this.todo.getAll()).toEqual([{"item":"bread", "qty":2, "id":1}]) + done() + }) + + test('getAll() with two items', async done => { + expect.assertions(1) + await this.todo.add('bread', 2) + await this.todo.add('ham', 3) + expect(await this.todo.getAll()).toEqual([{"item":"bread", "qty":2, "id":1}, {"item":"ham", "qty":3, "id":2}]) + done() + }) +}) + +describe('clear()', () => { + beforeEach( async() => { + this.todo = await new ToDo() + }) + + test('clear() with no items', async done => { + expect.assertions(2) + await this.todo.clear() + expect(await this.todo.countItems()).toEqual(0) + expect(await this.todo.getAll()).toEqual([]) + done() + }) + + test('clear() with a single item', async done => { + expect.assertions(2) + await this.todo.add('bread', 2) + await this.todo.clear() + expect(await this.todo.countItems()).toEqual(0) + expect(await this.todo.getAll()).toEqual([]) + done() + }) + + test('clear() with two items', async done => { + expect.assertions(2) + await this.todo.add('bread', 2) + await this.todo.add('ham', 3) + await this.todo.clear() + expect(await this.todo.countItems()).toEqual(0) + expect(await this.todo.getAll()).toEqual([]) + done() + }) +}) diff --git a/solutions/07_unit_testing/todo/todo.js b/solutions/07_unit_testing/todo/todo.js new file mode 100644 index 00000000..844c2a62 --- /dev/null +++ b/solutions/07_unit_testing/todo/todo.js @@ -0,0 +1,43 @@ + +'use strict' + +let data = [] + +module.exports.clear = () => { + data = [] +} + +module.exports.add = (item, qty) => { + if (item === '') throw new Error('item cannot be empty') + if (qty === '') throw new Error('qty cannot be empty') + qty = Number(qty) + if(isNaN(qty)) throw new Error('qty must be a number') + let flag = false + for(const index in data) { + if (data[index].item === item) { + data[index].qty += qty + flag = true + } + } + if(flag === false) data.push({item: item, qty: qty}) +} + +module.exports.getAll = () => { + for(const key in data) data[key].key = Number(key) + return data +} + +module.exports.delete = key => { + console.log(`delete key ${key}`) + if (key === undefined) throw new Error('key cannot be undefined') + key = Number(key) + if (isNaN(key)) throw new Error('key must be a number') + try { + this.getAll()[key].key // throws error unless the item with the target key exists + data.splice(key, 1) + } catch { + throw new Error('key has to exist') + } +} + +module.exports.countItems = () => data.length diff --git a/solutions/07_unit_testing/todo/todo.spec.js b/solutions/07_unit_testing/todo/todo.spec.js new file mode 100644 index 00000000..a0bdc7d4 --- /dev/null +++ b/solutions/07_unit_testing/todo/todo.spec.js @@ -0,0 +1,242 @@ + +'use strict' + +const todo = require('../modules/todo.js') + +beforeAll( async() => { + // stuff to do before any of the tests run +}) + +afterAll( async() => { + // runs after all the tests have completed +}) + +describe('add()', () => { + // block of tests + beforeEach( async() => { + todo.clear() + }) + afterEach( async() => { + // runs after each test completes + }) + test('add a single item', async done => { + expect.assertions(1) + try { + todo.add('bread', 3) + expect(todo.countItems()).toBe(1) + } catch(err) { + done.fail(err) + } finally { + done() + } + }) + test('qty must be a number', async done => { + expect.assertions(1) + try { + todo.add('bread', 'three') + done.fail('test failed') + } catch(err) { + expect(err.message).toBe('qty must be a number') + } finally { + done() + } + }) + + test('duplicates should increase qty', async done => { + expect.assertions(2) + try { + // ACT + todo.add('bread', 4) + todo.add('bread', 2) + // ASSERT + const count = todo.countItems() + expect(count).toBe(1) + const data = todo.getAll() + const qty = data[0].qty + expect(qty).toEqual(6) + } catch(err) { + done.fail('test failed') + } finally { + done() + } + }) + + test('item cannot be empty', async done => { + expect.assertions(1) + try { + todo.add('', 1) + done.fail('test failed') + } catch(err) { + expect(err.message).toBe('item cannot be empty') + } finally { + done() + } + }) + + test('qty cannot be empty', async done => { + expect.assertions(1) + try { + todo.add('bread', '') + done.fail('test failed') + } catch(err) { + expect(err.message).toBe('qty cannot be empty') + } finally { + done() + } + }) +}) + +describe('delete()', () => { + beforeEach( async() => { + todo.clear() + todo.add('bread', 2) + }) + afterEach( async() => { + }) + + test('key cannot be undefined', async done => { + expect.assertions(1) + try { + todo.delete() + done.fail('test failed') + } catch(err) { + expect(err.message).toBe('key cannot be undefined') + } finally { + done() + } + }) + + test('key must be a number', async done => { + expect.assertions(1) + try { + todo.delete('a') + done.fail('test failed') + } catch(err) { + expect(err.message).toBe('key must be a number') + } finally { + done() + } + }) + + test('key has to exist', async done => { + expect.assertions(1) + try { + todo.delete(1) + done.fail('test failed') + } catch(err) { + expect(err.message).toBe('key has to exist') + } finally { + done() + } + }) + + test('delete an item', async done => { + expect.assertions(1) + try { + todo.delete(0) + expect(todo.getAll()).toEqual([]) + } catch(err) { + done.fail('test failed') + console.log(err) + } finally { + done() + } + }) +}) + +describe('getAll()', () => { + beforeEach( async() => { + todo.clear() + }) + afterEach( async() => { + }) + + test('getAll() with no items', async done => { + expect.assertions(1) + try { + expect(todo.getAll()).toEqual([]) + } catch(err) { + done.fail('test failed') + console.log(err) + } finally { + done() + } + }) + + test('getAll() with a single item', async done => { + expect.assertions(1) + try { + todo.add('bread', 2) + expect(todo.getAll()).toEqual([{"item":"bread", "qty":2, "key":0}]) + } catch(err) { + done.fail('test failed') + console.log(err) + } finally { + done() + } + }) + + test('getAll() with two items', async done => { + expect.assertions(1) + try { + todo.add('bread', 2) + todo.add('ham', 3) + expect(todo.getAll()).toEqual([{"item":"bread", "qty":2, "key":0}, {"item":"ham", "qty":3, "key":1}]) + } catch(err) { + done.fail('test failed') + console.log(err) + } finally { + done() + } + }) +}) + +describe('clear()', () => { + beforeEach( async() => { + todo.clear() + }) + afterEach( async() => { + }) + + test('clear() with no items', async done => { + expect.assertions(1) + try { + todo.clear() + expect(todo.getAll()).toEqual([]) + } catch(err) { + done.fail('test failed') + console.log(err) + } finally { + done() + } + }) + + test('clear() with 1 item', async done => { + expect.assertions(1) + try { + todo.add('bread', 2) + todo.clear() + expect(todo.getAll()).toEqual([]) + } catch(err) { + done.fail('test failed') + console.log(err) + } finally { + done() + } + }) + + test('clear() with 2 items', async done => { + expect.assertions(1) + try { + todo.add('bread', 2) + todo.add('ham', 3) + todo.clear() + expect(todo.getAll()).toEqual([]) + } catch(err) { + done.fail('test failed') + console.log(err) + } finally { + done() + } + }) +})
RAM
@@ -92,7 +92,7 @@ Every resource on the WWW (such as html documents and images) has a unique URL a 1. Some resources need to be directly accessible in the web browser (they are accessed either directly or loaded by the html web page). These need to have their own directly accessible URL. 1. One directory needs to be specified as being publicly available. In this example we have created a directory called `public/` 2. Koa needs to make this directory public. This is achieved on line by importing a static module and using this to specify the public directory. - 3. assuming the server is running you can directly view the image using the URL `http://xxx:8080/paradox.jpeg`, remembering to substitute your server's URL. + 3. Assuming the server is running you can directly view the image using the URL `http://localhost:8080/paradox.jpeg`, remembering to substitute your server's URL. 2. Some resources are _virtual_ and are generated by a script running on the server before being sent back to the browser client. 1. There are some simple examples in `index.js`. Both the `/` and `/paradoxes` routes trigger scripts that take the contents of html files and send this back to the browser. 2. When you access the `/date` route it displays today's date. Look at the script that does this (you don't need to understand the code details). @@ -100,7 +100,7 @@ Every resource on the WWW (such as html documents and images) has a unique URL a #### 3.1.1 Test Your Knowledge 1. There is a file called `coventry_cathedral.jpg` in the `public/` directory. Display this in the browser. -2. Create a route called `/cathedral` which should return the contents of the `cathedral.html` file located in the `html/` directory. +2. Create a route called `/cathedral` which should return the contents of the `cathedral.html` file located in the `views/` directory. 3. Create a route called `/time` that displays the current time in hours and minutes. There is detailed documentation on the [Date](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date) function on the Mozilla website. ### 3.2 Hyperlinks @@ -115,23 +115,21 @@ Add a link to the appropriate Wikipedia article to this web page, in a suitable To test the functionality in your browser you will need to make sure the server is running and navigate to the correct URL. -A link, defined by the `a` element contains the URL of the linked web page as its `href` attribute. The link above contains an absolute path to a document on the external server. The absolute path begins will full protocol identifier and domain name. +A link, defined by the `a` element contains the URL of the linked web page as its `href` attribute. The link above contains an absolute path to a document on the external server. The absolute path begins with full protocol identifier and domain name. Unlike block elements (such as `h1` or `p`), links are inline elements: they always need a block element as a container and they are considered as a running part of the content of the parent block element. -A relative link is intended for links within the same domain. The parsing of the file path starts from the default directory, which is the directory where the containing HTML document is located. For instance: +A relative link is intended for links within the same domain. The parsing of the file path starts from the default directory, which is the directory where the containing HTML document is located, or as it is in this case, the directory specified with `koa-static`, which is `public/`. For instance: - `"document.html"` points to a document of that name in the default directory. - `"info/document.html"` points to a document in `info` subdirectory of the default directory. - `"../document.html"` points to a document in the parent directory of the default directory. (Note that, for security reasons, web servers prohibit the traversal of server's directory structure outside the dedicated document root folder.) -Add a link or two to suitable places in **computers80.html**. - ### Test your understanding -1. Create a relative link between the list item on the home page and the page on the Commodore 64. -2. Add a link at the bottom of the Commodore 64 page called **Back** which returns the user to the home page. -3. Create a file called **spectrum.html** in the `html/` directory with the content shown below correctly marked up as HTML 5. +1. Create a relative link between the list item on the home page and the page on the `Commodore 64`. +2. Add a link at the bottom of the `Commodore 64` page called **Back** which returns the user to the home page. +3. Create a file called **spectrum.html** in the `views/` directory with the content shown below correctly marked up as HTML 5. 4. Create a new `/spectrum` route in the `index.js`. 5. Add new link to the list on the home page to send the user to this new page. 6. Make sure there is a link on the Spectrum page to return the user to the home page! @@ -184,7 +182,7 @@ There are a couple of notable things about the `img` element: | Attribute | Purpose | |-----------|---------------------------------------------------------------------------------------------------------------------------------------------| -| src | For locating the image file. The file path is normally given as relative path, starting from the directory where the HTML file is located. | +| src | For locating the image file. The file path is normally given as relative path, starting from the default directory. | | alt | For displaying an alternative text if the image cannot be displayed, or if the user prefers using a screen reader for accessibility purposes. | #### 3.3.1 Test Your Understanding @@ -206,7 +204,7 @@ Now we will learn how to embed audio in a website. There are a number of resourc 2. In a similar way, video can also be embedded: 1. Most browsers require a video file encoded as `.mp4`. 2. Firefox needs an `.ogg` encoded version. -3. You can also embed a [YouTube](https://www.youtube.com) video in an ` +

Embedded youtube video via object

+ + + \ No newline at end of file diff --git a/solutions/03_html/03_hypermedia/views/spectrum.html b/solutions/03_html/03_hypermedia/views/spectrum.html new file mode 100644 index 00000000..22b82ba0 --- /dev/null +++ b/solutions/03_html/03_hypermedia/views/spectrum.html @@ -0,0 +1,66 @@ + + + + + Sinclair ZX Spectrum + + + +

Sinclair ZX Spectrum

+
+ A Sinclair ZX Spectrum computer +
Photo: Bill Bertram, CC via https://commons.wikimedia.org/
+
+
+ + \ No newline at end of file diff --git a/solutions/03_html/04_tables/comparison.html b/solutions/03_html/04_tables/comparison.html new file mode 100644 index 00000000..b512bad0 --- /dev/null +++ b/solutions/03_html/04_tables/comparison.html @@ -0,0 +1,62 @@ + + + + + Comparison of three computers + + + + +

A comparison of technical data of three popular 80's home computers:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Technical comparison
PropertyCommodore 64ZX SpectrumCommodore VIC-20Spectravideo SV-328
CPUMOS Technology 6510Zilog Z80MOS Technology 6502Zilog Z80A
RAM64 kilobytes16 or 64 kilobytes5 kilobytes64 kilobytes
ROM20 kilobytes16 kilobytes16 kilobytes32 kilobytes
Main usagehome computing
Killer gameJet Set WillyJelly MonstersArmoured Assault
+ +
+ + + + \ No newline at end of file diff --git a/solutions/03_html/05_semantic/cafe.html b/solutions/03_html/05_semantic/cafe.html new file mode 100644 index 00000000..05a525ab --- /dev/null +++ b/solutions/03_html/05_semantic/cafe.html @@ -0,0 +1,43 @@ + + + + + + The Java Bakery Cafe + + + + + Logo of Java Bakery Cafe + +

Welcome to the Java Bakery Cafe

+ +

+ The Java Cafe is passionate in providing quality home-baked goods, deliciously innovative + classic dishes and excellent beverages that evoke the atmosphere of the 1990s. +

+ +

+ Our cafés in Coventry and Cupertino aim to provide a wonderful place to relax, socialise, work, + hold meetings and above all enjoy exceptional-quality food and drinks at an unbeatable price. +

+ +

Payment in GBP only.

+ +

Price range: $$

+ +

Hours: Mo-Fri 10am-7pm Sa 10am-22pm Su 10am-21pm

+ +

Payment accepted: Cash, Credit Card

+ +

Priory Street, Coventry, CV1 5FB

+ +

Tourist Board 4 star rating

+ +

Serves Lavazza coffee

+ +

javacafe@example.com

+ +

Tel: 024 7655 5555

+ + diff --git a/solutions/03_html/06_markdown/computers.md b/solutions/03_html/06_markdown/computers.md new file mode 100644 index 00000000..60eeef7c --- /dev/null +++ b/solutions/03_html/06_markdown/computers.md @@ -0,0 +1,41 @@ + +# 80s Computers + +Here is a list of the best computers from the 1980s. + +1. Sinclair ZX80 +1. Commodore 64 +1. ZX Spectrum +1. Compaq Portable + +| Computer | Year | +| --------------- | ----: | +| Sinclair ZX80 | 1980 | +| Commodore64 | 1982 | +| ZX Spectrum | 1982 | +| Compaq Portable | 1982 | + +## Hardware +- Sinclair + - Z80 @ 3.25 MHz + - 1 KB (16 KB max.) +- Commodore 64 + - MOS Technology 6510/8500 + - MOS Technology VIC-II + - MOS Technology 6581/8580 SID + - Two 6526 Complex Interface Adapters + - 64 KB RAM + - 20 KB ROM +- ZX Spectrum + - Z80A @ 3.5 MHz + - 16 KB / 48 KB / 128 KB +- Compaq Portable + - Intel 8088, 4.77MHz + - 128 kilobytes RAM (expandable to 640 KiB) + +## Software +- Microsoft Word +- Pac-man +- Lotus 1-2-3 +- HyperCard +- Adobe Photoshop From c2c0cc96a7bcb7e87424ef863872cd2f604cd177 Mon Sep 17 00:00:00 2001 From: Balazs Bordas Date: Mon, 14 Sep 2020 20:34:49 +0200 Subject: [PATCH 66/70] fixed minor errors --- 01 Setup.md | 51 +++++++++++++++---------------- 02 HTTP.md | 32 +++++++++---------- 03 HTML5.md | 20 ++++++------ exercises/02_http/01_url/index.js | 4 +-- solutions/02_http/01_url/index.js | 6 ++-- 5 files changed, 54 insertions(+), 59 deletions(-) diff --git a/01 Setup.md b/01 Setup.md index 065039bd..3bd171e2 100644 --- a/01 Setup.md +++ b/01 Setup.md @@ -143,35 +143,32 @@ Now we have the server up and running so the final task is to view the web page ## 5 Using npm and its package.json -**Have a look at your `package.json` file and understand its contents** +**Have a look at your `package.json` file and understand its contents**. - When you are starting a new _project_, **you have to create this yourself**: - 1. Use the `npm init` command to create the package.json file - - You can leave all the options default, just leave them empty and keep pressing enter - - Alternatively you can run `npm init --yes`, it will simply leave everything default - 2. Install the dependencies for the first time using the `-S` _switch_ with `npm install` - - e.g.: `npm install -S koa koa-bodyparser` - - This would add something like this to the `package.json` file: - ```json - "dependencies": { - "koa": "^2.11.0", - "koa-bodyparser": "^4.2.1" - } - ``` - - When you next run `npm install -S `, the given package's _newest version_ will be simply added to the list, or in case of a new version for a _previously listed_ dependency, the _version number_ will be updated - - This `-S` is just a short version of the `--save` _switch_ - - **You can use the alternative `--save-dev` switch to install and save them as _development dependencies_** - - Something that you wouldn't want to deploy, but is necessary for development - - E.g. we will use `jest` for testing, and `eslint` for linting during the development phase, but these shouldn't be required to be installed during deployment - - You are done with adding the dependencies, now simply use `npm install` to install all of them at once! - - If you don't want to install development dependencies, use `npm install --production` - 3. This `package.json` file is also useful to store _scripts_: - - Look at the following line: ` "start": "nodemon index.js"` - - This lets us simply type `npm start` in the terminal to start our application via _nodemon_ - - Nodemon is a great tool that restarts the application every time we save a file in the given folder, so we don't actually have to manually stop and restart it after every modification. - - - +1. Use the `npm init` command to create the package.json file + - You can leave all the options default, just leave them empty and keep pressing enter + - Alternatively you can run `npm init --yes`, it will simply leave everything default +2. Install the dependencies for the first time using the `-S` _switch_ with `npm install` + - e.g.: `npm install -S koa koa-bodyparser` + - This would add something like this to the `package.json` file: + ```json + "dependencies": { + "koa": "^2.11.0", + "koa-bodyparser": "^4.2.1" + } + ``` + - When you next run `npm install -S `, the given package's _newest version_ will be simply added to the list, or in case of a new version for a _previously listed_ dependency, the _version number_ will be updated + - This `-S` is just a short version of the `--save` _switch_ + - **You can use the alternative `--save-dev` switch to install and save them as _development dependencies_** + - Something that you wouldn't want to deploy, but is necessary for development + - E.g. we will use `jest` for testing, and `eslint` for linting during the development phase, but these shouldn't be required to be installed during deployment + - You are done with adding the dependencies, now simply use `npm install` to install all of them at once! + - If you don't want to install development dependencies, use `npm install --production` +3. This `package.json` file is also useful to store _scripts_: + - Look at the following line: ` "start": "nodemon index.js"` + - This lets us simply type `npm start` in the terminal to start our application via _nodemon_ + - Nodemon is a great tool that restarts the application every time we save a file in the given folder, so we don't actually have to manually stop and restart it after every modification. ## 6 Pushing the Changes to GitHub diff --git a/02 HTTP.md b/02 HTTP.md index 39e3792d..d1817184 100644 --- a/02 HTTP.md +++ b/02 HTTP.md @@ -53,7 +53,7 @@ Study the `index.js` script in the `exercises/02_http/01_url/` directory. 3. `koa-bodyparser` 4. `koa-static` 5. `js2xmlparser` - - **You can install all these dependencies by simply running 'npm install' in the terminal.** + - **You can install all these dependencies by simply running `npm install` in the terminal.** - This command installs all the documented dependencies from the `package.json` file, which is already preconfigured in this case. - Refer to the `01_Setup.md` document's `Using npm and its package.json` chapter for more information @@ -66,7 +66,7 @@ Study the `index.js` script in the `exercises/02_http/01_url/` directory. 6. The main part of the script defines the _routes_ and we will be covering these in more detail as we progress through the lab. 7. Right at the end (line 138) we start the server on the defined port and _export_ the _koa object_ `app`. By exporting it we can import the script into our automated test suite (briefly covered in the previous lab). -Now start the server: +Now start the server by typing `npm start` into the terminal while in the correct directory and hitting enter: 1. Access the root url, notice that the message **Hello World** is displayed in the browser. 2. Access the `/anon` url. This should result in the same message being displayed. @@ -74,7 +74,7 @@ Now start the server: ### 1.2 URL Parameters -In the HTTP protocol URLs represent resources on the server. Up to this point each URL has matched a different _route_ (defined by an `router.get()` function) but on a real server there might be a database containing many thousands of records that we want to be able to access. For this to work, each record would need a different, unique, URL! Since each record in an SQL database has a unique key (primary key), a simple solution would be to include the primary key in the URL thus creating a different URL for each record. +In the HTTP protocol URLs represent resources on the server. Up to this point each URL has matched a different _route_ (defined by a `router.get()` function), but on a real server there might be a database containing many thousands of records that we want to be able to access. For this to work, each record would need a different, unique, URL! Since each record in an SQL database has a unique key (primary key), a simple solution would be to include the primary key in the URL thus creating a different URL for each record. To do this we need to extract some data from the http object `ctx` which is the parameter passed to the _anonymous callback function_. The `ctx` object is a _JavaScript Object_ and so we need to fully understand how these work. @@ -117,8 +117,8 @@ Each value in an object can be extracted using one or two different syntaxes: ```javascript const firstName = name.first const lastName = name['last name'] -const prop = year -const dobYear = name.dob.[prop] +const prop = 'year' +const dobYear = name.dob[prop] ``` New properties can be added and removed from an object. @@ -136,11 +136,11 @@ In this section you will learn about a number of JavaScript functions. In each c 1. Add a fourth book to the array and make sure you can access this by passing its index in the URL. 2. We are not restricted to only having two URL segments: 1. Modify the route to add a second parameter called `index2`. - 2. Make sure this is triggered by restarting the server and accessing this by passing a second parameter. + 2. Make sure this is triggered by restarting the server (which should happen automatically if you used `npm start`, which uses `nodemon`) and accessing this by passing a second parameter. 3. Modify the script to print out both book titles. 3. Next you need to add some validation to make sure the script does not crash (note that if you are using GoormIDE you will not be able to test it): 1. If the index in the URL exceeds the number of books in the array, you get an error. Insert an [`if...else` statement](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/if...else) that sends a suitable message to the browser if the index number in the URL is too high. - 2. The index must be a number. Use the [`isNaN()` function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isNaN) to check and send a suitable message to the browser if it is not. if it is, use the [`parseFloat()` function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseFloat) to convert it to a number. + 2. The index must be a number. Use the [`isNaN()` function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isNaN) to check and send a suitable message to the browser if it is not. If it is, use the [`parseFloat()` function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseFloat) to convert it to a number. 3. The number needs to be a whole number (integer). All JavaScript numbers are objects and have a number of useful functions. Use the [`Number.isInteger()` function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/isInteger) to check it is indeed an integer. Send a suitable message to the browser if it is not. You can convert it to an integer using the [`parseInt()` function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt). ### 1.3 URL Query Strings @@ -148,7 +148,7 @@ In this section you will learn about a number of JavaScript functions. In each c Whilst URL parameters are used to define unique URLs to identify online resources, sometimes we want to be able to pass additional information and this is done through the use of **query strings**. 1. Restart the server and access the `/hello/John%20Doe` route. - 1. Since spaces are not permitted in a URL we have to replace spaces with special codes. This is known as **URL Encoding** and there are specific [codes](https://www.degraeve.com/reference/urlencoding.php) to use. + 1. Since spaces are not permitted in a URL we have to replace spaces with special codes. This is known as **URL Encoding** and there are specific [codes](https://www.degraeve.com/reference/urlencoding.php) to use; however, your browser will probably do this automatically. 2. Notice that the message `hello John Doe` is displayed in the browser. 2. Now change the URL to `/hello/John%20Doe?format=upper`. 1. Notice that the same data has been displayed just the format has changed. @@ -179,7 +179,7 @@ Headers allow for additional information to be passed: Make sure the server is still running and use the [Chrome web browser](https://www.google.com/chrome/) to access the root URL `/`. -1. Open the [Chrome Developer Tools](https://developers.google.com/web/tools/chrome-devtools/) by clicking on the _Customise and control Chrome_ button (the three dots to the extreme right of the address bar), choosing **More tools** from the menu and then **Developer tools** from the submenu. +1. Open the [Chrome Developer Tools](https://developers.google.com/web/tools/chrome-devtools/) by pressing `ctrl+shift+i` or by clicking on the _Customise and control Chrome_ button (the three dots to the extreme right of the address bar), choosing **More tools** from the menu and then **Developer tools** from the submenu. 2. Locate the **Network** tab in the Chrome developer tools. 3. Reload the web page. (Press F5) 4. You should now see the resource sent in the HTTP response together with some data dealing with response times. @@ -201,7 +201,7 @@ In the **Request Headers** note that: 2. Next it specifies the host the request is being sent to. 3. Then there are multiple request headers. These are always property-value pairs. Lets look at a few of the more interesting ones: 1. The `User-Agent` header sends information about the browser being used. - 2. The `Accepts` header tells the server what [MIME](https://goo.gl/W2SWtZ) data types our browser prefers. + 2. The `Accepts` header tells the server what [MIME data types](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types) our browser prefers. In addition to the **Response Body** (the information in the web browser window), the server has returned a **Status Code** (in this case it is `200` meaning `OK`) plus a set of **Response Headers** that provide additional information. @@ -215,14 +215,12 @@ As part of the worksheets you will be given some exercises to carry out to make 1. Go to the [University website](http://www.coventry.ac.uk) and use the Chrome Developer Tools to examine the request and response headers. 1. Are there any headers that were missing from the example above? - 2. [Look up](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers) the meaning of all the headers. + 2. Look up the meaning of all the [headers](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers). ## 2 Using the POST Method Now we have a good understanding of the request-response process used by the HTTP protocol and have learned about the headers we will extend this by examining the use of the HTTP POST method. -Before completing this section in the lab sheet you will need to install the `koa-static` package. - 1. Start by accessing the list of names on the `/names` url Make sure you have the Chrome Developer Tools open on the Network tab.: 1. Notice the browser displays an error message. 2. If you look at the HTTP Status Code you will see it is `404 Not Found` which makes sense as there are no names in the list (yet) @@ -231,12 +229,12 @@ Before completing this section in the lab sheet you will need to install the `ko 1. Notice that the Request Method has changed to `POST`. 2. Notice that the Response Code is `201 Created` to indicate that your data has been uploaded and stored. 3. There is a section called **Form Data** which is the request body and contains the data you submitted using the form. Use the _View Source_ link to display the raw data. This is how your data is sent to the server. -4. Use the back button to return to the form and use this to add the names of everyone else on your table. +4. Use the back button to return to the form and use this to add the names of everyone else at your table. 5. Access the `/names` url which should now respond with the HTTP Status Code `200 OK` and display your names in an HTML table. ## 3 Meta-Data -The path in the Uniform Resource Locator (URL) represents a _resource_ on the server however sometimes you need to pass _metadata_ to tell the server what you want it to do with this resource. There are two ways to pass metadata in an HTTP request, query strings and request headers. They differ in that anything in the URL is part of a book mark whilst the request headers are not. You need to decide whether this is important before deciding which to use. +The path in the Uniform Resource Locator (URL) represents a _resource_ on the server; however, sometimes you need to pass _metadata_ to tell the server what you want it to do with this resource. There are two ways to pass metadata in an HTTP request, query strings and request headers. They differ in that anything in the URL is part of a bookmark whilst the request headers are not. You need to decide whether this is important before deciding which to use. ### 3.1 Query Strings @@ -262,7 +260,7 @@ To complete this section of the lab you need to install the [Modify Headers](htt ![editing the request headers](exercises/.images/chrome_05.png) -You can also modify the standard request headers. In this example we will change the `Accept` header which defines the prefered format of the response data. The data formats are defined as [MIME types](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types) The default settings look something like: +You can also modify the standard request headers. In this example we will change the `Accept` header which defines the prefered format of the response data. The data formats are defined as [MIME types](https://developer.mozilla.org/en-US/docs/Web/HTTP/Basics_of_HTTP/MIME_types). The default settings look something like: ``` text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8 @@ -271,7 +269,7 @@ text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*; This specified that the browser would prefer data in HTML/XML format (0.9 weighting) but will accept certain image formats and everything else. We will be changing this to request our data in specific formats. 1. Still on the `/names` URL, modify the request headers by removing any search terms. -2. Add a custom `Accept` header which will modify the default and set its value to `text/html` (see the screenshot below). If you refresh the browser you will see that the data is still displayed in an HTML table (because this format has been provided by the server). +2. Add a custom `Accept` header which will modify the default and set its value to `text/html` (see the screenshot below). If you refresh the browser you will see that the data is still displayed in an HTML table (because this format was used previously as well). 3. Now try the following MIME types: 1. `application/json` 2. `application/xml` diff --git a/03 HTML5.md b/03 HTML5.md index ce5419c8..15f2d85f 100644 --- a/03 HTML5.md +++ b/03 HTML5.md @@ -18,7 +18,7 @@ In this worksheet you will be learning about the markup language HTML which is c ## 1 Syntax -Lets take a look at some basic HTML syntax. Start by locating the `exercises/03_html/01_syntax/` directory. Navigate to this using the SSH Terminal, install the all the necessary `koa` packages and start the web server. If you navigate to the base route `/` you will see a screen full of text. +Lets take a look at some basic HTML syntax. Start by locating the `exercises/03_html/01_syntax/` directory. Navigate here using the terminal, install all the necessary `koa` packages with `npm install` and start the web server with `node index.js`. If you navigate to the base route `/`, you will see a screen full of text. ![the unformatted text](exercises/.images/chrome_07.png) @@ -35,7 +35,7 @@ As you work, save the html file and refresh the browser, you don't need to resta ## 2 Lists -Now you have mastered the basics of html its time to move on to how it can be used to render lists of different types. Start by locating the files in the `exercises/02_html/02_lists/` directory. Now install the necessary packages, start the `koa` server and view the root URL `/`. This should display a simple page with the title **1980's Home Computers**. +Now that you have mastered the basics of HTML, it's time to move on to how it can be used to render lists of different types. Start by locating the files in the `exercises/02_html/02_lists/` directory. Now install the necessary packages, start the `koa` server and view the root URL `/`. This should display a simple page with the title **1980s' Home Computers**. Now, add a list on your web page. Insert the following lines of code after the paragraph describing clever uses for home computers: @@ -83,7 +83,7 @@ The definitions list contains two elements for each item: a `dt` for the term an ## 3 Hypermedia -Now you have mastered the basics of HTML markup we will look at one of the most important features, the ability to link resources together (known as **hypermedia**), this is one of the cornerstones of the World Wide Web (WWW). +Now that you have mastered the basics of HTML markup, we will look at one of the most important features, the ability to link resources together (known as **hypermedia**), this is one of the cornerstones of the World Wide Web (WWW). ### 3.1 Routes @@ -91,11 +91,11 @@ Every resource on the WWW (such as html documents and images) has a unique URL a 1. Some resources need to be directly accessible in the web browser (they are accessed either directly or loaded by the html web page). These need to have their own directly accessible URL. 1. One directory needs to be specified as being publicly available. In this example we have created a directory called `public/` - 2. Koa needs to make this directory public. This is achieved on line by importing a static module and using this to specify the public directory. + 2. Koa needs to make this directory public. This is achieved on line 8 by importing a static module and using this to specify the public directory. 3. Assuming the server is running you can directly view the image using the URL `http://localhost:8080/paradox.jpeg`, remembering to substitute your server's URL. 2. Some resources are _virtual_ and are generated by a script running on the server before being sent back to the browser client. 1. There are some simple examples in `index.js`. Both the `/` and `/paradoxes` routes trigger scripts that take the contents of html files and send this back to the browser. - 2. When you access the `/date` route it displays today's date. Look at the script that does this (you don't need to understand the code details). + 2. When you access the `/date` route it, displays today's date. Look at the script that does this (you don't need to understand the code details). #### 3.1.1 Test Your Knowledge @@ -154,7 +154,7 @@ Sinclair ZX Spectrum ### 3.3 Images -In HTML5, images are put inside a `figure` element. The `figure` element normally contains one image, possibly with a caption, but technically it can serve as a container for multiple images. because the images are loaded by the HTML web page (and not directly by the web server) they need to be in a publicly accessible directory. On our web server this has been defined as the `public/` directory. You should create subdirectories within this to organise your files. +In HTML5, images are put inside a `figure` element. The `figure` element normally contains one image, possibly with a caption, but technically it can serve as a container for multiple images. Because the images are loaded by the HTML web page (and not directly by the web server) they need to be in a publicly accessible directory. On our web server this has been defined as the `public/` directory. You should create subdirectories within this to organise your files. Locate the `03_hypermedia/public/` directory and create a new folder inside this called `images/`. Find an image of a 1980s computer and drag it into this new directory. You can use the image below if you wish. @@ -247,12 +247,12 @@ Verify that you understand the elements used in marking up the table: ## 5 Semantic Markup -In this final exercise we will look at how [MicroData](https://developer.mozilla.org/en-US/docs/Web/HTML/Microdata) can be used to add semantic information to a web page. Start by using the SSH Terminal to run the server in the `exercises/03_html/05_semantic/` directory and navigating to the base route `/`. This should display a simple review page. +In this final exercise we will look at how [MicroData](https://developer.mozilla.org/en-US/docs/Web/HTML/Microdata) can be used to add semantic information to a web page. Start by using the terminal to run the server in the `exercises/03_html/05_semantic/` directory and navigating to the base route `/`. This should display a simple review page. 1. Paste the HTML code into Google's [Structured Data Testing Tool](https://search.google.com/structured-data/testing-tool) to see what semantic data it contains. Notice: - 1. There are two **items** on in the webpage, a movie and a rating. These are defined using the `itemscope` attribute in the html. Each item has an `itemtype` attribute that points to the appropriate Microdata definition. + 1. There is one main **item** on the webpage, which is a `review`, but it has many properties, some of which also consist of other **items**. These are defined using the `itemscope` attribute in the HTML file. Each item has an `itemtype` attribute that points to the appropriate Microdata definition. 2. Within each `itemscope`, the information has been tagged using the `itemprop` attribute. The allowed values are defined by the `itemtype` definition available on the [Schema.org website](http://schema.org/docs/full.html). - 3. The schema definitions define what `itemtype` are allowed and also what items can be nested inside which items. + 3. The schema definitions define what `itemtype`s are allowed and also what items can be nested inside which items. 2. The [Structured Data Testing Tool](https://search.google.com/structured-data/testing-tool) will not only extract the metadata but will also identify any errors in your implementation of the MicroData schema. 3. Install the [Structured Data Testing Tool Plugin](https://chrome.google.com/webstore/detail/structured-data-testing-t/kfdjeigpgagildmolfanniafmplnplpl/related?hl=en) for your Chrome Browser and use it to see the metadata. @@ -267,7 +267,7 @@ Hand-coding HTML can be a hassle, especially because you have to remember to add Start by running the server (note that you need to install an additional package called `marked`). 1. View the root path `/`. Notice that it displays a web page. -2. Use the **Elements** tab in the Chrome Developer Tools to view the markup, notice that the page contains a `

`,a `

` element plus an ordered list and a table. +2. Use the **Elements** tab in the Chrome Developer Tools to view the markup, notice that the page contains an `

`, a `

` element, plus an ordered list and a table. 3. Now open the `computers.md` file: 1. Notice how a single `#` symbol is used to denote a top level `

` element. 2. The `

` paragraph is denoted by text with no additional markup. diff --git a/exercises/02_http/01_url/index.js b/exercises/02_http/01_url/index.js index acf845f0..50e91348 100644 --- a/exercises/02_http/01_url/index.js +++ b/exercises/02_http/01_url/index.js @@ -73,8 +73,8 @@ router.post('/form', ctx => { router.get('/names', ctx => { let list = names - let search = 'x' - const minLength = 3 + let search = '' + const minLength = 1 if(ctx.query.search && ctx.query.search.length >= minLength) { search = ctx.query.search.toLowerCase() diff --git a/solutions/02_http/01_url/index.js b/solutions/02_http/01_url/index.js index e26c5ff1..000cfda9 100644 --- a/solutions/02_http/01_url/index.js +++ b/solutions/02_http/01_url/index.js @@ -67,7 +67,7 @@ router.get('/hello/:name', ctx => { // only applies uppercase if formatting query exists if (ctx.query.format === 'upper') myname = myname.toUpperCase() - if (ctx.query.format === 'upper') myname = myname.toLowerCase() + if (ctx.query.format === 'lower') myname = myname.toLowerCase() if (ctx.query.reverse === 'true') { myname = myname.split('').reverse().join('') @@ -93,8 +93,8 @@ router.post('/form', ctx => { router.get('/names', ctx => { let list = names - let search = 'x' - const minLength = 3 + let search = '' + const minLength = 1 if(ctx.query.search && ctx.query.search.length >= minLength) { search = ctx.query.search.toLowerCase() From e4321b034e0a353bc0fbac2a071f8257b89d496b Mon Sep 17 00:00:00 2001 From: Balazs Bordas Date: Sat, 19 Sep 2020 14:42:11 +0200 Subject: [PATCH 67/70] fixed errors and added all solutions up to the end of 04_css --- 04 CSS3.md | 105 +++++++++--------- exercises/03_html/02_lists/computers80.html | 6 +- .../03_hypermedia/views/commodore64.html | 3 +- .../01_formatting/html/hello-world.html | 24 ---- .../04_css/01_formatting/html/hello.html | 16 --- .../04_css/01_formatting/html/targets.html | 40 ------- .../04_css/01_formatting/public/css/hello.css | 3 +- .../01_formatting/public/css/selectors.css | 2 +- .../01_formatting/public/css/simple.css | 9 -- .../01_formatting/public/css/targetstyles.css | 2 +- .../01_formatting/views/comparison.html | 15 +-- .../04_css/01_formatting/views/csstest.html | 17 ++- .../01_formatting/views/hello-world.html | 24 ---- .../04_css/01_formatting/views/hello.html | 25 ++--- .../04_css/01_formatting/views/selectors.html | 8 +- .../04_css/01_formatting/views/targets.html | 27 ++--- .../02_layout/public/css/floatstyles.css | 10 +- .../02_layout/public/css/menustyles.css | 4 +- .../04_css/02_layout/views/boxmodel.html | 36 +++--- exercises/04_css/02_layout/views/columns.html | 104 +++++++++-------- .../04_css/02_layout/views/floating.html | 85 +++++++------- exercises/04_css/02_layout/views/menu.html | 45 ++++---- solutions/03_html/01_syntax/coventry.html | 3 +- solutions/03_html/02_lists/computers80.html | 6 +- .../03_hypermedia/views/commodore64.html | 6 +- .../03_html/03_hypermedia/views/index.html | 30 ++--- .../03_html/03_hypermedia/views/spectrum.html | 3 +- solutions/04_css/01_formatting/comparison.css | 47 ++++++++ .../04_css/01_formatting}/comparison.html | 18 ++- .../04_css/01_formatting}/csstest.html | 30 +++-- solutions/04_css/01_formatting/selectors.css | 23 ++++ .../04_css/01_formatting}/selectors.html | 14 +-- solutions/04_css/01_formatting/test.css | 60 ++++++++++ solutions/04_css/02_layout/berries.css | 56 ++++++++++ solutions/04_css/02_layout/berries.html | 30 +++++ solutions/04_css/02_layout/boxstyles.css | 25 +++++ solutions/04_css/02_layout/columnstyles.css | 13 +++ solutions/04_css/02_layout/floating.html | 64 +++++++++++ solutions/04_css/02_layout/floatstyles.css | 22 ++++ solutions/04_css/02_layout/menu.html | 54 +++++++++ solutions/04_css/02_layout/menustyles.css | 53 +++++++++ 41 files changed, 731 insertions(+), 436 deletions(-) delete mode 100644 exercises/04_css/01_formatting/html/hello-world.html delete mode 100644 exercises/04_css/01_formatting/html/hello.html delete mode 100644 exercises/04_css/01_formatting/html/targets.html delete mode 100644 exercises/04_css/01_formatting/public/css/simple.css delete mode 100644 exercises/04_css/01_formatting/views/hello-world.html create mode 100644 solutions/04_css/01_formatting/comparison.css rename {exercises/04_css/01_formatting/html => solutions/04_css/01_formatting}/comparison.html (76%) rename {exercises/04_css/01_formatting/html => solutions/04_css/01_formatting}/csstest.html (74%) create mode 100644 solutions/04_css/01_formatting/selectors.css rename {exercises/04_css/01_formatting/html => solutions/04_css/01_formatting}/selectors.html (53%) create mode 100644 solutions/04_css/01_formatting/test.css create mode 100644 solutions/04_css/02_layout/berries.css create mode 100644 solutions/04_css/02_layout/berries.html create mode 100644 solutions/04_css/02_layout/boxstyles.css create mode 100644 solutions/04_css/02_layout/columnstyles.css create mode 100644 solutions/04_css/02_layout/floating.html create mode 100644 solutions/04_css/02_layout/floatstyles.css create mode 100644 solutions/04_css/02_layout/menu.html create mode 100644 solutions/04_css/02_layout/menustyles.css diff --git a/04 CSS3.md b/04 CSS3.md index 4630da37..0c442e20 100644 --- a/04 CSS3.md +++ b/04 CSS3.md @@ -5,7 +5,7 @@ Before you start you need to pull any _upstream changes_. Detailed instructions ## 1 Introduction to CSS3 -The purpose of HTML is to define the structure and contents of a website. It is not intended to contain any representational markups. CSS (Cascaded Style Sheets) is designed for that purpose. +The purpose of HTML is to define the structure and contents of a website. It is not intended to contain any representational markups. CSS (Cascading Style Sheets) is designed for that purpose. > CSS is amazingly powerful. As an example, click to visit [CSS Zen Garden](http://www.csszengarden.com). Different CSS files are applied to a single HTML file by clicking on the navigation links to the right of the screen. There's a book for it as well on [Amazon](http://www.amazon.co.uk/ZEN-CSS-Design-Visual-Enlightenment/dp/0321303474). @@ -14,9 +14,9 @@ This worksheet is split into two sections: 1. The basics of CSS 2. The CSS box model and layouts -In the first part of this lab, you do the following tasks, and it takes approximately 2 hours. +The first part of this lab takes approximately 2 hours, and you'll do the following tasks: -1. Perform basic formatting (colors, fonts, etc.) of your web pages. +1. Perform basic formatting (colours, fonts, etc.) of your web pages. 2. Use CSS classes and identifiers to pick the correct elements 3. Fine-tune your selection by picking nested elements and using pseudo elements. @@ -28,13 +28,6 @@ Start by locating the `exercises/04_css/01_formatting/` directory. This contains > This diagram was created using the `tree` command run inside the `01_formatting/` directory. -1. The `index.js` script is in the root directory and contains the routes served by the Express web server (just like the ones in the previous weeks). -2. The `package.json` includes all the _metadata_ for this project including the packages that need to be installed. To install all the required packages run `npm install`. -3. The HTML files that are served by the routes are stored in a directory called `html/`. -4. Any resources that are linked to the html document need to have their own external URLs and are kept in the `public/` directory. - 1. There are some CSS files which we will be editing. - 2. There are some images loaded by the web pages. - ``` . ├── index.js @@ -48,7 +41,6 @@ Start by locating the `exercises/04_css/01_formatting/` directory. This contains └── public ├── css │   ├── selectors.css - │   ├── simple.css │   └── targetstyles.css └── images ├── comparison.png @@ -56,15 +48,22 @@ Start by locating the `exercises/04_css/01_formatting/` directory. This contains └── tickmark.png ``` +1. The `index.js` script is in the root directory and contains the routes served by the Koa web server (just like the ones in the previous weeks). +2. The `package.json` file includes all the _metadata_ for this project, including the packages that need to be installed. To install all the required packages, run `npm install`. +3. The HTML files that are served by the routes are stored in the `views/` directory. +4. Any resources that are linked to the html document need to have their own external URLs and are kept in the `public/` directory. + 1. There are some CSS files which we will be editing. + 2. There are some images loaded by the web pages. + The purpose of a style sheet is to collect all information on how the pages in a website should be visually rendered, into one place. Ideally, all web pages in a site should be linked to one style sheet (one CSS file) that contains all visual formatting rules for the entire website. -This approach makes a clear separation between content and representation. The approach makes it easy to get a uniform outlook for the entire site. Moreover, one can easily build alternative views that may be strikingly different visually yet they share the same content. +>This approach creates a clear separation between content and representation, and makes it easy to get a uniform outlook for the entire site. Moreover, one can easily build alternative views that may be strikingly different visually yet share the same content. -1. Look at the `index.js` file and locate the base route (`/`). Notice that it loads the contents of the `html/hello.html` file and sends this to the browser. -2. In the `` tags you should see a `` tag which loads the `public/css/hello.css` stylesheet file. Note that the script defines all the files in the `public/` directory as publicly visible which means the contents of this folder are treated as being in the web server root directory. In simple terms we don't need to specify the `public/` directory in the path to the CSS file. -3. Now start the server (if you have not already done so) and view the base url. You will see the heading is coloured in red. +1. Look at the `index.js` file and locate the base route (`/`). Notice that it loads the contents of the `views/hello.html` file and sends this to the browser. +2. In the `` tags you should see a `` tag which loads the `public/css/hello.css` stylesheet file. Note that the script defines all the files in the `public/` directory as publicly visible which means the contents of this folder are treated as being in the web server root directory. In simple terms, we don't need to specify the `public/` directory in the path to the CSS file. +3. Now start the server (if you have not already done so) and view the base URL. You will see the heading is coloured in red. 1. Look at the `hello.css` file and see if you can figure out why this has happened. 2. Change the colour of the heading to a different [named colour](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value). 4. Add the following to the css file and see what effect this has on the appearance of the web page. @@ -72,7 +71,7 @@ This approach makes a clear separation between content and representation. The a ```css body { - font-family: Arial, Verdana, sans-serif; + font-family: Arial, Helvetica, sans-serif; } h1, h2 { @@ -83,10 +82,10 @@ h1, h2 { Examine the CSS file and verify that you understand its contents. Pay attention to the following points: -- The file contains two rules. Each rule begins with the list of elements it has an effect on. The first rule is applied to the `body` element whilst the second rule is applied to `h1` and `h2` header elements. +- The file contains two rules. Each rule begins with the list of elements it has an effect on. The first rule is applied to the `body` element, while the second rule is applied to `h1` and `h2` header elements. - Followed by the element names (called selectors), there is a block starting with `{` and ending with `}`. This block contains a list of properties. - The first rule (applicable to the `body` element) contains one property for setting the font. -- The second rule (applicable to major headers) contains two properties, one for setting blue font color and the other for bold text. +- The second rule (applicable to major headers) contains two properties, one for setting blue font colour and the other for bold text. - The rules are automatically in effect in the nested subelements, so the font setting for `body` element applies to all elements in the page, including headers, lists, and paragraphs. - The fonts are given as a list of alternatives. The browser uses the first font in the list that it is capable of. The list should always end in a generic font such as `serif` or `sans-serif`. @@ -94,14 +93,14 @@ Examine the CSS file and verify that you understand its contents. Pay attention 1. View the `/test` url which should display a page about 1980s computers. 2. Create a new stylesheet in the `public/css/` directory called `test.css`. -3. Add a `h1` selector and apply a style to turn the headings _orange_. +3. Add an `h1` selector and apply a style to turn the headings _orange_. 4. Edit the `csstest.html` file and link to the spreadsheet. - 1. If you have done this correctly the heading should be orange when you refresh the browser! + - If you have done this correctly, the heading should be orange when you refresh the browser! 5. Spend time experimenting with different **selectors** and add new **rules** and **properties** to the file and see how they affect the web page. There is a complete list of CSS property names and possible values (among other information) at the [W3C Cascading Stylesheets documentation](http://www.w3.org/TR/CSS/) website. - 1. Add a border to each list and change the color of list items to dark grey. + 1. Add a border to each list and change the colour of list items to dark grey. 2. Indent the paragraphs and lists. 3. Make figure captions smaller and use bold face. - 4. Set a background color for the page. + 4. Set a background colour for the page. 6. Try specifying the page colours: 1. Using named colours ("red", "blue", etc.). 2. Specifying the same colours using RGB decimal values, eg `rgb(65,105,225)`. @@ -111,7 +110,7 @@ Examine the CSS file and verify that you understand its contents. Pay attention 1. Start by specifying the absolute size of the text by using _pixels_ (px) 2. Now change this to use _points_ (pt) 3. What is the change when you define the font sizes in _ems_. - 4. Finally change all font sizes are in percentages. + 4. Finally try font sizes in percentages. | Unit | Type | Meaning | |------|----------|----------------------------------------------------------| @@ -173,7 +172,7 @@ The paragraph element above belongs to two classes: `info` and `urgent`. #### 1.2.2 Identifiers -As seen before, multiple elements can belong to the same class. However, unique identifiers are a better option to generate rules that are applied only once. +As seen before, multiple elements can belong to the same class, however, unique identifiers are a better option to generate rules that are applied only once. This is marked in HTML by the identifier attribute: @@ -205,8 +204,8 @@ In the file, there are five paragraphs (`p`) and one header (`h1`). Verify that - The first and the second paragraphs are regular paragraph elements (start tag `

`). For these paragraphs, standard rules for `p` elements are applied. - The third and the fifth paragraphs are assigned a common class name (start tag `

`). For these paragraphs, standard rules for paragraphs are applied. In addition, rules for all `alert` class elements (`.alert`) are applied as well as those rules that are specific to paragraphs belonging to alert class (`p.alert`). - The fourth paragraph is supposed to have a unique formatting. Thus, it is assigned an identifier (start tag `

`). For this paragraph, standard paragraph rules plus rules specific to this identifier (#unique) apply. -- The header belongs to `alert` class like two of the paragraphs. It is affected by a rule that is targeted to all elements of `alert` class (`.alert`). In addition, all rules for `h1` would be applied but there is none. -- The rule for `body` element is applied to all elements as they are nested elements inside the body element. +- The header belongs to the `alert` class, like two of the paragraphs. It is affected by a rule that is targeted to all elements of the `alert` class (`.alert`). In addition, all rules for `h1` would be applied but there are none. +- The rule for the`body` element is applied to all elements as they are nested elements inside the body element. If a property of an element would be defined in multiple CSS rules, the rule whose selector has the highest specificity wins. For instance, the properties defined in a class-specific rule override the attributes defined in the general rule for the element. @@ -214,7 +213,7 @@ If a property of an element would be defined in multiple CSS rules, the rule who 1. Modify the `selectors.html` and `selectors.css` files so that the first, third, and fifth paragraph appear underlined (in addition to the existing formatting). You should achieve this with a single CSS rule. 2. In `csstest.html` file, add a paragraph about Basic programming to the bottom of the page (Basic was a common language for programming 80's home computers). Below the paragraph, add a sample program as below: - ``` + ```basic 10 PRINT "Hello, World" 20 INPUT "Continue (y/n)?", R$ 30 IF R$="y" THEN GOTO 10 @@ -257,7 +256,7 @@ ul li ul li ul { As the HTML file contains several list elements, nested and unnested, we can't make the correct elements as targets of the rules using a single element as a selector. However, CSS provides a straightforward way to achieve our goal. -- In the first rule, selector `ol > li` matches only those `li` elements that are direct children of the unordered list. +- In the first rule, selector `ol > li` matches only those `li` elements that are direct children of the ordered list. - In the second rule, those unordered lists are selected that appear in list items of a higher-level unordered list. Note that this rule applies to both the second and the third levels of the nested list in the example. - The third rule applies only to the third level (and potential deeper levels) in nested unordered lists. @@ -274,15 +273,15 @@ input[type="submit"] { } ``` -Of course, you can use also the normal selectors for elements like `form`, `legend`, `fieldset`, etc. Unfortunately support for styling form controls is inconsistent across browsers. +>Of course, you can also use the normal selectors for elements like `form`, `legend`, `fieldset`, etc. -Therefore, you should always check that the results are what is expected. +Unfortunately, support for styling form controls is inconsistent across browsers. Therefore, you should always check that the results are what is expected. #### 1.3.3 Nested and Pseudo Elements Pseudoelements allow formatting only certain parts of an element. Using pseudoelements, it is, for instance, possible to pick the first letter or line of a paragraph. -Add the following line into `simple.css` (that is linked to `csstest.html`): +Add the following lines to `test.css` (that is linked to `csstest.html`): ```css p::first-letter { @@ -326,7 +325,7 @@ As these approaches obscure the separation of content and presentation, their us #### 1.3.5 Test your Understanding -You need the aforementioned file `simple.css`. CSS pseudo elements `::before` and `::after` allow inserting content right before or after an element for stylistic purposes. These are normally used in conjunction with `content` property that specifies the content to be included. +You need the aforementioned file `test.css`. CSS pseudo elements `::before` and `::after` allow inserting content right before or after an element for stylistic purposes. These are normally used in conjunction with `content` property that specifies the content to be included. - Add a rule that adds the text `Note!` before each paragraph in `csstest.html`. - Add a rule that prints the image of a tick mark after each paragraph in `csstest.html`. A public domain tick mark image (Author: Kosta Kostov, via http://www.publicdomainpictures.net/) can be found in the lab's `public/images/` directory. @@ -347,7 +346,7 @@ In this section you will be doing the following tasks, it takes approximately 2 ### 2.1 CSS Box Model -First locate the `exercises/04_css/02_layout/` directory, start the Express server and open the `/boxmodel` route. This will display the contents of the `boxmodel.html` file. This will be used to illustrate the CSS box model which is vital for understanding how to set the dimensions, margins and paddings of elements in a web page. Check the contents of the file. You notice that it contains four paragraph elements, each labeled to belong to a different class. +First locate the `exercises/04_css/02_layout/` directory, start the Koa server and open the `/boxmodel` route. This will display the contents of the `boxmodel.html` file. This will be used to illustrate the CSS box model which is vital for understanding how to set the dimensions, margins and paddings of elements in a web page. Check the contents of the file. You notice that it contains four paragraph elements, each labeled to belong to a different class. Create a file called `boxstyles.css` in the correct directory and link it to the HTML file. @@ -384,13 +383,13 @@ Now, add rules for the remaining paragraph classes (two, three, four) to generat - class `two`: same border as for class `one`, no padding, 5em margins except for the top where no should be no margin. - class `three`: a 3-pixel wide solid black border only in the left edge of the paragraph, 1em padding except for the top where no padding is applied, 2em top margin, 8em bottom margin, no left and right margins. -- class `four`: a 5 pixels wide dashed red margin with rounded corners (1em radius). +- class `four`: a 5 pixels wide dashed red border with rounded corners (1em radius). Verify that all four paragraphs are displayed exactly as intended. #### 2.1.1 Developer tools -In Google Chrome browser, there are a built-in Developer Tools for viewing the layout of an individual element. It is an important tool for finding and correcting layout problems. Click options menu to the right of the menu bar, then More Tools ==> Developer Tools to view it. +In Google Chrome browser, there are a built-in Developer Tools for viewing the layout of an individual element. It is an important tool for finding and correcting layout problems. Press `ctrl+shift+i` or click options menu to the right of the menu bar, then More Tools -> Developer Tools to view it. ![](exercises/.images/03_tools.png) @@ -400,7 +399,7 @@ Alternatively, you can simply right-click on an element and select **Inspect**. #### 2.1.2 Test Your Understanding -The file `box_assignment.png` in the lab's `public/images/` directory contains an image of intended appearance for a webpage. Using CSS box model, construct an HTML page and the associated CSS file that reproduce the appearance of the image. +The file `box_assignment.png` in the lab's `public/images/` directory contains an image of intended appearance for a webpage. Using CSS box model, construct an HTML page and the associated CSS file that reproduce the appearance of the image. Don't forget to add the new route to the index.js file. In the lab's `public/images/` directory you also find the public domain image `berries.png` (author Scott Bauer, via http://commons.wikimedia.org) needed for this task. @@ -434,7 +433,7 @@ The HTML file contains one image tag. First, add an identifier for the figure ho ```html

-Onions + Onions
Onions are delicious.
``` @@ -453,12 +452,12 @@ Next, we make a floating fact box that contains multiple elements. Add the follo ```html
-

Did you know?

-
    -
  • The latin name for onion plant is Allium Cepa.
  • -
  • Onions have been used in cooking for thousands of years.
  • -
  • 89% of onion's content is water.
  • -
+

Did you know?

+
    +
  • The latin name for onion plant is Allium Cepa.
  • +
  • Onions have been used in cooking for thousands of years.
  • +
  • 89% of onions' content is water.
  • +
``` @@ -491,11 +490,11 @@ Add the navigation information (using the HTML5 `nav` element) into the bottom o ```html + Nutrition + Recipes + Growing + History + ``` Note that the routes that the links point to do not exist. We could add them later. @@ -519,14 +518,14 @@ Note that the elements positioned using absolute positioning may appear on top o ```css body { - font-family: Arial, Verdana, sans-serif; + font-family: Arial, Helvetica, sans-serif; margin-left: 200px; } ``` #### 2.2.3 Test Your Understanding -1. Open file **columns.html**. Generate a style sheet **columnstyles.css** where the paragraphs are displayed in: +1. Open file **columns.html**. Generate a style sheet **columnstyles.css** (which is already linked to the HTML file) where the paragraphs are displayed in: 1. two columns 2. three columns 3. Search for CSS properties containing the word `column`. Currently, there are browser restrictions and inconsistencies in displaying multi-column content, but the workarounds are well documented. Try to take these into account in your CSS. @@ -536,15 +535,15 @@ body { The next task is to build a navigation menu bar to the website using CSS. Depending on the number of menu items, the menu bar can contain multi-level menus. -A menu bar can be defined as a HTML unordered list. Each menu in a menu bar is a list item. +A menu bar can be defined as an HTML unordered list. Each menu in a menu bar is a list item. The menus can contain submenus. A submenu is coded as a list that is within the parent menu's list item. -Open the `/menu` route and find the appropriate html and css files. +Open the `/menu` route and find the appropriate `.html` and `.css` files. Try the functionality of the two-level menu by hovering the mouse pointer over the **Item 1**, **Item 2**, and **Item 3** texts. The last two have submenus. -Examine, how the hierarchical menu was created using plain CSS. Note that the links are just dummies; they don't lead to any web pages. In the example, the barebones menu bar contains only minimum formatting that is necessary for correct layout. +Examine, how the hierarchical menu was created using plain CSS. Note that the links are just dummies: they don't lead to any web pages. In the example, the barebones menu bar contains only the minimum formatting that is necessary for correct layout. Important things to note: diff --git a/exercises/03_html/02_lists/computers80.html b/exercises/03_html/02_lists/computers80.html index 5c185f87..e4fafc19 100644 --- a/exercises/03_html/02_lists/computers80.html +++ b/exercises/03_html/02_lists/computers80.html @@ -1,11 +1,10 @@ - + 1980s' home computers - + -
A computer with a monitor @@ -28,5 +27,4 @@

Key concepts

The hardware charateristics of a home computer could be defined by its graphics and sound capabilities, CPU, and amount of memory.

- \ No newline at end of file diff --git a/exercises/03_html/03_hypermedia/views/commodore64.html b/exercises/03_html/03_hypermedia/views/commodore64.html index 3315d8a1..a98baa85 100644 --- a/exercises/03_html/03_hypermedia/views/commodore64.html +++ b/exercises/03_html/03_hypermedia/views/commodore64.html @@ -1,10 +1,9 @@ - + Commodore 64 - diff --git a/exercises/04_css/01_formatting/html/hello-world.html b/exercises/04_css/01_formatting/html/hello-world.html deleted file mode 100644 index 32dc15b0..00000000 --- a/exercises/04_css/01_formatting/html/hello-world.html +++ /dev/null @@ -1,24 +0,0 @@ - - - - - Document - - - - - - - - - - -
- -
    -
  • -
  • -
  • -
  • -
  • -
\ No newline at end of file diff --git a/exercises/04_css/01_formatting/html/hello.html b/exercises/04_css/01_formatting/html/hello.html deleted file mode 100644 index de2ff46d..00000000 --- a/exercises/04_css/01_formatting/html/hello.html +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - Let's see CSS at Work - - - - - -

Hello CSS!

-

Use this file to see how CSS can be used to change the appearance of a web page.

- - \ No newline at end of file diff --git a/exercises/04_css/01_formatting/html/targets.html b/exercises/04_css/01_formatting/html/targets.html deleted file mode 100644 index 5738cf46..00000000 --- a/exercises/04_css/01_formatting/html/targets.html +++ /dev/null @@ -1,40 +0,0 @@ - - - - Selecting elements - - - - - -

Element selection demo

- -

The sources of energy are:

-
    -
  1. protein
  2. -
  3. carbohydrates
  4. -
  5. fat
  6. -
- -

Sources of carbohydrates:

-
    -
  • Fruits and berries
  • -
  • Wheat and pasta
  • -
  • Sweet products -
      -
    • Candies
        -
      • Jelly beans
      • -
      • Irish toffee
      • -
      • Fruit drops
      • - -
    • - -
    • Pastries
    • -
    -
  • - -
- - - - \ No newline at end of file diff --git a/exercises/04_css/01_formatting/public/css/hello.css b/exercises/04_css/01_formatting/public/css/hello.css index fb0e5d21..4717ad4b 100644 --- a/exercises/04_css/01_formatting/public/css/hello.css +++ b/exercises/04_css/01_formatting/public/css/hello.css @@ -1,4 +1,3 @@ - h1 { - color: red; + color: red; } \ No newline at end of file diff --git a/exercises/04_css/01_formatting/public/css/selectors.css b/exercises/04_css/01_formatting/public/css/selectors.css index 41f8b1cc..8a7ab42d 100644 --- a/exercises/04_css/01_formatting/public/css/selectors.css +++ b/exercises/04_css/01_formatting/public/css/selectors.css @@ -1,5 +1,5 @@ body { - font-family: Arial, Verdana, sans-serif; + font-family: Arial, Helvetica, sans-serif; } p { diff --git a/exercises/04_css/01_formatting/public/css/simple.css b/exercises/04_css/01_formatting/public/css/simple.css deleted file mode 100644 index 061fbf3b..00000000 --- a/exercises/04_css/01_formatting/public/css/simple.css +++ /dev/null @@ -1,9 +0,0 @@ -body { - font-family: Arial, Verdana, sans-serif; -} - -h1, -h2 { - color: blue; - font-weight: bold; -} \ No newline at end of file diff --git a/exercises/04_css/01_formatting/public/css/targetstyles.css b/exercises/04_css/01_formatting/public/css/targetstyles.css index 7cebbae5..8843f31f 100644 --- a/exercises/04_css/01_formatting/public/css/targetstyles.css +++ b/exercises/04_css/01_formatting/public/css/targetstyles.css @@ -1,3 +1,3 @@ body { - font-family: Arial, Verdana, sans-serif; + font-family: Arial, Helvetica, sans-serif; } diff --git a/exercises/04_css/01_formatting/views/comparison.html b/exercises/04_css/01_formatting/views/comparison.html index 42b0dda9..a0e45264 100644 --- a/exercises/04_css/01_formatting/views/comparison.html +++ b/exercises/04_css/01_formatting/views/comparison.html @@ -1,11 +1,10 @@ - + Comparison of three computers - + -

A comparison of technical data of three popular 80's home computers:

@@ -21,28 +20,24 @@ - CPU + CPU MOS Technology 6510 Zilog Z80 MOS Technology 6502 - RAM + RAM 64 kilobytes 16 or 64 kilobytes 5 kilobytes - ROM + ROM 20 kilobytes 16 kilobytes 16 kilobytes - -
- - \ No newline at end of file diff --git a/exercises/04_css/01_formatting/views/csstest.html b/exercises/04_css/01_formatting/views/csstest.html index 0791d1a4..4880a54c 100644 --- a/exercises/04_css/01_formatting/views/csstest.html +++ b/exercises/04_css/01_formatting/views/csstest.html @@ -1,9 +1,9 @@ - - + + Vintage Home Computers - +
@@ -11,8 +11,8 @@

1980's Home Computers

In early 1980's, home computers became mainstream. For the first time, computers could be purchased by an average family household.

- A computer with a monitor -
Photo: Piotr Siedlecki, public domain via http://www.publicdomainpictures.net.
+ A computer with a monitor +
Photo: Piotr Siedlecki, public domain via http://www.publicdomainpictures.net.

Novel uses

The main usage for a home computer was, of course, games. As cool games may not be a valid reason for purchasing an expensive gadget, @@ -47,10 +47,7 @@

Key concepts