From 8207d2b8176ecb95da028c3412271eaebe9da66e Mon Sep 17 00:00:00 2001 From: William Wager Date: Sun, 9 Feb 2020 19:14:20 -0500 Subject: [PATCH 01/34] Completed project 1 --- .devcontainer/Dockerfile | 21 ++++++++++++++ .devcontainer/devcontainer.json | 24 ++++++++++++++++ 01 - JavaScript Drum Kit/index-START.html | 6 +--- 01 - JavaScript Drum Kit/typescripts.js | 17 +++++++++++ 01 - JavaScript Drum Kit/typescripts.ts | 35 +++++++++++++++++++++++ readme.md | 13 ++++++++- 6 files changed, 110 insertions(+), 6 deletions(-) create mode 100644 .devcontainer/Dockerfile create mode 100644 .devcontainer/devcontainer.json create mode 100644 01 - JavaScript Drum Kit/typescripts.js create mode 100644 01 - JavaScript Drum Kit/typescripts.ts diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile new file mode 100644 index 0000000000..0c2b14f401 --- /dev/null +++ b/.devcontainer/Dockerfile @@ -0,0 +1,21 @@ +#------------------------------------------------------------------------------------------------------------- +# Copyright (c) Microsoft Corporation. All rights reserved. +# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information. +#------------------------------------------------------------------------------------------------------------- + +# To fully customize the contents of this image, use the following Dockerfile instead: +# https://github.com/microsoft/vscode-dev-containers/tree/v0.101.0/containers/typescript-node-12/.devcontainer/Dockerfile +FROM mcr.microsoft.com/vscode/devcontainers/typescript-node:0-12 + +# ** [Optional] Uncomment this section to install additional packages. ** +# +# ENV DEBIAN_FRONTEND=noninteractive +# RUN apt-get update \ +# && apt-get -y install --no-install-recommends \ +# # +# # Clean up +# && apt-get autoremove -y \ +# && apt-get clean -y \ +# && rm -rf /var/lib/apt/lists/* +# ENV DEBIAN_FRONTEND=dialog + diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000000..783e222ebe --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,24 @@ +// For format details, see https://aka.ms/vscode-remote/devcontainer.json or this file's README at: +// https://github.com/microsoft/vscode-dev-containers/tree/v0.101.0/containers/typescript-node-12 +{ + "name": "Node.js 12 & TypeScript", + "dockerFile": "Dockerfile", + // Set *default* container specific settings.json values on container create. + "settings": { + "terminal.integrated.shell.linux": "/bin/bash" + }, + // Add the IDs of extensions you want installed when the container is created. + "extensions": [ + "dbaeumer.vscode-eslint", + "ms-vscode.vscode-typescript-tslint-plugin", + "ritwickdey.liveserver" + ], + // Use 'forwardPorts' to make a list of ports inside the container available locally. + "forwardPorts": [ + 5500 + ], + // Use 'postCreateCommand' to run commands after the container is created. + // "postCreateCommand": "yarn install", + // Uncomment to connect as a non-root user. See https://aka.ms/vscode-remote/containers/non-root. + // "remoteUser": "node" +} \ No newline at end of file diff --git a/01 - JavaScript Drum Kit/index-START.html b/01 - JavaScript Drum Kit/index-START.html index 4070d32767..490591ae62 100644 --- a/01 - JavaScript Drum Kit/index-START.html +++ b/01 - JavaScript Drum Kit/index-START.html @@ -57,10 +57,6 @@ - - - + diff --git a/01 - JavaScript Drum Kit/typescripts.js b/01 - JavaScript Drum Kit/typescripts.js new file mode 100644 index 0000000000..5e1c47ec88 --- /dev/null +++ b/01 - JavaScript Drum Kit/typescripts.js @@ -0,0 +1,17 @@ +var keys = document.querySelector('.keys'); +function handleKey(e) { + var audio = document.querySelector("audio[data-key=\"" + e.keyCode + "\"]"); + if (!audio) + return; + var key = document.querySelector(".key[data-key=\"" + e.keyCode + "\"]"); + audio.currentTime = 0; + audio.play(); + key.classList.add('playing'); +} +function handleEnd(e) { + if (e.propertyName !== 'transform') + return; + e.target.classList.remove('playing'); +} +document.addEventListener('keydown', handleKey); +keys.addEventListener('transitionend', handleEnd); diff --git a/01 - JavaScript Drum Kit/typescripts.ts b/01 - JavaScript Drum Kit/typescripts.ts new file mode 100644 index 0000000000..39545914cd --- /dev/null +++ b/01 - JavaScript Drum Kit/typescripts.ts @@ -0,0 +1,35 @@ +/** + * JavaScript30 by Wes Bos, https://javascript30.com/ + * TypeScript implementation by Will Wager https://willwager.dev + * Project: TypeScript Drum Kit + * Concepts: + * keyCodes, Audio, transitionend events + * Key takeaways: + * Attribute selectors, HTMLAudioElement properties and methods, classList usage, and + * using transitionend events to keep the visuals in sync. + * Sidenotes: + * keyCode is deprecated, but the replacement 'code' is not implemented in Edge and IE. + * The sound is reset when pressed multiple times, but the visual state is not so there + * is a flicker when holding the key. + */ + +const keys = document.querySelector('.keys'); + +function handleKey(e) { + const audio: HTMLAudioElement = document.querySelector(`audio[data-key="${e.keyCode}"]`); + if (!audio) return; + const key = document.querySelector(`.key[data-key="${e.keyCode}"]`); + audio.currentTime = 0; + audio.play(); + + key.classList.add('playing'); +} + +// Updated to use event delegation here. +function handleEnd(e) { + if (e.propertyName !== 'transform') return; + e.target.classList.remove('playing'); +} + +document.addEventListener('keydown', handleKey); +keys.addEventListener('transitionend', handleEnd); \ No newline at end of file diff --git a/readme.md b/readme.md index bb861dd631..c2d9ea3a3d 100644 --- a/readme.md +++ b/readme.md @@ -1,7 +1,18 @@ ![](https://javascript30.com/images/JS3-social-share.png) +Will Wager's TypeScript solutions for Wes Bos's... # JavaScript30 +Run them yourself from a VS Code container! +* Open in vscode and run `Remote Containers: Reopen in Container` from the command palette. +* Build each TypeScript file with `tsc typescripts.ts` from each project's folder. + * All html files have been adjusted to look for typescripts.js. + * I use the options `--target es5 --removeComments` in my js builds. +* Press ALT + L, ALT + O to start the Live Server extension and access the html files at http://localhost:5500 + the relative path. + * For example, to open the first project, go to (replace spaces with '20%' if your browser complains): `http://localhost:5500/01%20-%20JavaScript%20Drum%20Kit/index-START.html` + +---- + Starter Files + Completed solutions for the JavaScript 30 Day Challenge. Grab the course at [https://JavaScript30.com](https://JavaScript30.com) @@ -39,7 +50,7 @@ Feel free to submit a PR adding a link to your own recaps, guides or reviews! * [Yusong Notes](https://sky172839465.github.io/course/js30) Records Yusong JS 30 days note and demo :star2: * [Ding's Implementation](https://github.com/Ding-Fan/javascript30) code and online demo * [Herminio Torres](https://github.com/herminiotorres/JavaScript30) lessons and tricks learned, and a [gh-page](https://herminiotorres.github.io/JavaScript30/) to see working all the mini-projects. -* [Dmytro Borysovskyi](https://github.com/dimabory) says many thanks to for the course to Wes 🤝 It was incredible challenge 👌 The full repository with code available [here](https://github.com/dimabory/dimabory.github.io/tree/gh-pages/src/components/JavaScript30Days) and demos can be reached by the link to [gh-pages](https://dimabory.github.io/#/js30days) 👍👍👍 +* [Dmytro Borysovskyi](https://github.com/dimabory) says many thanks to for the course to Wes 🤝 It was incredible challenge 👌 The full repository with code available [here](https://github.com/dimabory/dimabory.github.io/tree/gh-pages/src/components/JavaScript30Days) and demos can be reached by the link to [gh-pages](https://dimabory.github.io/#/js30days) 👍👍👍 * [Kizito](https://github.com/akhilome/)'s follow along [repo](https://github.com/akhilome/js30) with [completed challenges](https://akhilome.github.io/js30) and [notes](https://akhilome.github.io/js30/notes). * [VannTile](https://github.com/vanntile)'s [repository](https://github.com/vanntile/JavaScript30) and [GitHub Pages showcase](https://vanntile.github.io/JavaScript30/). Thank you for a great ⌨️ experience. * [Alex Kim](https://github.com/Alex-K1m/js30-challenge) completed all the challenges. You can check them out at [github pages](https://alex-k1m.github.io/js30-challenge/). From 885abbca14b57931bc095d9027337b3b374324cc Mon Sep 17 00:00:00 2001 From: William Wager Date: Mon, 10 Feb 2020 14:34:10 -0500 Subject: [PATCH 02/34] Completed project 2 --- 02 - JS and CSS Clock/index-START.html | 35 ++++++++++++-------- 02 - JS and CSS Clock/typescripts.js | 35 ++++++++++++++++++++ 02 - JS and CSS Clock/typescripts.ts | 46 ++++++++++++++++++++++++++ 3 files changed, 102 insertions(+), 14 deletions(-) create mode 100644 02 - JS and CSS Clock/typescripts.js create mode 100644 02 - JS and CSS Clock/typescripts.ts diff --git a/02 - JS and CSS Clock/index-START.html b/02 - JS and CSS Clock/index-START.html index 12f721b183..4276907ce6 100644 --- a/02 - JS and CSS Clock/index-START.html +++ b/02 - JS and CSS Clock/index-START.html @@ -1,19 +1,21 @@ + JS + CSS Clock + -
-
-
-
-
-
+
+
+
+
+
+
- + - + + \ No newline at end of file diff --git a/02 - JS and CSS Clock/typescripts.js b/02 - JS and CSS Clock/typescripts.js new file mode 100644 index 0000000000..ec490a5ca0 --- /dev/null +++ b/02 - JS and CSS Clock/typescripts.js @@ -0,0 +1,35 @@ +var secHand = document.querySelector('.second-hand'); +var minHand = document.querySelector('.min-hand'); +var hourHand = document.querySelector('.hour-hand'); +function setDateLoop() { + var now = new Date(); + var seconds = now.getSeconds(); + var secondsDegrees = (seconds / 60) * 360 + 90; + if (secondsDegrees === 90) { + secHand.style.transition = 'none'; + } + else { + secHand.style.transition = 'transform 0.05s cubic-bezier(0.1, 2.7, 0.58, 1)'; + } + secHand.style.transform = "rotate(" + secondsDegrees + "deg)"; + var mins = now.getMinutes(); + var minsDegrees = (mins / 60) * 360 + 90; + if (minsDegrees === 90) { + minHand.style.transition = 'none'; + } + else { + minHand.style.transition = 'transform 0.05s cubic-bezier(0.1, 2.7, 0.58, 1)'; + } + minHand.style.transform = "rotate(" + minsDegrees + "deg)"; + var hours = now.getHours(); + var hoursDegrees = (hours / 12) * 360 + 90; + if (hoursDegrees === 90) { + hourHand.style.transition = 'none'; + } + else { + hourHand.style.transition = 'transform 0.05s cubic-bezier(0.1, 2.7, 0.58, 1)'; + } + hourHand.style.transform = "rotate(" + hoursDegrees + "deg)"; + window.requestAnimationFrame(setDateLoop); +} +setDateLoop(); diff --git a/02 - JS and CSS Clock/typescripts.ts b/02 - JS and CSS Clock/typescripts.ts new file mode 100644 index 0000000000..b757ab8e1c --- /dev/null +++ b/02 - JS and CSS Clock/typescripts.ts @@ -0,0 +1,46 @@ +/** + * JavaScript30 by Wes Bos, https://javascript30.com/ + * TypeScript implementation by Will Wager + * Project: TS and CSS Clock + * Concepts: Transforms and transitions + * Key takeaways: Using Date, updating CSS with TS. + * Sidenotes: Disable transition on the reset step to avoid flicker. + */ + +const secHand: HTMLElement = document.querySelector('.second-hand'); +const minHand: HTMLElement = document.querySelector('.min-hand'); +const hourHand: HTMLElement = document.querySelector('.hour-hand'); + +function setDateLoop(): void { + const now = new Date(); + const seconds = now.getSeconds(); + const secondsDegrees = (seconds / 60) * 360 + 90; + if (secondsDegrees === 90) { + secHand.style.transition = 'none'; + } else { + secHand.style.transition = 'transform 0.05s cubic-bezier(0.1, 2.7, 0.58, 1)'; + } + secHand.style.transform = `rotate(${secondsDegrees}deg)`; + + const mins = now.getMinutes(); + const minsDegrees = (mins / 60) * 360 + 90; + if (minsDegrees === 90) { + minHand.style.transition = 'none'; + } else { + minHand.style.transition = 'transform 0.05s cubic-bezier(0.1, 2.7, 0.58, 1)'; + } + minHand.style.transform = `rotate(${minsDegrees}deg)`; + + const hours = now.getHours(); + const hoursDegrees = (hours / 12) * 360 + 90; + if (hoursDegrees === 90) { + hourHand.style.transition = 'none'; + } else { + hourHand.style.transition = 'transform 0.05s cubic-bezier(0.1, 2.7, 0.58, 1)'; + } + hourHand.style.transform = `rotate(${hoursDegrees}deg)`; + + window.requestAnimationFrame(setDateLoop); +} + +setDateLoop(); From e2c70e255f46e0239072c7a844c02b499a10b773 Mon Sep 17 00:00:00 2001 From: William Wager Date: Thu, 20 Feb 2020 20:59:19 -0500 Subject: [PATCH 03/34] Finished project 3 --- 03 - CSS Variables/index-START.html | 23 ++++++++++++++++++++--- 03 - CSS Variables/typescripts.js | 7 +++++++ 03 - CSS Variables/typescripts.ts | 9 +++++++++ 3 files changed, 36 insertions(+), 3 deletions(-) create mode 100644 03 - CSS Variables/typescripts.js create mode 100644 03 - CSS Variables/typescripts.ts diff --git a/03 - CSS Variables/index-START.html b/03 - CSS Variables/index-START.html index 6b9b539c09..b6a31e4a24 100644 --- a/03 - CSS Variables/index-START.html +++ b/03 - CSS Variables/index-START.html @@ -1,9 +1,11 @@ + Scoped CSS Variables and JS +

Update CSS Variables with JS

@@ -21,6 +23,21 @@

Update CSS Variables with JS

- + - + + \ No newline at end of file diff --git a/03 - CSS Variables/typescripts.js b/03 - CSS Variables/typescripts.js new file mode 100644 index 0000000000..ab2b038a1d --- /dev/null +++ b/03 - CSS Variables/typescripts.js @@ -0,0 +1,7 @@ +var inputs = document.querySelectorAll('.controls input'); +function handleUpdate() { + var suffix = this.dataset.sizing || ''; + document.documentElement.style.setProperty("--" + this.name, this.value + suffix); +} +inputs.forEach(function (input) { return input.addEventListener('change', handleUpdate); }); +inputs.forEach(function (input) { return input.addEventListener('mousemove', handleUpdate); }); diff --git a/03 - CSS Variables/typescripts.ts b/03 - CSS Variables/typescripts.ts new file mode 100644 index 0000000000..7f401a0b34 --- /dev/null +++ b/03 - CSS Variables/typescripts.ts @@ -0,0 +1,9 @@ +const inputs: NodeList = document.querySelectorAll('.controls input'); + +function handleUpdate() { + const suffix = this.dataset.sizing || ''; + document.documentElement.style.setProperty(`--${this.name}`, this.value + suffix); +} + +inputs.forEach(input => input.addEventListener('change', handleUpdate)); +inputs.forEach(input => input.addEventListener('mousemove', handleUpdate)); From 5331f6d3def452875bc52e709fbeedf42e3b1097 Mon Sep 17 00:00:00 2001 From: William Wager Date: Fri, 21 Feb 2020 20:42:05 -0500 Subject: [PATCH 04/34] Adding notes to project 3 --- 03 - CSS Variables/typescripts.ts | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/03 - CSS Variables/typescripts.ts b/03 - CSS Variables/typescripts.ts index 7f401a0b34..1c89266ae8 100644 --- a/03 - CSS Variables/typescripts.ts +++ b/03 - CSS Variables/typescripts.ts @@ -1,3 +1,12 @@ +/** + * JavaScript30 by Wes Bos, https://javascript30.com/ + * TypeScript implementation by Will Wager + * Project: CSS Variables + * Concepts: Dynamically updating CSS Variables + * Key takeaways: CSS variables syntax, CSS variables cascade. + * Sidenotes: AKA "CSS custom properties" + */ + const inputs: NodeList = document.querySelectorAll('.controls input'); function handleUpdate() { From c54cb9d957d63117d9eace3fedcbd3afa26b1efc Mon Sep 17 00:00:00 2001 From: William Wager Date: Fri, 21 Feb 2020 20:47:55 -0500 Subject: [PATCH 05/34] Project 4 complete --- 04 - Array Cardio Day 1/index-START.html | 55 ++------------- 04 - Array Cardio Day 1/typescripts.js | 42 ++++++++++++ 04 - Array Cardio Day 1/typescripts.ts | 85 ++++++++++++++++++++++++ 3 files changed, 132 insertions(+), 50 deletions(-) create mode 100644 04 - Array Cardio Day 1/typescripts.js create mode 100644 04 - Array Cardio Day 1/typescripts.ts diff --git a/04 - Array Cardio Day 1/index-START.html b/04 - Array Cardio Day 1/index-START.html index d19181b6b4..7f62ee31fb 100644 --- a/04 - Array Cardio Day 1/index-START.html +++ b/04 - Array Cardio Day 1/index-START.html @@ -1,59 +1,14 @@ + Array Cardio 💪 +

Psst: have a look at the JavaScript Console 💁

- + - + + \ No newline at end of file diff --git a/04 - Array Cardio Day 1/typescripts.js b/04 - Array Cardio Day 1/typescripts.js new file mode 100644 index 0000000000..1ae842be44 --- /dev/null +++ b/04 - Array Cardio Day 1/typescripts.js @@ -0,0 +1,42 @@ +var inventors = [ + { first: 'Albert', last: 'Einstein', year: 1879, passed: 1955 }, + { first: 'Isaac', last: 'Newton', year: 1643, passed: 1727 }, + { first: 'Galileo', last: 'Galilei', year: 1564, passed: 1642 }, + { first: 'Marie', last: 'Curie', year: 1867, passed: 1934 }, + { first: 'Johannes', last: 'Kepler', year: 1571, passed: 1630 }, + { first: 'Nicolaus', last: 'Copernicus', year: 1473, passed: 1543 }, + { first: 'Max', last: 'Planck', year: 1858, passed: 1947 }, + { first: 'Katherine', last: 'Blodgett', year: 1898, passed: 1979 }, + { first: 'Ada', last: 'Lovelace', year: 1815, passed: 1852 }, + { first: 'Sarah E.', last: 'Goode', year: 1855, passed: 1905 }, + { first: 'Lise', last: 'Meitner', year: 1878, passed: 1968 }, + { first: 'Hanna', last: 'Hammarström', year: 1829, passed: 1909 } +]; +var people = ['Beck, Glenn', 'Becker, Carl', 'Beckett, Samuel', 'Beddoes, Mick', 'Beecher, Henry', 'Beethoven, Ludwig', 'Begin, Menachem', 'Belloc, Hilaire', 'Bellow, Saul', 'Benchley, Robert', 'Benenson, Peter', 'Ben-Gurion, David', 'Benjamin, Walter', 'Benn, Tony', 'Bennington, Chester', 'Benson, Leana', 'Bent, Silas', 'Bentsen, Lloyd', 'Berger, Ric', 'Bergman, Ingmar', 'Berio, Luciano', 'Berle, Milton', 'Berlin, Irving', 'Berne, Eric', 'Bernhard, Sandra', 'Berra, Yogi', 'Berry, Halle', 'Berry, Wendell', 'Bethea, Erin', 'Bevan, Aneurin', 'Bevel, Ken', 'Biden, Joseph', 'Bierce, Ambrose', 'Biko, Steve', 'Billings, Josh', 'Biondo, Frank', 'Birrell, Augustine', 'Black, Elk', 'Blair, Robert', 'Blair, Tony', 'Blake, William']; +var fifteen = inventors.filter(function (inventor) { return inventor.year >= 1500 && inventor.year < 1600; }); +console.table(fifteen); +var fullNames = inventors.map(function (inventor) { return inventor.first + " " + inventor.last; }); +console.table(fullNames); +var ordered = inventors.sort(function (inventorA, inventorB) { return inventorA.year > inventorB.year ? 1 : -1; }); +console.table(ordered); +var totalYears = inventors.reduce(function (total, inventor) { return total + (inventor.passed - inventor.year); }, 0); +console.log(totalYears); +var oldest = inventors.sort(function (inventorA, inventorB) { return ((inventorA.passed - inventorA.year) > (inventorB.passed - inventorB.year)) ? -1 : 1; }); +console.table(oldest); +var alpha = people.sort(function (personA, personB) { + var _a = personA.split(', '), lastA = _a[0], firstA = _a[1]; + var _b = personB.split(', '), lastB = _b[0], firstB = _b[1]; + return lastA > lastB ? 1 : -1; +}); +console.table(alpha); +var data = ['car', 'car', 'truck', 'truck', 'bike', 'walk', 'car', 'van', 'bike', 'walk', 'car', 'van', 'car', 'truck']; +var transportation = data.reduce(function (obj, item) { + if (!obj[item]) { + obj[item] = 1; + } + else { + obj[item]++; + } + return obj; +}, {}); +console.log(transportation); diff --git a/04 - Array Cardio Day 1/typescripts.ts b/04 - Array Cardio Day 1/typescripts.ts new file mode 100644 index 0000000000..9cbc444291 --- /dev/null +++ b/04 - Array Cardio Day 1/typescripts.ts @@ -0,0 +1,85 @@ +/** + * JavaScript30 by Wes Bos, https://javascript30.com/ + * TypeScript implementation by Will Wager + * Project: Array Cardio + * Concepts: Array builtins - filter, map, sort, reduce. + * Key takeaways: Practice, and reduce function must return the thing + * Sidenotes: Search only under a DOM element with element.querySelector[All]() + */ + +// Get your shorts on - this is an array workout! +// ## Array Cardio Day 1 + +// Some data we can work with + +const inventors = [ + { first: 'Albert', last: 'Einstein', year: 1879, passed: 1955 }, + { first: 'Isaac', last: 'Newton', year: 1643, passed: 1727 }, + { first: 'Galileo', last: 'Galilei', year: 1564, passed: 1642 }, + { first: 'Marie', last: 'Curie', year: 1867, passed: 1934 }, + { first: 'Johannes', last: 'Kepler', year: 1571, passed: 1630 }, + { first: 'Nicolaus', last: 'Copernicus', year: 1473, passed: 1543 }, + { first: 'Max', last: 'Planck', year: 1858, passed: 1947 }, + { first: 'Katherine', last: 'Blodgett', year: 1898, passed: 1979 }, + { first: 'Ada', last: 'Lovelace', year: 1815, passed: 1852 }, + { first: 'Sarah E.', last: 'Goode', year: 1855, passed: 1905 }, + { first: 'Lise', last: 'Meitner', year: 1878, passed: 1968 }, + { first: 'Hanna', last: 'Hammarström', year: 1829, passed: 1909 } +]; + +const people = ['Beck, Glenn', 'Becker, Carl', 'Beckett, Samuel', 'Beddoes, Mick', 'Beecher, Henry', 'Beethoven, Ludwig', 'Begin, Menachem', 'Belloc, Hilaire', 'Bellow, Saul', 'Benchley, Robert', 'Benenson, Peter', 'Ben-Gurion, David', 'Benjamin, Walter', 'Benn, Tony', 'Bennington, Chester', 'Benson, Leana', 'Bent, Silas', 'Bentsen, Lloyd', 'Berger, Ric', 'Bergman, Ingmar', 'Berio, Luciano', 'Berle, Milton', 'Berlin, Irving', 'Berne, Eric', 'Bernhard, Sandra', 'Berra, Yogi', 'Berry, Halle', 'Berry, Wendell', 'Bethea, Erin', 'Bevan, Aneurin', 'Bevel, Ken', 'Biden, Joseph', 'Bierce, Ambrose', 'Biko, Steve', 'Billings, Josh', 'Biondo, Frank', 'Birrell, Augustine', 'Black, Elk', 'Blair, Robert', 'Blair, Tony', 'Blake, William']; + +// Array.prototype.filter() +// 1. Filter the list of inventors for those who were born in the 1500's +const fifteen = inventors.filter(inventor => inventor.year >= 1500 && inventor.year < 1600); +console.table(fifteen); + +// Array.prototype.map() +// 2. Give us an array of the inventors first and last names +const fullNames = inventors.map(inventor => `${inventor.first} ${inventor.last}`); +console.table(fullNames); + +// Array.prototype.sort() +// 3. Sort the inventors by birthdate, oldest to youngest +const ordered = inventors.sort((inventorA, inventorB) => inventorA.year > inventorB.year ? 1 : -1); +console.table(ordered); + +// Array.prototype.reduce() +// 4. How many years did all the inventors live all together? +const totalYears = inventors.reduce((total, inventor) => total + (inventor.passed - inventor.year), 0); +console.log(totalYears); + +// 5. Sort the inventors by years lived +const oldest = inventors.sort((inventorA, inventorB) => ((inventorA.passed - inventorA.year) > (inventorB.passed - inventorB.year)) ? -1 : 1); +console.table(oldest); + +// 6. create a list of Boulevards in Paris that contain 'de' anywhere in the name +// https://en.wikipedia.org/wiki/Category:Boulevards_in_Paris +// const category = document.querySelector('.mw-category'); +// const links = Array.from(category.querySelectorAll('a')); +// const de = links.map(link => link.textContent).filter(streetName => streetName.includes('de')); +// console.table(de); + +// 7. sort Exercise +// Sort the people alphabetically by last name +const alpha = people.sort((personA, personB) => { + const [lastA, firstA] = personA.split(', '); + const [lastB, firstB] = personB.split(', '); + return lastA > lastB ? 1 : -1; +}); +console.table(alpha); + + +// 8. Reduce Exercise +// Sum up the instances of each of these +const data = ['car', 'car', 'truck', 'truck', 'bike', 'walk', 'car', 'van', 'bike', 'walk', 'car', 'van', 'car', 'truck']; + +const transportation = data.reduce((obj, item) => { + if (!obj[item]) { + obj[item] = 1; + } else { + obj[item]++; + } + return obj; +}, {}); +console.log(transportation); From df26f0af2dff62b4cffb7bb954654742da1caf6f Mon Sep 17 00:00:00 2001 From: William Wager Date: Mon, 24 Feb 2020 12:28:14 -0500 Subject: [PATCH 06/34] Flex Panel (5) complete --- 05 - Flex Panel Gallery/index-START.html | 81 ++++++++++++++++++------ 05 - Flex Panel Gallery/typescripts.js | 11 ++++ 05 - Flex Panel Gallery/typescripts.ts | 25 ++++++++ 3 files changed, 97 insertions(+), 20 deletions(-) create mode 100644 05 - Flex Panel Gallery/typescripts.js create mode 100644 05 - Flex Panel Gallery/typescripts.ts diff --git a/05 - Flex Panel Gallery/index-START.html b/05 - Flex Panel Gallery/index-START.html index 71d1c26f00..1078fac50b 100644 --- a/05 - Flex Panel Gallery/index-START.html +++ b/05 - Flex Panel Gallery/index-START.html @@ -1,10 +1,12 @@ + Flex Panels 💪 + @@ -104,11 +148,8 @@
- - - + - + + \ No newline at end of file diff --git a/05 - Flex Panel Gallery/typescripts.js b/05 - Flex Panel Gallery/typescripts.js new file mode 100644 index 0000000000..636de483e4 --- /dev/null +++ b/05 - Flex Panel Gallery/typescripts.js @@ -0,0 +1,11 @@ +var panels = document.querySelectorAll('.panel'); +function toggleOpen() { + this.classList.toggle('open'); +} +function toggleActive(e) { + if (e.propertyName.includes('flex')) { + this.classList.toggle('open-active'); + } +} +panels.forEach(function (panel) { return panel.addEventListener('click', toggleOpen); }); +panels.forEach(function (panel) { return panel.addEventListener('transitionend', toggleActive); }); diff --git a/05 - Flex Panel Gallery/typescripts.ts b/05 - Flex Panel Gallery/typescripts.ts new file mode 100644 index 0000000000..6792dc6615 --- /dev/null +++ b/05 - Flex Panel Gallery/typescripts.ts @@ -0,0 +1,25 @@ +/** + * JavaScript30 by Wes Bos, https://javascript30.com/ + * TypeScript implementation by Will Wager + * Project: Flex Panel Gallery + * Concepts: Flexbox + * Key takeaways: Leaning on CSS, nesting flexboxes, , using classList.toggle + * Sidenotes: + * Exaggerated cubic bezier transition can add a nice touch. + * TransitionEndEvent.propertyName can be used to determine which transition triggered the event. + */ + +const panels = document.querySelectorAll('.panel'); + +function toggleOpen() { + this.classList.toggle('open'); +} + +function toggleActive(e) { + if (e.propertyName.includes('flex')) { + this.classList.toggle('open-active'); + } +} + +panels.forEach(panel => panel.addEventListener('click', toggleOpen)); +panels.forEach(panel => panel.addEventListener('transitionend', toggleActive)); From bcbab53592be0d8a1b6d441fb21227774d6ea347 Mon Sep 17 00:00:00 2001 From: William Wager Date: Mon, 24 Feb 2020 20:57:50 -0500 Subject: [PATCH 07/34] Project 6 complete with more strict tsc flags --- 06 - Type Ahead/index-START.html | 10 ++--- 06 - Type Ahead/typescripts.js | 39 +++++++++++++++++++ 06 - Type Ahead/typescripts.ts | 66 ++++++++++++++++++++++++++++++++ readme.md | 2 +- 4 files changed, 111 insertions(+), 6 deletions(-) create mode 100644 06 - Type Ahead/typescripts.js create mode 100644 06 - Type Ahead/typescripts.ts diff --git a/06 - Type Ahead/index-START.html b/06 - Type Ahead/index-START.html index 109c90fb36..2f1403b888 100644 --- a/06 - Type Ahead/index-START.html +++ b/06 - Type Ahead/index-START.html @@ -1,10 +1,12 @@ + Type Ahead 👀 +
@@ -14,9 +16,7 @@
  • or a state
  • - + - + + \ No newline at end of file diff --git a/06 - Type Ahead/typescripts.js b/06 - Type Ahead/typescripts.js new file mode 100644 index 0000000000..817ffb3c83 --- /dev/null +++ b/06 - Type Ahead/typescripts.js @@ -0,0 +1,39 @@ +var endpoint = 'https://gist.githubusercontent.com/Miserlou/c5cd8364bf9b2420bb29/raw/2bf258763cdddd704f8ffd3ea9a3e81d25e2c6f6/cities.json'; +var cities = []; +fetch(endpoint) + .then(function (blob) { return blob.json(); }) + .then(function (data) { return cities.push.apply(cities, data); }); +function findMatches(wordToMatch, cities) { + return cities.filter(function (place) { + var regexp = new RegExp(wordToMatch, 'gi'); + return place.city.match(regexp) || place.state.match(regexp); + }); +} +function numberWithCommas(x) { + return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ','); +} +function displayMatches() { + var _this = this; + var matchArray = findMatches(this.value, cities); + var html = matchArray.map(function (place) { + var regexp = new RegExp(_this.value, 'gi'); + var cityName = place.city.replace(regexp, "" + _this.value + ""); + var stateName = place.state.replace(regexp, "" + _this.value + ""); + return ("\n
  • \n " + cityName + ", " + stateName + "\n " + numberWithCommas(place.population) + "\n
  • \n "); + }).join(''); + if (suggestions) { + suggestions.innerHTML = html; + } + else { + throw new Error('Suggestions block not found'); + } +} +var searchInput = document.querySelector('.search'); +var suggestions = document.querySelector('.suggestions'); +if (searchInput) { + searchInput.addEventListener('change', displayMatches); + searchInput.addEventListener('keyup', displayMatches); +} +else { + throw new Error('Search input not found'); +} diff --git a/06 - Type Ahead/typescripts.ts b/06 - Type Ahead/typescripts.ts new file mode 100644 index 0000000000..aa64c616f6 --- /dev/null +++ b/06 - Type Ahead/typescripts.ts @@ -0,0 +1,66 @@ +/** + * JavaScript30 by Wes Bos, https://javascript30.com/ + * TypeScript implementation by Will Wager + * Project: Type Ahead + * Concepts: AJAX, Fetch API + * Key takeaways: Get the data first, then worry about displaying it. + * Sidenotes: + * Fetch API uses Promises. + * I've no idea how that comma adding regexp works... + */ + +interface City { + city: string; + state: string; + population: number; +} + +const endpoint = 'https://gist.githubusercontent.com/Miserlou/c5cd8364bf9b2420bb29/raw/2bf258763cdddd704f8ffd3ea9a3e81d25e2c6f6/cities.json'; + +const cities: City[] = []; + +fetch(endpoint) + .then(blob => blob.json()) + .then(data => cities.push(...(data as City[]))); + +function findMatches(wordToMatch: string, cities: City[]) { + return cities.filter(place => { + const regexp = new RegExp(wordToMatch, 'gi'); + return place.city.match(regexp) || place.state.match(regexp); + }); +} + +function numberWithCommas(x: number) { + return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ','); +} + +function displayMatches() { + const matchArray = findMatches(this.value, cities); + const html = matchArray.map(place => { + const regexp = new RegExp(this.value, 'gi'); + const cityName = place.city.replace(regexp, `${this.value}`); + const stateName = place.state.replace(regexp, `${this.value}`); + return (` +
  • + ${cityName}, ${stateName} + ${numberWithCommas(place.population)} +
  • + `); + }).join(''); + + if (suggestions) { + suggestions.innerHTML = html; + } else { + throw new Error('Suggestions block not found'); + } +} + +const searchInput = document.querySelector('.search'); +const suggestions = document.querySelector('.suggestions'); + +if (searchInput) { + searchInput.addEventListener('change', displayMatches); + searchInput.addEventListener('keyup', displayMatches); +} else { + throw new Error('Search input not found'); +} diff --git a/readme.md b/readme.md index c2d9ea3a3d..173b746170 100644 --- a/readme.md +++ b/readme.md @@ -7,7 +7,7 @@ Run them yourself from a VS Code container! * Open in vscode and run `Remote Containers: Reopen in Container` from the command palette. * Build each TypeScript file with `tsc typescripts.ts` from each project's folder. * All html files have been adjusted to look for typescripts.js. - * I use the options `--target es5 --removeComments` in my js builds. + * Starting at project 6, I use the options `--removeComments --strictNullChecks --noImplicitAny --target es5 ` in my js builds. * Press ALT + L, ALT + O to start the Live Server extension and access the html files at http://localhost:5500 + the relative path. * For example, to open the first project, go to (replace spaces with '20%' if your browser complains): `http://localhost:5500/01%20-%20JavaScript%20Drum%20Kit/index-START.html` From a18d31191395862393ae1d4ce904a1190e264c1b Mon Sep 17 00:00:00 2001 From: William Wager Date: Mon, 24 Feb 2020 21:28:34 -0500 Subject: [PATCH 08/34] Completed project 6 --- 06 - Type Ahead/typescripts.ts | 2 +- 07 - Array Cardio Day 2/index-START.html | 37 ++------------ 07 - Array Cardio Day 2/typescripts.js | 33 +++++++++++++ 07 - Array Cardio Day 2/typescripts.ts | 62 ++++++++++++++++++++++++ 4 files changed, 101 insertions(+), 33 deletions(-) create mode 100644 07 - Array Cardio Day 2/typescripts.js create mode 100644 07 - Array Cardio Day 2/typescripts.ts diff --git a/06 - Type Ahead/typescripts.ts b/06 - Type Ahead/typescripts.ts index aa64c616f6..d4e6b1f3ab 100644 --- a/06 - Type Ahead/typescripts.ts +++ b/06 - Type Ahead/typescripts.ts @@ -5,7 +5,7 @@ * Concepts: AJAX, Fetch API * Key takeaways: Get the data first, then worry about displaying it. * Sidenotes: - * Fetch API uses Promises. + * Fetch API uses Promises, but --target es5 does not cause errors... * I've no idea how that comma adding regexp works... */ diff --git a/07 - Array Cardio Day 2/index-START.html b/07 - Array Cardio Day 2/index-START.html index 969566ff78..e01b5f7d77 100644 --- a/07 - Array Cardio Day 2/index-START.html +++ b/07 - Array Cardio Day 2/index-START.html @@ -1,41 +1,14 @@ + Array Cardio 💪💪 +

    Psst: have a look at the JavaScript Console 💁

    - + - + + \ No newline at end of file diff --git a/07 - Array Cardio Day 2/typescripts.js b/07 - Array Cardio Day 2/typescripts.js new file mode 100644 index 0000000000..f5c22efc7a --- /dev/null +++ b/07 - Array Cardio Day 2/typescripts.js @@ -0,0 +1,33 @@ +const people = [ + { name: 'Wes', year: 1988 }, + { name: 'Kait', year: 1986 }, + { name: 'Irv', year: 1970 }, + { name: 'Lux', year: 2015 } +]; +const comments = [ + { text: 'Love this!', id: 523423 }, + { text: 'Super good', id: 823423 }, + { text: 'You are the best', id: 2039842 }, + { text: 'Ramen is my fav food ever', id: 123523 }, + { text: 'Nice Nice Nice!', id: 542328 } +]; +const isAdults = people.some(person => { + const currentYear = (new Date()).getFullYear(); + return ((currentYear - person.year) >= 19); +}); +console.log({ isAdults }); +const allAdult = people.every(person => { + const currentYear = (new Date()).getFullYear(); + return ((currentYear - person.year) >= 19); +}); +console.log({ allAdult }); +const comment = comments.find(comment => comment.id === 823423); +console.log(comment); +console.table(comments); +const index = comments.findIndex(comment => comment.id === 823423); +console.log({ index }); +const newComments = [ + ...comments.slice(0, index), + ...comments.slice(index + 1) +]; +console.table(newComments); diff --git a/07 - Array Cardio Day 2/typescripts.ts b/07 - Array Cardio Day 2/typescripts.ts new file mode 100644 index 0000000000..02de9a79e5 --- /dev/null +++ b/07 - Array Cardio Day 2/typescripts.ts @@ -0,0 +1,62 @@ +/** + * JavaScript30 by Wes Bos, https://javascript30.com/ + * TypeScript implementation by Will Wager + * Project: Array Cardio 2 + * Concepts: Array builtins - some, every, find, findIndex + * Key takeaways: Practice, keep functions pure by spreads with slice instead of splice. + * Sidenotes: + * Log name and value of boolean with an object literal in .log + * Find is not in es5, so I had to use --target es6 + */ + +// ## Array Cardio Day 2 + +const people = [ + { name: 'Wes', year: 1988 }, + { name: 'Kait', year: 1986 }, + { name: 'Irv', year: 1970 }, + { name: 'Lux', year: 2015 } +]; + +const comments = [ + { text: 'Love this!', id: 523423 }, + { text: 'Super good', id: 823423 }, + { text: 'You are the best', id: 2039842 }, + { text: 'Ramen is my fav food ever', id: 123523 }, + { text: 'Nice Nice Nice!', id: 542328 } +]; + +// Some and Every Checks +// Array.prototype.some() // is at least one person 19 or older? +const isAdults = people.some(person => { + const currentYear = (new Date()).getFullYear(); + return ((currentYear - person.year) >= 19); +}); +console.log({ isAdults }); + +// Array.prototype.every() // is everyone 19 or older? +const allAdult = people.every(person => { + const currentYear = (new Date()).getFullYear(); + return ((currentYear - person.year) >= 19); +}); +console.log({ allAdult }); + +// Array.prototype.find() +// Find is like filter, but instead returns just the one you are looking for +// find the comment with the ID of 823423 +const comment = comments.find(comment => comment.id === 823423); +console.log(comment); + +// Array.prototype.findIndex() +// Find the comment with this ID +// delete the comment with the ID of 823423 +console.table(comments); + +const index = comments.findIndex(comment => comment.id === 823423); +console.log({ index }); + +const newComments = [ + ...comments.slice(0, index), + ...comments.slice(index + 1) +]; +console.table(newComments); \ No newline at end of file From 9b1eb992668de7f897718a6941e707680292722d Mon Sep 17 00:00:00 2001 From: William Wager Date: Mon, 24 Feb 2020 23:42:46 -0500 Subject: [PATCH 09/34] Project 8 complete --- 08 - Fun with HTML5 Canvas/index-START.html | 21 ++++--- 08 - Fun with HTML5 Canvas/typescripts.js | 46 +++++++++++++++ 08 - Fun with HTML5 Canvas/typescripts.ts | 62 +++++++++++++++++++++ 3 files changed, 120 insertions(+), 9 deletions(-) create mode 100644 08 - Fun with HTML5 Canvas/typescripts.js create mode 100644 08 - Fun with HTML5 Canvas/typescripts.ts diff --git a/08 - Fun with HTML5 Canvas/index-START.html b/08 - Fun with HTML5 Canvas/index-START.html index 9da9b5b3c5..f01bd75f84 100644 --- a/08 - Fun with HTML5 Canvas/index-START.html +++ b/08 - Fun with HTML5 Canvas/index-START.html @@ -1,19 +1,22 @@ + HTML5 Canvas + - - + - + + - + + \ No newline at end of file diff --git a/08 - Fun with HTML5 Canvas/typescripts.js b/08 - Fun with HTML5 Canvas/typescripts.js new file mode 100644 index 0000000000..138d468599 --- /dev/null +++ b/08 - Fun with HTML5 Canvas/typescripts.js @@ -0,0 +1,46 @@ +var canvas = document.querySelector('#draw'); +var ctx = canvas.getContext('2d'); +canvas.width = window.innerWidth; +canvas.height = window.innerHeight; +ctx.strokeStyle = '#BADA55'; +ctx.lineJoin = 'round'; +ctx.lineCap = 'round'; +ctx.lineWidth = 100; +ctx.globalCompositeOperation = 'multiply'; +var isDrawing = false; +var lastX = 0; +var lastY = 0; +var hue = 0; +var direction = true; +function draw(e) { + if (!isDrawing) + return; + ctx.strokeStyle = "hsl(" + hue + ", 100%, 50%)"; + ctx.beginPath(); + ctx.moveTo(lastX, lastY); + ctx.lineTo(e.offsetX, e.offsetY); + ctx.stroke(); + lastX = e.offsetX; + lastY = e.offsetY; + hue++; + if (hue >= 360) { + hue = 0; + } + if (ctx.lineWidth >= 100 || ctx.lineWidth <= 1) { + direction = !direction; + } + if (direction) { + ctx.lineWidth++; + } + else { + ctx.lineWidth--; + } +} +canvas.addEventListener('mousemove', draw); +canvas.addEventListener('mousedown', function (e) { + isDrawing = true; + lastX = e.offsetX; + lastY = e.offsetY; +}); +canvas.addEventListener('mouseup', function () { return isDrawing = false; }); +canvas.addEventListener('mouseout', function () { return isDrawing = false; }); diff --git a/08 - Fun with HTML5 Canvas/typescripts.ts b/08 - Fun with HTML5 Canvas/typescripts.ts new file mode 100644 index 0000000000..7b658e957b --- /dev/null +++ b/08 - Fun with HTML5 Canvas/typescripts.ts @@ -0,0 +1,62 @@ +/** + * JavaScript30 by Wes Bos, https://javascript30.com/ + * TypeScript implementation by Will Wager + * Project: Fun with HTML5 Canvas + * Concepts: Canvas, 2d context, HSL + * Key takeaways: 2d context API, isDrawing pattern, direction pattern + * Sidenotes: The ! after querySelector caused the inferred type to be Element + * instead of HTMLCanvasElement, so I needed to add 'as HTMLCanvasElement' + * Compilation command: + * tsc --removeComments --strictNullChecks --noImplicitAny --target es5 typescripts.ts + */ + +const canvas: HTMLCanvasElement = document.querySelector('#draw')! as HTMLCanvasElement; +const ctx = canvas.getContext('2d')!; + +canvas.width = window.innerWidth; +canvas.height = window.innerHeight; + +ctx.strokeStyle = '#BADA55'; +ctx.lineJoin = 'round'; +ctx.lineCap = 'round'; +ctx.lineWidth = 100; +ctx.globalCompositeOperation = 'multiply'; + +let isDrawing = false; +let lastX = 0; +let lastY = 0; +let hue = 0; +let direction = true; + +function draw(e: MouseEvent) { + if (!isDrawing) return; + ctx.strokeStyle = `hsl(${hue}, 100%, 50%)`; + ctx.beginPath(); + ctx.moveTo(lastX, lastY); + ctx.lineTo(e.offsetX, e.offsetY); + ctx.stroke(); + lastX = e.offsetX; + lastY = e.offsetY; + hue++; + if (hue >= 360) { + hue = 0; + } + + if (ctx.lineWidth >= 100 || ctx.lineWidth <= 1) { + direction = !direction; + } + if (direction) { + ctx.lineWidth++; + } else { + ctx.lineWidth--; + } +} + +canvas.addEventListener('mousemove', draw); +canvas.addEventListener('mousedown', e => { + isDrawing = true; + lastX = e.offsetX; + lastY = e.offsetY; +}); +canvas.addEventListener('mouseup', () => isDrawing = false); +canvas.addEventListener('mouseout', () => isDrawing = false); \ No newline at end of file From 80c172966c7cf87ad11f0193a5eb5b325c059a40 Mon Sep 17 00:00:00 2001 From: William Wager Date: Tue, 25 Feb 2020 10:49:50 -0500 Subject: [PATCH 10/34] Project 9 complete --- 09 - Dev Tools Domination/index-START.html | 40 ++--------- 09 - Dev Tools Domination/typescripts.js | 41 +++++++++++ 09 - Dev Tools Domination/typescripts.ts | 82 ++++++++++++++++++++++ 3 files changed, 128 insertions(+), 35 deletions(-) create mode 100644 09 - Dev Tools Domination/typescripts.js create mode 100644 09 - Dev Tools Domination/typescripts.ts diff --git a/09 - Dev Tools Domination/index-START.html b/09 - Dev Tools Domination/index-START.html index 196fffd719..9b88a69ffa 100644 --- a/09 - Dev Tools Domination/index-START.html +++ b/09 - Dev Tools Domination/index-START.html @@ -1,46 +1,16 @@ + Console Tricks! +

    ×BREAK×DOWN×

    - + - + + \ No newline at end of file diff --git a/09 - Dev Tools Domination/typescripts.js b/09 - Dev Tools Domination/typescripts.js new file mode 100644 index 0000000000..b796211b7d --- /dev/null +++ b/09 - Dev Tools Domination/typescripts.js @@ -0,0 +1,41 @@ +var dogs = [{ name: 'Snickers', age: 2 }, { name: 'hugo', age: 8 }]; +function makeGreen() { + var p = document.querySelector('p'); + debugger; + p.style.color = '#BADA55'; + p.style.fontSize = '50px'; +} +console.clear(); +console.log('hello'); +console.log('Hello, I am a %s string', '💩'); +console.log('%c I am some great text', 'font-size: 50px; background-color: red; text-shadow: 2px 2px 4px blue;'); +console.warn('OH NOOO'); +console.error('Shoot!'); +console.info('Crocodiles eat 3-4 people per year'); +var p = document.querySelector('p'); +console.assert(p.classList.contains('ouch'), 'That is wrong!'); +console.log(p); +dogs.forEach(function (dog) { + console.groupCollapsed("This is " + dog.name); + console.log(dog.name + " is " + dog.age + " years old."); + console.log(dog.name + " is " + dog.age * 7 + " dog years old"); + console.groupEnd(); +}); +console.count('Will'); +console.count('Will'); +console.count('Will'); +console.count('Wags'); +console.count('Will'); +console.count('Wags'); +console.count('Will'); +console.count('Wags'); +console.count('Wags'); +console.count('Wags'); +console.time('fetching data'); +fetch('https://api.github.com/users/wwags33') + .then(function (data) { return data.json(); }) + .then(function (data) { + console.timeEnd('fetching data'); + console.log(data); +}); +console.table(dogs); diff --git a/09 - Dev Tools Domination/typescripts.ts b/09 - Dev Tools Domination/typescripts.ts new file mode 100644 index 0000000000..f0ce355406 --- /dev/null +++ b/09 - Dev Tools Domination/typescripts.ts @@ -0,0 +1,82 @@ +/** + * JavaScript30 by Wes Bos, https://javascript30.com/ + * TypeScript implementation by Will Wager + * Project: Dev Tools Domination + * Concepts: Console methods + * Key takeaways: Lots of options to log effectively; grouping, counting, and timing is simple + * Sidenotes: DOM Mutation Breakpoints did not work for me in Firefox on Linux, but the debugger command does. + * Compilation command: + * tsc --removeComments --strictNullChecks --noImplicitAny --target es5 typescripts.ts + */ +const dogs = [{ name: 'Snickers', age: 2 }, { name: 'hugo', age: 8 }]; + +function makeGreen() { + const p = document.querySelector('p')!; + debugger; // Adds a breakpoint in the code. + p.style.color = '#BADA55'; + p.style.fontSize = '50px'; +} + +console.clear(); +// Regular +console.log('hello'); + +// Interpolated +console.log('Hello, I am a %s string', '💩'); + +// Styled +console.log('%c I am some great text', 'font-size: 50px; background-color: red; text-shadow: 2px 2px 4px blue;'); + +// warning! +console.warn('OH NOOO'); + +// Error :| +console.error('Shoot!'); + +// Info +console.info('Crocodiles eat 3-4 people per year'); + +// Testing +const p = document.querySelector('p')!; + +console.assert(p.classList.contains('ouch'), 'That is wrong!'); + +// clearing +// console.clear(); + +// Viewing DOM Elements +console.log(p); +// console.dir(p); + +// Grouping together +dogs.forEach(dog => { + console.groupCollapsed(`This is ${dog.name}`); + console.log(`${dog.name} is ${dog.age} years old.`); + console.log(`${dog.name} is ${dog.age * 7} dog years old`); + console.groupEnd(); +}); + +// counting +console.count('Will'); +console.count('Will'); + +console.count('Will'); +console.count('Wags'); +console.count('Will'); +console.count('Wags'); +console.count('Will'); +console.count('Wags'); +console.count('Wags'); +console.count('Wags'); + + +// timing +console.time('fetching data'); +fetch('https://api.github.com/users/wwags33') + .then(data => data.json()) + .then(data => { + console.timeEnd('fetching data'); + console.log(data); + }); + +console.table(dogs); From 49ab32b8eff484c37b8007a926d194572dee1b60 Mon Sep 17 00:00:00 2001 From: William Wager Date: Tue, 25 Feb 2020 11:12:35 -0500 Subject: [PATCH 11/34] Project 10 complete --- .../index-START.html | 17 +++++---- .../typescripts.js | 20 ++++++++++ .../typescripts.ts | 37 +++++++++++++++++++ 3 files changed, 66 insertions(+), 8 deletions(-) create mode 100644 10 - Hold Shift and Check Checkboxes/typescripts.js create mode 100644 10 - Hold Shift and Check Checkboxes/typescripts.ts diff --git a/10 - Hold Shift and Check Checkboxes/index-START.html b/10 - Hold Shift and Check Checkboxes/index-START.html index 4fd2936ddc..810748048b 100644 --- a/10 - Hold Shift and Check Checkboxes/index-START.html +++ b/10 - Hold Shift and Check Checkboxes/index-START.html @@ -1,12 +1,13 @@ + Hold Shift to Check Multiple Checkboxes + - - + + + + + + + + + +

    LOCAL TAPAS

    @@ -21,18 +38,46 @@

    LOCAL TAPAS

    - + + + +
    - + - + \ No newline at end of file diff --git a/15 - LocalStorage/typescripts.js b/15 - LocalStorage/typescripts.js new file mode 100644 index 0000000000..65e252e60c --- /dev/null +++ b/15 - LocalStorage/typescripts.js @@ -0,0 +1,54 @@ +var addItems = document.querySelector('.add-items'); +var itemsList = document.querySelector('.plates'); +var items = JSON.parse(localStorage.getItem('items')) || []; +function populateList(plates, platesList) { + if (plates === void 0) { plates = []; } + platesList.innerHTML = plates.map(function (plate, i) { + return "\n
  • \n \n \n
  • \n "; + }).join(''); +} +function addItem(e) { + e.preventDefault(); + var text = (this.querySelector('[name="item"]')).value; + var item = { + text: text, + done: false, + }; + items.push(item); + populateList(items, itemsList); + localStorage.setItem('items', JSON.stringify(items)); + this.reset(); +} +addItems.addEventListener('submit', addItem); +function toggleDone(e) { + var el = e.target; + if (el.matches('input')) { + var index = Number(el.dataset.index); + items[index].done = !items[index].done; + localStorage.setItem('items', JSON.stringify(items)); + populateList(items, itemsList); + } +} +itemsList.addEventListener('click', toggleDone); +var clearBtn = document.querySelector('.clear'); +var checkAllBtn = document.querySelector('.check'); +var uncheckAllBtn = document.querySelector('.uncheck'); +function clearItems() { + items.length = 0; + localStorage.setItem('items', JSON.stringify(items)); + populateList(items, itemsList); +} +function checkAllItems() { + items.forEach(function (item) { return item.done = true; }); + localStorage.setItem('items', JSON.stringify(items)); + populateList(items, itemsList); +} +function uncheckAllItems() { + items.forEach(function (item) { return item.done = false; }); + localStorage.setItem('items', JSON.stringify(items)); + populateList(items, itemsList); +} +clearBtn.addEventListener('click', clearItems); +checkAllBtn.addEventListener('click', checkAllItems); +uncheckAllBtn.addEventListener('click', uncheckAllItems); +populateList(items, itemsList); diff --git a/15 - LocalStorage/typescripts.ts b/15 - LocalStorage/typescripts.ts new file mode 100644 index 0000000000..e7fc3f4be7 --- /dev/null +++ b/15 - LocalStorage/typescripts.ts @@ -0,0 +1,90 @@ +/** + * JavaScript30 by Wes Bos, https://javascript30.com/ + * TypeScript implementation by Will Wager + * Project: LocalStorage + * Concepts: Browser local storage, event delegation + * Key takeaways: LocalStorage API, JSON.stringify and parse for arrays and objects, + * e.target to get the clicked child + * Sidenotes: Tried a neomorphism design... + * Compilation command: + * tsc --removeComments --strictNullChecks --noImplicitAny --target es5 typescripts.ts + */ + +interface Item { + text: string; + done: boolean; +} + +const addItems = document.querySelector('.add-items')! as HTMLFormElement; +const itemsList = document.querySelector('.plates')! as HTMLElement; +const items: Item[] = JSON.parse(localStorage.getItem('items')!) || []; + +function populateList(plates: Item[] = [], platesList: HTMLElement) { + platesList.innerHTML = plates.map((plate, i) => { + return ` +
  • + + +
  • + `; + }).join(''); +} + +function addItem(e: Event) { + e.preventDefault(); + const text = (this.querySelector('[name="item"]')).value; + const item = { + text, + done: false, + } + + items.push(item); + populateList(items, itemsList); + localStorage.setItem('items', JSON.stringify(items)); + this.reset(); +} + +addItems.addEventListener('submit', addItem); + + +function toggleDone(e: MouseEvent) { + const el = e.target! as HTMLLIElement; + if (el.matches('input')) { + const index = Number(el.dataset.index!); + items[index].done = !items[index].done; + localStorage.setItem('items', JSON.stringify(items)); + populateList(items, itemsList); + } +} + +itemsList.addEventListener('click', toggleDone); + + +const clearBtn = document.querySelector('.clear')! as HTMLButtonElement; +const checkAllBtn = document.querySelector('.check')! as HTMLButtonElement; +const uncheckAllBtn = document.querySelector('.uncheck')! as HTMLButtonElement; + +function clearItems() { + items.length = 0; + localStorage.setItem('items', JSON.stringify(items)); + populateList(items, itemsList); +} + +function checkAllItems() { + items.forEach(item => item.done = true); + localStorage.setItem('items', JSON.stringify(items)); + populateList(items, itemsList); +} + +function uncheckAllItems() { + items.forEach(item => item.done = false); + localStorage.setItem('items', JSON.stringify(items)); + populateList(items, itemsList); +} + +clearBtn.addEventListener('click', clearItems); +checkAllBtn.addEventListener('click', checkAllItems); +uncheckAllBtn.addEventListener('click', uncheckAllItems); + +// Init +populateList(items, itemsList); \ No newline at end of file From 0bfe58336fe5357ea60aea6be9f893098a2c1fe6 Mon Sep 17 00:00:00 2001 From: William Wager Date: Mon, 2 Mar 2020 17:26:13 -0500 Subject: [PATCH 17/34] Project 16 complete --- 16 - Mouse Move Shadow/index-START.html | 50 +++++++++++++------------ 16 - Mouse Move Shadow/typescripts.js | 16 ++++++++ 16 - Mouse Move Shadow/typescripts.ts | 40 ++++++++++++++++++++ 3 files changed, 82 insertions(+), 24 deletions(-) create mode 100644 16 - Mouse Move Shadow/typescripts.js create mode 100644 16 - Mouse Move Shadow/typescripts.ts diff --git a/16 - Mouse Move Shadow/index-START.html b/16 - Mouse Move Shadow/index-START.html index 280a4907c2..61a1527d67 100644 --- a/16 - Mouse Move Shadow/index-START.html +++ b/16 - Mouse Move Shadow/index-START.html @@ -1,9 +1,11 @@ + Mouse Shadow +
    @@ -11,30 +13,30 @@

    🔥WOAH!

    - + - + + \ No newline at end of file diff --git a/16 - Mouse Move Shadow/typescripts.js b/16 - Mouse Move Shadow/typescripts.js new file mode 100644 index 0000000000..25f2ec0729 --- /dev/null +++ b/16 - Mouse Move Shadow/typescripts.js @@ -0,0 +1,16 @@ +var hero = document.querySelector('.hero'); +var text = hero.querySelector('h1'); +var maxWalk = 200; +function shadow(e) { + var target = e.target; + var x = e.offsetX, y = e.offsetY; + var width = hero.offsetWidth, height = hero.offsetHeight; + if (target && this !== e.target) { + x = x + target.offsetLeft; + y = y + target.offsetTop; + } + var xWalk = Math.round((x / width * maxWalk) - (maxWalk / 2)); + var yWalk = Math.round((y / height * maxWalk) - (maxWalk / 2)); + text.style.textShadow = "\n " + xWalk + "px " + yWalk + "px 2px red,\n " + -xWalk + "px " + -yWalk + "px 2px blue,\n " + yWalk + "px " + xWalk + "px 2px green,\n " + -yWalk + "px " + -xWalk + "px 2px green\n "; +} +hero.addEventListener('mousemove', shadow); diff --git a/16 - Mouse Move Shadow/typescripts.ts b/16 - Mouse Move Shadow/typescripts.ts new file mode 100644 index 0000000000..5f1e9517be --- /dev/null +++ b/16 - Mouse Move Shadow/typescripts.ts @@ -0,0 +1,40 @@ +/** + * JavaScript30 by Wes Bos, https://javascript30.com/ + * TypeScript implementation by Will Wager + * Project: Mouse Move Shadow + * Concepts: CSS text-shadow, mouse position + * Key takeaways: offset(X|Y), offsetWidth(X|Y), offset(Top|Right|Bottom|Left); + * calculating walk + * Sidenotes: Walk is a "normalized" representation of the distance between + * the mouse and the center of the element. + * Compilation command: + * tsc --removeComments --strictNullChecks --noImplicitAny --target es5 typescripts.ts + */ + +const hero = document.querySelector('.hero')! as HTMLDivElement; +const text = hero.querySelector('h1')! as HTMLHeadingElement; +const maxWalk = 200; + +function shadow(e: MouseEvent) { + const target = e.target! as HTMLElement; + + // Get accurate mouse position + let { offsetX: x, offsetY: y } = e; + const { offsetWidth: width, offsetHeight: height } = hero; + if (target && this !== e.target) { + x = x + target.offsetLeft; + y = y + target.offsetTop; + } + + const xWalk = Math.round((x / width * maxWalk) - (maxWalk / 2)); + const yWalk = Math.round((y / height * maxWalk) - (maxWalk / 2)); + + text.style.textShadow = ` + ${xWalk}px ${yWalk}px 2px red, + ${-xWalk}px ${-yWalk}px 2px blue, + ${yWalk}px ${xWalk}px 2px green, + ${-yWalk}px ${-xWalk}px 2px green + `; +} + +hero.addEventListener('mousemove', shadow); \ No newline at end of file From b43d30474b1e716cb84018d7773d3567f3bf8459 Mon Sep 17 00:00:00 2001 From: William Wager Date: Tue, 3 Mar 2020 09:42:40 -0500 Subject: [PATCH 18/34] Project 17 complete --- 17 - Sort Without Articles/index-START.html | 16 +++++++--------- 17 - Sort Without Articles/typescripts.js | 6 ++++++ 17 - Sort Without Articles/typescripts.ts | 19 +++++++++++++++++++ 3 files changed, 32 insertions(+), 9 deletions(-) create mode 100644 17 - Sort Without Articles/typescripts.js create mode 100644 17 - Sort Without Articles/typescripts.ts diff --git a/17 - Sort Without Articles/index-START.html b/17 - Sort Without Articles/index-START.html index 2b6c9546e9..227eb9a337 100644 --- a/17 - Sort Without Articles/index-START.html +++ b/17 - Sort Without Articles/index-START.html @@ -1,9 +1,11 @@ + Sort Without Articles +
      - + - + + \ No newline at end of file diff --git a/17 - Sort Without Articles/typescripts.js b/17 - Sort Without Articles/typescripts.js new file mode 100644 index 0000000000..8b56b446d2 --- /dev/null +++ b/17 - Sort Without Articles/typescripts.js @@ -0,0 +1,6 @@ +var bands = ['The Plot in You', 'The Devil Wears Prada', 'Pierce the Veil', 'Norma Jean', 'The Bled', 'Say Anything', 'The Midway State', 'We Came as Romans', 'Counterparts', 'Oh, Sleeper', 'A Skylit Drive', 'Anywhere But Here', 'An Old Dog']; +var articleRegExp = /^(a |the |an )/i; +var sortedBands = bands.sort(function (a, b) { + return a.replace(articleRegExp, '').trim() > b.replace(articleRegExp, '').trim() ? 1 : -1; +}); +document.querySelector('#bands').innerHTML = sortedBands.map(function (band) { return "
    • " + band + "
    • "; }).join(''); diff --git a/17 - Sort Without Articles/typescripts.ts b/17 - Sort Without Articles/typescripts.ts new file mode 100644 index 0000000000..0a5fc14df8 --- /dev/null +++ b/17 - Sort Without Articles/typescripts.ts @@ -0,0 +1,19 @@ +/** + * JavaScript30 by Wes Bos, https://javascript30.com/ + * TypeScript implementation by Will Wager + * Project: Sort Without Articles + * Concepts: Sort function comparator + * Key takeaways: Sort is easy to customize + * Sidenotes: Comparator should return 1 if a should go after b, or -1 if before; 0 if equal. + * Compilation command: + * tsc --removeComments --strictNullChecks --noImplicitAny --target es5 typescripts.ts + */ + +const bands = ['The Plot in You', 'The Devil Wears Prada', 'Pierce the Veil', 'Norma Jean', 'The Bled', 'Say Anything', 'The Midway State', 'We Came as Romans', 'Counterparts', 'Oh, Sleeper', 'A Skylit Drive', 'Anywhere But Here', 'An Old Dog']; +const articleRegExp = /^(a |the |an )/i; + +const sortedBands = bands.sort((a, b) => { + return a.replace(articleRegExp, '').trim() > b.replace(articleRegExp, '').trim() ? 1 : -1; +}); + +document.querySelector('#bands')!.innerHTML = sortedBands.map(band => `
    • ${band}
    • `).join(''); From c2489d9547a934ecfe21839a7c60a7f89772bb16 Mon Sep 17 00:00:00 2001 From: William Wager Date: Tue, 3 Mar 2020 10:57:59 -0500 Subject: [PATCH 19/34] Project 18 complete --- .../index-START.html | 8 ++-- .../typescripts.js | 25 ++++++++++++ .../typescripts.ts | 39 +++++++++++++++++++ 3 files changed, 69 insertions(+), 3 deletions(-) create mode 100644 18 - Adding Up Times with Reduce/typescripts.js create mode 100644 18 - Adding Up Times with Reduce/typescripts.ts diff --git a/18 - Adding Up Times with Reduce/index-START.html b/18 - Adding Up Times with Reduce/index-START.html index abdf4c91af..894acdf2c8 100644 --- a/18 - Adding Up Times with Reduce/index-START.html +++ b/18 - Adding Up Times with Reduce/index-START.html @@ -1,9 +1,11 @@ + Videos +
      • @@ -181,7 +183,7 @@ Video 58
      - + - + + \ No newline at end of file diff --git a/18 - Adding Up Times with Reduce/typescripts.js b/18 - Adding Up Times with Reduce/typescripts.js new file mode 100644 index 0000000000..ea049adf13 --- /dev/null +++ b/18 - Adding Up Times with Reduce/typescripts.js @@ -0,0 +1,25 @@ +const timeNodes = Array.from(document.querySelectorAll('[data-time]')); +console.time('map and reduce'); +const seconds = timeNodes + .map((node) => node.dataset.time) + .map(timeCode => { + if (!timeCode) + return 0; + const [mins, secs] = timeCode.split(':').map(Number); + return (mins * 60) + secs; +}) + .reduce((total, vidSeconds) => total + vidSeconds); +console.timeEnd('map and reduce'); +let secondsLeft = seconds; +const hours = Math.floor(secondsLeft / 3600); +secondsLeft = secondsLeft % 3600; +const minutes = Math.floor(secondsLeft / 60); +secondsLeft = secondsLeft % 60; +console.log(`Map and reduce: ${hours}:${minutes}:${secondsLeft}`); +console.time('just reduce'); +const redSeconds = timeNodes.reduce((totalSeconds, node) => { + const [mins, secs] = node.dataset.time.split(':').map(Number); + return totalSeconds + mins * 60 + secs; +}, 0); +console.timeEnd('just reduce'); +console.log(`Just reduce: ${Math.floor(redSeconds / 3600)}:${Math.floor((redSeconds % 3600) / 60)}:${redSeconds % 60}`); diff --git a/18 - Adding Up Times with Reduce/typescripts.ts b/18 - Adding Up Times with Reduce/typescripts.ts new file mode 100644 index 0000000000..601c14fa58 --- /dev/null +++ b/18 - Adding Up Times with Reduce/typescripts.ts @@ -0,0 +1,39 @@ +/** + * JavaScript30 by Wes Bos, https://javascript30.com/ + * TypeScript implementation by Will Wager + * Project: Adding up times with reduce + * Concepts: Map, reduce, calculating times + * Key takeaways: Mapping step by step can be more readable, but combining + * into a single map or reduce is less expensive. + * Sidenotes: Targeted es6 to get Array.from + * Compilation command: + * tsc --removeComments --strictNullChecks --noImplicitAny --target es6 typescripts.ts + */ + +const timeNodes = Array.from(document.querySelectorAll('[data-time]')); +console.time('map and reduce'); +const seconds = timeNodes + .map((node: HTMLElement) => node.dataset.time) + .map(timeCode => { + if (!timeCode) return 0; + const [mins, secs] = timeCode.split(':').map(Number); + return (mins * 60) + secs; + }) + .reduce((total, vidSeconds) => total + vidSeconds); +console.timeEnd('map and reduce'); + +let secondsLeft = seconds; +const hours = Math.floor(secondsLeft / 3600); +secondsLeft = secondsLeft % 3600; +const minutes = Math.floor(secondsLeft / 60); +secondsLeft = secondsLeft % 60; +console.log(`Map and reduce: ${hours}:${minutes}:${secondsLeft}`); + + +console.time('just reduce'); +const redSeconds = timeNodes.reduce((totalSeconds: number, node: HTMLElement) => { + const [mins, secs] = node.dataset.time!.split(':').map(Number); + return totalSeconds + mins * 60 + secs; +}, 0); +console.timeEnd('just reduce'); +console.log(`Just reduce: ${Math.floor(redSeconds / 3600)}:${Math.floor((redSeconds % 3600) / 60)}:${redSeconds % 60}`); From ca99b4e8dffcd76ab0a2c9370ef270469c901752 Mon Sep 17 00:00:00 2001 From: William Wager Date: Tue, 3 Mar 2020 13:40:50 -0500 Subject: [PATCH 20/34] Project 19 complete --- 19 - Webcam Fun/index.html | 11 ++-- 19 - Webcam Fun/typescripts.js | 80 +++++++++++++++++++++++ 19 - Webcam Fun/typescripts.ts | 114 +++++++++++++++++++++++++++++++++ 3 files changed, 201 insertions(+), 4 deletions(-) create mode 100644 19 - Webcam Fun/typescripts.js create mode 100644 19 - Webcam Fun/typescripts.ts diff --git a/19 - Webcam Fun/index.html b/19 - Webcam Fun/index.html index 682192dbb5..bf874bf765 100755 --- a/19 - Webcam Fun/index.html +++ b/19 - Webcam Fun/index.html @@ -1,16 +1,18 @@ + Get User Media Code Along! +
      - +
      @@ -39,7 +41,8 @@ - + - + + \ No newline at end of file diff --git a/19 - Webcam Fun/typescripts.js b/19 - Webcam Fun/typescripts.js new file mode 100644 index 0000000000..c6cc90b6e1 --- /dev/null +++ b/19 - Webcam Fun/typescripts.js @@ -0,0 +1,80 @@ +var video = document.querySelector('.player'); +var canvas = document.querySelector('.photo'); +var ctx = canvas.getContext('2d'); +var strip = document.querySelector('.strip'); +var snap = document.querySelector('.snap'); +function redEffect(pixels) { + for (var i = 0; i < pixels.data.length; i += 4) { + pixels.data[i + 0] += 100; + pixels.data[i + 1] += -50; + pixels.data[i + 2] *= 0.5; + } + return pixels; +} +function rgbSplit(pixels) { + for (var i = 0; i < pixels.data.length; i += 4) { + pixels.data[i - 150] = pixels.data[i + 0]; + pixels.data[i + 100] = pixels.data[i + 1]; + pixels.data[i - 150] = pixels.data[i + 2]; + } + return pixels; +} +function greenScreen(pixels) { + var levels = {}; + var inputs = document.querySelectorAll('.rgb input'); + if (!inputs) + return pixels; + inputs.forEach(function (input) { return levels[input.name] = Number(input.value); }); + for (var i = 0; i < pixels.data.length; i = i + 4) { + var red = pixels.data[i + 0]; + var green = pixels.data[i + 1]; + var blue = pixels.data[i + 2]; + if (red >= levels.rmin + && green >= levels.gmin + && blue >= levels.bmin + && red <= levels.rmax + && green <= levels.gmax + && blue <= levels.bmax) { + pixels.data[i + 3] = 0; + } + } + return pixels; +} +function paintToCanvas() { + var width = video.videoWidth; + var height = video.videoHeight; + canvas.width = width; + canvas.height = height; + function paintVideoLoop() { + if (!ctx) + return; + ctx.drawImage(video, 0, 0, width, height); + var pixels = ctx.getImageData(0, 0, width, height); + pixels = greenScreen(pixels); + ctx.putImageData(pixels, 0, 0); + requestAnimationFrame(paintVideoLoop); + } + paintVideoLoop(); +} +function getVideo() { + navigator.mediaDevices.getUserMedia({ video: true, audio: false }) + .then(function (localMediaStream) { + video.srcObject = localMediaStream; + video.onloadedmetadata = function () { + video.play(); + paintToCanvas(); + }; + }) + .catch(function (err) { return console.error("\uD83D\uDE2C I'm gonna need your webcam for this...", err); }); +} +getVideo(); +function takePhoto() { + snap.currentTime = 0; + snap.play(); + var data = canvas.toDataURL('image/jpeg'); + var link = document.createElement('a'); + link.href = data; + link.setAttribute('download', 'handsome'); + link.innerHTML = "\"Photo"; + strip.insertBefore(link, strip.firstChild); +} diff --git a/19 - Webcam Fun/typescripts.ts b/19 - Webcam Fun/typescripts.ts new file mode 100644 index 0000000000..4d8436e3c2 --- /dev/null +++ b/19 - Webcam Fun/typescripts.ts @@ -0,0 +1,114 @@ +/** + * JavaScript30 by Wes Bos, https://javascript30.com/ + * TypeScript implementation by Will Wager + * Project: Webcam fun + * Concepts: Accessing user media; Painting video to canvas; pixel manipulation + * Key takeaways: Pixel manipulation is straightforward with the ImageData object and a canvas; + * Create a download link with the download attribute + * Sidenotes: Small update was required to get the media stream to work (video.srcObject) + * Compilation command: + * tsc --removeComments --strictNullChecks --noImplicitAny --target es5 typescripts.ts + */ + +interface GreenScreenConfig { + [index: string]: number; +} + +const video = document.querySelector('.player') as HTMLVideoElement; +const canvas = document.querySelector('.photo') as HTMLCanvasElement; +const ctx = canvas.getContext('2d'); +const strip = document.querySelector('.strip')! as HTMLDivElement; +const snap = document.querySelector('.snap') as HTMLAudioElement; + +function redEffect(pixels: ImageData) { + for (let i = 0; i < pixels.data.length; i += 4) { + pixels.data[i + 0] += 100; + pixels.data[i + 1] += -50; + pixels.data[i + 2] *= 0.5; + } + return pixels; +} + +function rgbSplit(pixels: ImageData) { + for (let i = 0; i < pixels.data.length; i += 4) { + pixels.data[i - 150] = pixels.data[i + 0]; + pixels.data[i + 100] = pixels.data[i + 1]; + pixels.data[i - 150] = pixels.data[i + 2]; + } + return pixels; +} + +function greenScreen(pixels: ImageData) { + const levels: GreenScreenConfig = {}; + + const inputs = document.querySelectorAll('.rgb input'); + if (!inputs) return pixels; + inputs.forEach((input: HTMLInputElement) => levels[input.name] = Number(input.value)); + + for (let i = 0; i < pixels.data.length; i = i + 4) { + const red = pixels.data[i + 0]; + const green = pixels.data[i + 1]; + const blue = pixels.data[i + 2]; + + if ( + red >= levels.rmin + && green >= levels.gmin + && blue >= levels.bmin + && red <= levels.rmax + && green <= levels.gmax + && blue <= levels.bmax + ) { + pixels.data[i + 3] = 0; + } + } + + return pixels; +} + +function paintToCanvas() { + const width = video.videoWidth; + const height = video.videoHeight; + + canvas.width = width; + canvas.height = height; + + function paintVideoLoop() { + if (!ctx) return; + ctx.drawImage(video, 0, 0, width, height) + let pixels = ctx.getImageData(0, 0, width, height); + + // pixels = redEffect(pixels); + // pixels = rgbSplit(pixels); + // ctx.globalAlpha = 0.1; + pixels = greenScreen(pixels); + ctx.putImageData(pixels, 0, 0); + requestAnimationFrame(paintVideoLoop); + } + paintVideoLoop(); +} + +function getVideo() { + navigator.mediaDevices.getUserMedia({ video: true, audio: false }) + .then(localMediaStream => { + video.srcObject = localMediaStream; + video.onloadedmetadata = () => { + video.play(); + paintToCanvas(); + }; + }) + .catch(err => console.error(`😬 I'm gonna need your webcam for this...`, err)); +} +getVideo(); + +function takePhoto() { + snap.currentTime = 0; + snap.play(); + + const data = canvas.toDataURL('image/jpeg'); + const link = document.createElement('a'); + link.href = data; + link.setAttribute('download', 'handsome'); + link.innerHTML = `Photo booth photo`; + strip.insertBefore(link, strip.firstChild); +} + From c80c60327de68676c104816a5dad680851ede978 Mon Sep 17 00:00:00 2001 From: William Wager Date: Tue, 3 Mar 2020 17:52:03 -0500 Subject: [PATCH 21/34] Project 20 complete --- 20 - Speech Detection/index-START.html | 15 ++++----- 20 - Speech Detection/typescripts.js | 22 +++++++++++++ 20 - Speech Detection/typescripts.ts | 44 ++++++++++++++++++++++++++ 3 files changed, 73 insertions(+), 8 deletions(-) create mode 100644 20 - Speech Detection/typescripts.js create mode 100644 20 - Speech Detection/typescripts.ts diff --git a/20 - Speech Detection/index-START.html b/20 - Speech Detection/index-START.html index 31b4042563..7b543eb27d 100644 --- a/20 - Speech Detection/index-START.html +++ b/20 - Speech Detection/index-START.html @@ -1,19 +1,17 @@ + Speech Detection +
      - + - + + \ No newline at end of file diff --git a/20 - Speech Detection/typescripts.js b/20 - Speech Detection/typescripts.js new file mode 100644 index 0000000000..46919967c0 --- /dev/null +++ b/20 - Speech Detection/typescripts.js @@ -0,0 +1,22 @@ +window.SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition; +const recognition = new SpeechRecognition(); +recognition.interimResults = true; +let p = document.createElement('p'); +const words = document.querySelector('.words'); +words.appendChild(p); +recognition.addEventListener('result', e => { + const transcript = Array.from(e.results) + .map(result => result[0]) + .map(result => result.transcript) + .join(''); + p.textContent = transcript; + if (e.results[0].isFinal) { + p = document.createElement('p'); + words.appendChild(p); + if (transcript.includes('unicorn')) { + console.log('🦄🦄🦄🦄🦄🦄🦄'); + } + } +}); +recognition.addEventListener('end', recognition.start); +recognition.start(); diff --git a/20 - Speech Detection/typescripts.ts b/20 - Speech Detection/typescripts.ts new file mode 100644 index 0000000000..2780984d30 --- /dev/null +++ b/20 - Speech Detection/typescripts.ts @@ -0,0 +1,44 @@ +/** + * JavaScript30 by Wes Bos, https://javascript30.com/ + * TypeScript implementation by Will Wager + * Project: Speech Detection + * Concepts: Speech Recognition API + * Key takeaways: Chrome and Edge have native speech recognition; + * The transcript can be used to trigger any other actions. + * Sidenotes: es6 needed for Array.from; needed to extend window interface to add prefixed API. + * Compilation command: + * tsc --removeComments --strictNullChecks --noImplicitAny --target es6 typescripts.ts + */ + +interface Window { + webkitSpeechRecognition: any; +} + +window.SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition; + +const recognition = new SpeechRecognition(); +recognition.interimResults = true; + +let p = document.createElement('p'); +const words = document.querySelector('.words')! as HTMLDivElement; +words.appendChild(p); + +recognition.addEventListener('result', e => { + const transcript = Array.from(e.results) + .map(result => result[0]) + .map(result => result.transcript) + .join(''); + + p.textContent = transcript; + if (e.results[0].isFinal) { + p = document.createElement('p'); + words.appendChild(p); + if (transcript.includes('unicorn')) { + console.log('🦄🦄🦄🦄🦄🦄🦄'); + } + } +}); + +recognition.addEventListener('end', recognition.start); + +recognition.start(); \ No newline at end of file From de18ffa563df255cfe4aba654730601dbd294e7d Mon Sep 17 00:00:00 2001 From: William Wager Date: Tue, 3 Mar 2020 21:43:06 -0500 Subject: [PATCH 22/34] Geolocation project complete --- 21 - Geolocation/index-START.html | 35 +- 21 - Geolocation/package-lock.json | 4046 ++++++++++++++++++++++++++++ 21 - Geolocation/typescripts.js | 12 + 21 - Geolocation/typescripts.ts | 26 + 4 files changed, 4112 insertions(+), 7 deletions(-) create mode 100644 21 - Geolocation/package-lock.json create mode 100644 21 - Geolocation/typescripts.js create mode 100644 21 - Geolocation/typescripts.ts diff --git a/21 - Geolocation/index-START.html b/21 - Geolocation/index-START.html index 6d48c7a6d1..e9da837e9d 100644 --- a/21 - Geolocation/index-START.html +++ b/21 - Geolocation/index-START.html @@ -1,12 +1,32 @@ + Document + - + + + + + + + + + + + +

      @@ -18,7 +38,7 @@

      html { font-size: 100px; } - + body { margin: 0; font-family: sans-serif; @@ -30,8 +50,8 @@

      background: radial-gradient(black 15%, transparent 16%) 0 0, radial-gradient(black 15%, transparent 16%) 8px 8px, - radial-gradient(rgba(255,255,255,.1) 15%, transparent 20%) 0 1px, - radial-gradient(rgba(255,255,255,.1) 15%, transparent 20%) 8px 9px; + radial-gradient(rgba(255, 255, 255, .1) 15%, transparent 20%) 0 1px, + radial-gradient(rgba(255, 255, 255, .1) 15%, transparent 20%) 8px 9px; background-color: #282828; background-size: 16px 16px; background-attachment: fixed; @@ -56,9 +76,10 @@

      .units { font-size: 15px; } + /*Compass: https://thenounproject.com/search/?q=compass&i=592352*/ - + - + + \ No newline at end of file diff --git a/21 - Geolocation/package-lock.json b/21 - Geolocation/package-lock.json new file mode 100644 index 0000000000..a917c2f685 --- /dev/null +++ b/21 - Geolocation/package-lock.json @@ -0,0 +1,4046 @@ +{ + "name": "gum", + "version": "1.0.0", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "accepts": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.7.tgz", + "integrity": "sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA==", + "dev": true, + "requires": { + "mime-types": "~2.1.24", + "negotiator": "0.6.2" + } + }, + "after": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/after/-/after-0.8.2.tgz", + "integrity": "sha1-/ts5T58OAqqXaOcCvaI7UF+ufh8=", + "dev": true + }, + "ajv": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-4.11.8.tgz", + "integrity": "sha1-gv+wKynmYq5TvcIK8VlHcGc5xTY=", + "dev": true, + "requires": { + "co": "^4.6.0", + "json-stable-stringify": "^1.0.1" + } + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "anymatch": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz", + "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==", + "dev": true, + "requires": { + "micromatch": "^2.1.5", + "normalize-path": "^2.0.0" + } + }, + "arr-diff": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz", + "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=", + "dev": true, + "requires": { + "arr-flatten": "^1.0.1" + } + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "dev": true + }, + "array-unique": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz", + "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=", + "dev": true + }, + "arraybuffer.slice": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/arraybuffer.slice/-/arraybuffer.slice-0.0.7.tgz", + "integrity": "sha512-wGUIVQXuehL5TCqQun8OW81jGzAWycqzFF8lFp+GOM5BXLYj3bKNsYC4daB7n6XjCqxQA/qgTJ+8ANR3acjrog==", + "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": "0.2.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.2.0.tgz", + "integrity": "sha1-104bh+ev/A24qttwIfP+SBAasjQ=", + "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 + }, + "async": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", + "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", + "dev": true + }, + "async-each": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz", + "integrity": "sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ==", + "dev": true + }, + "async-each-series": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/async-each-series/-/async-each-series-0.1.1.tgz", + "integrity": "sha1-dhfBkXQB/Yykooqtzj266Yr+tDI=", + "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.6.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.6.0.tgz", + "integrity": "sha1-FDQt0428yU0OW4fXY81jYSwOeU8=", + "dev": true + }, + "aws4": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.1.tgz", + "integrity": "sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug==", + "dev": true + }, + "backo2": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/backo2/-/backo2-1.0.2.tgz", + "integrity": "sha1-MasayLEpNjRj41s+u2n038+6eUc=", + "dev": true + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + } + } + }, + "base64-arraybuffer": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-0.1.5.tgz", + "integrity": "sha1-c5JncZI7Whl0etZmqlzUv5xunOg=", + "dev": true + }, + "base64id": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-1.0.0.tgz", + "integrity": "sha1-R2iMuZu2gE8OBtPnY7HDLlfY5rY=", + "dev": true + }, + "batch": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.5.3.tgz", + "integrity": "sha1-PzQU84AyF0O/wQQvmoP/HVgk1GQ=", + "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" + } + }, + "better-assert": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/better-assert/-/better-assert-1.0.2.tgz", + "integrity": "sha1-QIZrnhueC1W0gYlDEeaPr/rrxSI=", + "dev": true, + "requires": { + "callsite": "1.0.0" + } + }, + "binary-extensions": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz", + "integrity": "sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw==", + "dev": true + }, + "bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "dev": true, + "optional": true, + "requires": { + "file-uri-to-path": "1.0.0" + } + }, + "blob": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/blob/-/blob-0.0.5.tgz", + "integrity": "sha512-gaqbzQPqOoamawKg0LGVd7SzLgXS+JH61oWprSLH+P+abTczqJbhTR8CmJ2u9/bUYNmHTGJx/UEmn6doAvvuig==", + "dev": true + }, + "boom": { + "version": "2.10.1", + "resolved": "https://registry.npmjs.org/boom/-/boom-2.10.1.tgz", + "integrity": "sha1-OciRjO/1eZ+D+UkqhI9iWt0Mdm8=", + "dev": true, + "requires": { + "hoek": "2.x.x" + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz", + "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=", + "dev": true, + "requires": { + "expand-range": "^1.8.1", + "preserve": "^0.2.0", + "repeat-element": "^1.1.2" + } + }, + "browser-sync": { + "version": "2.23.1", + "resolved": "https://registry.npmjs.org/browser-sync/-/browser-sync-2.23.1.tgz", + "integrity": "sha512-NKlkRzDK1e44ptr01GxWtoEC00YSnr5N2kEIk6zoCfQTxLYypiAh0uTNqAMz/n+jQe4MHmd4gjGdR7OReg1yxw==", + "dev": true, + "requires": { + "browser-sync-ui": "v1.0.1", + "bs-recipes": "1.3.4", + "chokidar": "1.7.0", + "connect": "3.5.0", + "connect-history-api-fallback": "^1.5.0", + "dev-ip": "^1.0.1", + "easy-extender": "2.3.2", + "eazy-logger": "3.0.2", + "emitter-steward": "^1.0.0", + "etag": "^1.8.1", + "fresh": "^0.5.2", + "fs-extra": "3.0.1", + "http-proxy": "1.15.2", + "immutable": "3.8.1", + "localtunnel": "1.8.3", + "micromatch": "2.3.11", + "opn": "4.0.2", + "portscanner": "2.1.1", + "qs": "6.2.1", + "resp-modifier": "6.0.2", + "rx": "4.1.0", + "serve-index": "1.8.0", + "serve-static": "1.12.2", + "server-destroy": "1.0.1", + "socket.io": "2.0.4", + "ua-parser-js": "0.7.12", + "yargs": "6.4.0" + } + }, + "browser-sync-ui": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browser-sync-ui/-/browser-sync-ui-1.0.1.tgz", + "integrity": "sha512-RIxmwVVcUFhRd1zxp7m2FfLnXHf59x4Gtj8HFwTA//3VgYI3AKkaQAuDL8KDJnE59XqCshxZa13JYuIWtZlKQg==", + "dev": true, + "requires": { + "async-each-series": "0.1.1", + "connect-history-api-fallback": "^1.1.0", + "immutable": "^3.7.6", + "server-destroy": "1.0.1", + "socket.io-client": "2.0.4", + "stream-throttle": "^0.1.3" + } + }, + "bs-recipes": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/bs-recipes/-/bs-recipes-1.3.4.tgz", + "integrity": "sha1-DS1NSKcYyMBEdp/cT4lZLci2lYU=", + "dev": true + }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + } + } + }, + "callsite": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/callsite/-/callsite-1.0.0.tgz", + "integrity": "sha1-KAOY5dZkvXQDi28JBRU+borxvCA=", + "dev": true + }, + "camelcase": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz", + "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=", + "dev": true + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "chokidar": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz", + "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=", + "dev": true, + "requires": { + "anymatch": "^1.3.0", + "async-each": "^1.0.0", + "fsevents": "^1.0.0", + "glob-parent": "^2.0.0", + "inherits": "^2.0.1", + "is-binary-path": "^1.0.0", + "is-glob": "^2.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.0.0" + } + }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + } + } + }, + "cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "dev": true, + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wrap-ansi": "^2.0.0" + } + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=", + "dev": true + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true + }, + "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" + } + }, + "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==", + "dev": true + }, + "component-bind": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/component-bind/-/component-bind-1.0.0.tgz", + "integrity": "sha1-AMYIq33Nk4l8AAllGx06jh5zu9E=", + "dev": true + }, + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "dev": true + }, + "component-inherit": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/component-inherit/-/component-inherit-0.0.3.tgz", + "integrity": "sha1-ZF/ErfWLcrZJ1crmUTVhnbJv8UM=", + "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=", + "dev": true + }, + "connect": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.5.0.tgz", + "integrity": "sha1-s1dSWgtMH1BZnNmD4dnv7qlncZg=", + "dev": true, + "requires": { + "debug": "~2.2.0", + "finalhandler": "0.5.0", + "parseurl": "~1.3.1", + "utils-merge": "1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", + "dev": true, + "requires": { + "ms": "0.7.1" + } + }, + "ms": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", + "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", + "dev": true + } + } + }, + "connect-history-api-fallback": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", + "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==", + "dev": true + }, + "cookie": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.3.1.tgz", + "integrity": "sha1-5+Ch+e9DtMi6klxcWpboBtFoc7s=", + "dev": true + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "dev": true + }, + "core-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 + }, + "cryptiles": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz", + "integrity": "sha1-O9/s3GCBR8HGcgL6KR59ylnqo7g=", + "dev": true, + "requires": { + "boom": "2.x.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" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + } + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "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 + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "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 + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=", + "dev": true + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=", + "dev": true + }, + "dev-ip": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dev-ip/-/dev-ip-1.0.1.tgz", + "integrity": "sha1-p2o+0YVb56ASu4rBbLgPPADcKPA=", + "dev": true + }, + "easy-extender": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/easy-extender/-/easy-extender-2.3.2.tgz", + "integrity": "sha1-PTJI/r4rFZYHMW2PnPSRwWZIIh0=", + "dev": true, + "requires": { + "lodash": "^3.10.1" + } + }, + "eazy-logger": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/eazy-logger/-/eazy-logger-3.0.2.tgz", + "integrity": "sha1-oyWqXlPROiIliJsqxBE7K5Y29Pw=", + "dev": true, + "requires": { + "tfunk": "^3.0.1" + } + }, + "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" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=", + "dev": true + }, + "emitter-steward": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/emitter-steward/-/emitter-steward-1.0.0.tgz", + "integrity": "sha1-80Ea3pdYp1Zd+Eiy2gy70bRsvWQ=", + "dev": true + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "dev": true + }, + "engine.io": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-3.1.5.tgz", + "integrity": "sha512-D06ivJkYxyRrcEe0bTpNnBQNgP9d3xog+qZlLbui8EsMr/DouQpf5o9FzJnWYHEYE0YsFHllUv2R1dkgYZXHcA==", + "dev": true, + "requires": { + "accepts": "~1.3.4", + "base64id": "1.0.0", + "cookie": "0.3.1", + "debug": "~3.1.0", + "engine.io-parser": "~2.1.0", + "uws": "~9.14.0", + "ws": "~3.3.1" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "engine.io-client": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-3.1.6.tgz", + "integrity": "sha512-hnuHsFluXnsKOndS4Hv6SvUrgdYx1pk2NqfaDMW+GWdgfU3+/V25Cj7I8a0x92idSpa5PIhJRKxPvp9mnoLsfg==", + "dev": true, + "requires": { + "component-emitter": "1.2.1", + "component-inherit": "0.0.3", + "debug": "~3.1.0", + "engine.io-parser": "~2.1.1", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "ws": "~3.3.1", + "xmlhttprequest-ssl": "~1.5.4", + "yeast": "0.1.2" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "engine.io-parser": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-2.1.3.tgz", + "integrity": "sha512-6HXPre2O4Houl7c4g7Ic/XzPnHBvaEmN90vtRO9uLmwtRqQmTOw0QMevL1TOfL2Cpu1VzsaTmMotQgMdkzGkVA==", + "dev": true, + "requires": { + "after": "0.8.2", + "arraybuffer.slice": "~0.0.7", + "base64-arraybuffer": "0.1.5", + "blob": "0.0.5", + "has-binary2": "~1.0.2" + } + }, + "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" + } + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=", + "dev": true + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=", + "dev": true + }, + "eventemitter3": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-1.2.0.tgz", + "integrity": "sha1-HIaZHYFq0eUEdQ5zh0Ik7PO+xQg=", + "dev": true + }, + "expand-brackets": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz", + "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=", + "dev": true, + "requires": { + "is-posix-bracket": "^0.1.0" + } + }, + "expand-range": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz", + "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=", + "dev": true, + "requires": { + "fill-range": "^2.1.0" + } + }, + "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": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "extglob": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz", + "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=", + "dev": true, + "requires": { + "is-extglob": "^1.0.0" + } + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true + }, + "file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", + "dev": true, + "optional": true + }, + "filename-regex": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz", + "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=", + "dev": true + }, + "fill-range": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.4.tgz", + "integrity": "sha512-cnrcCbj01+j2gTG921VZPnHbjmdAf8oQV/iGeV2kZxGSyfYjjTyY79ErsK1WJWMpw6DaApEX72binqJE+/d+5Q==", + "dev": true, + "requires": { + "is-number": "^2.1.0", + "isobject": "^2.0.0", + "randomatic": "^3.0.0", + "repeat-element": "^1.1.2", + "repeat-string": "^1.5.2" + } + }, + "finalhandler": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-0.5.0.tgz", + "integrity": "sha1-6VCKvs6bbbqHGmlCodeRG5GRGsc=", + "dev": true, + "requires": { + "debug": "~2.2.0", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "statuses": "~1.3.0", + "unpipe": "~1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", + "dev": true, + "requires": { + "ms": "0.7.1" + } + }, + "ms": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", + "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", + "dev": true + } + } + }, + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "dev": true, + "requires": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.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 + }, + "for-own": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz", + "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=", + "dev": true, + "requires": { + "for-in": "^1.0.1" + } + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true + }, + "form-data": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.1.4.tgz", + "integrity": "sha1-M8GDrPGTJ27KqYFDpp6Uv+4XUNE=", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.5", + "mime-types": "^2.1.12" + } + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dev": true, + "requires": { + "map-cache": "^0.2.2" + } + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=", + "dev": true + }, + "fs-extra": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-3.0.1.tgz", + "integrity": "sha1-N5TzeMWLNC6n27sjCVEJxLO2IpE=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^3.0.0", + "universalify": "^0.1.0" + } + }, + "fsevents": { + "version": "1.2.11", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.11.tgz", + "integrity": "sha512-+ux3lx6peh0BpvY0JebGyZoiR4D+oYzdPZMKJwkZ+sFkNJzpL7tXc/wehS49gUAxg3tmMHPHZkA8JU2rhhgDHw==", + "dev": true, + "optional": true, + "requires": { + "bindings": "^1.5.0", + "nan": "^2.12.1", + "node-pre-gyp": "*" + }, + "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.3", + "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": "3.2.6", + "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.7", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.6.0" + } + }, + "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.6", + "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.3", + "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.4", + "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.9.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.3.3", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.9.0" + } + }, + "mkdirp": { + "version": "0.5.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.1.2", + "bundled": true, + "dev": true, + "optional": true + }, + "needle": { + "version": "2.4.0", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "debug": "^3.2.6", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + } + }, + "node-pre-gyp": { + "version": "0.14.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.4.2" + } + }, + "nopt": { + "version": "4.0.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, + "npm-bundled": { + "version": "1.1.1", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "npm-normalize-package-bin": "^1.0.1" + } + }, + "npm-normalize-package-bin": { + "version": "1.0.1", + "bundled": true, + "dev": true, + "optional": true + }, + "npm-packlist": { + "version": "1.4.7", + "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.1", + "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.7.1", + "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.1", + "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.13", + "bundled": true, + "dev": true, + "optional": true, + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.8.6", + "minizlib": "^1.2.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.3" + } + }, + "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.1.1", + "bundled": true, + "dev": true, + "optional": true + } + } + }, + "get-caller-file": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", + "dev": true + }, + "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" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + } + } + }, + "glob-base": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz", + "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=", + "dev": true, + "requires": { + "glob-parent": "^2.0.0", + "is-glob": "^2.0.0" + } + }, + "glob-parent": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz", + "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=", + "dev": true, + "requires": { + "is-glob": "^2.0.0" + } + }, + "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 + }, + "har-schema": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-1.0.5.tgz", + "integrity": "sha1-0mMTX0MwfALGAq/I/pWXDAFRNp4=", + "dev": true + }, + "har-validator": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-4.2.1.tgz", + "integrity": "sha1-M0gdDxu/9gDdID11gSpqX7oALio=", + "dev": true, + "requires": { + "ajv": "^4.9.1", + "har-schema": "^1.0.5" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "has-binary2": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-binary2/-/has-binary2-1.0.3.tgz", + "integrity": "sha512-G1LWKhDSvhGeAQ8mPVQlqNcOB2sJdwATtZKl2pDKKHfpf/rYj24lkinxf69blJbnsvtqqNU+L3SL50vzZhXOnw==", + "dev": true, + "requires": { + "isarray": "2.0.1" + } + }, + "has-cors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", + "integrity": "sha1-XkdHk/fqmEPRu5nCPu9J/xJv/zk=", + "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" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + } + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "hawk": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/hawk/-/hawk-3.1.3.tgz", + "integrity": "sha1-B4REvXwWQLD+VA0sm3PVlnjo4cQ=", + "dev": true, + "requires": { + "boom": "2.x.x", + "cryptiles": "2.x.x", + "hoek": "2.x.x", + "sntp": "1.x.x" + } + }, + "hoek": { + "version": "2.16.3", + "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.3.tgz", + "integrity": "sha1-ILt0A9POo5jpHcRxCo/xuCdKJe0=", + "dev": true + }, + "hosted-git-info": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz", + "integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==", + "dev": true + }, + "http-errors": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.5.1.tgz", + "integrity": "sha1-eIwNLB3iyBuebowBhDtrl+uSB1A=", + "dev": true, + "requires": { + "inherits": "2.0.3", + "setprototypeof": "1.0.2", + "statuses": ">= 1.3.1 < 2" + }, + "dependencies": { + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + } + } + }, + "http-proxy": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.15.2.tgz", + "integrity": "sha1-ZC/cr/5S00SNK9o7AHnpQJBk2jE=", + "dev": true, + "requires": { + "eventemitter3": "1.x.x", + "requires-port": "1.x.x" + } + }, + "http-signature": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.1.1.tgz", + "integrity": "sha1-33LiZwZs0Kxn+3at+OE0qPvPkb8=", + "dev": true, + "requires": { + "assert-plus": "^0.2.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "immutable": { + "version": "3.8.1", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.8.1.tgz", + "integrity": "sha1-IAgH8Rqw9ycQ6khVQt4IgHX2jNI=", + "dev": true + }, + "indexof": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz", + "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=", + "dev": true + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "invert-kv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", + "dev": true + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "dev": true, + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "is-dotfile": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz", + "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=", + "dev": true + }, + "is-equal-shallow": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz", + "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=", + "dev": true, + "requires": { + "is-primitive": "^2.0.0" + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + }, + "is-extglob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz", + "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "is-glob": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz", + "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=", + "dev": true, + "requires": { + "is-extglob": "^1.0.0" + } + }, + "is-number": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz", + "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "is-number-like": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/is-number-like/-/is-number-like-1.0.8.tgz", + "integrity": "sha512-6rZi3ezCyFcn5L71ywzz2bS5b2Igl1En3eTlZlvKjpz1n3IZLAYMbKYAIQgFmEu0GENg92ziU/faEOA/aixjbA==", + "dev": true, + "requires": { + "lodash.isfinite": "^3.3.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" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + } + } + }, + "is-posix-bracket": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz", + "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=", + "dev": true + }, + "is-primitive": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz", + "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=", + "dev": true + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", + "dev": true + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true + }, + "isarray": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.1.tgz", + "integrity": "sha1-o32U7ZzaLVmGXJ92/llu4fM4dB4=", + "dev": true + }, + "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" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "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 + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "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-stable-stringify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz", + "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=", + "dev": true, + "requires": { + "jsonify": "~0.0.0" + } + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true + }, + "jsonfile": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-3.0.1.tgz", + "integrity": "sha1-pezG9l9T9mLEQVx2daAzHQmS7GY=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "jsonify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", + "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=", + "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" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + } + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + }, + "lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "dev": true, + "requires": { + "invert-kv": "^1.0.0" + } + }, + "limiter": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/limiter/-/limiter-1.1.5.tgz", + "integrity": "sha512-FWWMIEOxz3GwUI4Ts/IvgVy6LPvoMPgjMdQ185nN6psJyBJ4yOpzqm695/h5umdLJg2vW3GR5iG11MAkR2AzJA==", + "dev": true + }, + "load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + } + }, + "localtunnel": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/localtunnel/-/localtunnel-1.8.3.tgz", + "integrity": "sha1-3MWSL9hWUQN9S94k/ZMkjQsk6wU=", + "dev": true, + "requires": { + "debug": "2.6.8", + "openurl": "1.1.1", + "request": "2.81.0", + "yargs": "3.29.0" + }, + "dependencies": { + "debug": { + "version": "2.6.8", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz", + "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "yargs": { + "version": "3.29.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.29.0.tgz", + "integrity": "sha1-GquWYOrnnYuPZ1vK7qtu40ws9pw=", + "dev": true, + "requires": { + "camelcase": "^1.2.1", + "cliui": "^3.0.3", + "decamelize": "^1.0.0", + "os-locale": "^1.4.0", + "window-size": "^0.1.2", + "y18n": "^3.2.0" + } + } + } + }, + "lodash": { + "version": "3.10.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz", + "integrity": "sha1-W/Rejkm6QYnhfUgnid/RW9FAt7Y=", + "dev": true + }, + "lodash.isfinite": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/lodash.isfinite/-/lodash.isfinite-3.3.2.tgz", + "integrity": "sha1-+4m2WpqAKBgz8LdHizpRBPiY67M=", + "dev": true + }, + "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" + } + }, + "math-random": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/math-random/-/math-random-1.0.4.tgz", + "integrity": "sha512-rUxjysqif/BZQH2yhd5Aaq7vXMSx9NdEsQcyA07uEzIvxgI7zIr33gGsh+RU0/XjmQpCW7RsVof1vlkvQVCK5A==", + "dev": true + }, + "micromatch": { + "version": "2.3.11", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz", + "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=", + "dev": true, + "requires": { + "arr-diff": "^2.0.0", + "array-unique": "^0.2.1", + "braces": "^1.8.2", + "expand-brackets": "^0.1.4", + "extglob": "^0.3.1", + "filename-regex": "^2.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.1", + "kind-of": "^3.0.2", + "normalize-path": "^2.0.1", + "object.omit": "^2.0.0", + "parse-glob": "^3.0.4", + "regex-cache": "^0.4.2" + } + }, + "mime": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz", + "integrity": "sha1-EV+eO2s9rylZmDyzjxSaLUDrXVM=", + "dev": true + }, + "mime-db": { + "version": "1.43.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz", + "integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==", + "dev": true + }, + "mime-types": { + "version": "2.1.26", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz", + "integrity": "sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==", + "dev": true, + "requires": { + "mime-db": "1.43.0" + } + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "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" + } + } + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "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": { + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "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==", + "dev": true + }, + "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" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true + }, + "oauth-sign": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz", + "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM=", + "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=", + "dev": true + }, + "object-component": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/object-component/-/object-component-0.0.3.tgz", + "integrity": "sha1-8MaapQ78lbhmwYb0AKM3acsvEpE=", + "dev": true + }, + "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-path": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/object-path/-/object-path-0.9.2.tgz", + "integrity": "sha1-D9mnT8X60a45aLWGvaXGMr1sBaU=", + "dev": true + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dev": true, + "requires": { + "isobject": "^3.0.0" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + } + } + }, + "object.omit": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz", + "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=", + "dev": true, + "requires": { + "for-own": "^0.1.4", + "is-extendable": "^0.1.1" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dev": true, + "requires": { + "isobject": "^3.0.1" + }, + "dependencies": { + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + } + } + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "dev": true, + "requires": { + "ee-first": "1.1.1" + } + }, + "openurl": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/openurl/-/openurl-1.1.1.tgz", + "integrity": "sha1-OHW0sO96UsFW8NtB1GCduw+Us4c=", + "dev": true + }, + "opn": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/opn/-/opn-4.0.2.tgz", + "integrity": "sha1-erwi5kTf9jsKltWrfyeQwPAavJU=", + "dev": true, + "requires": { + "object-assign": "^4.0.1", + "pinkie-promise": "^2.0.0" + } + }, + "os-locale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", + "dev": true, + "requires": { + "lcid": "^1.0.0" + } + }, + "parse-glob": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz", + "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=", + "dev": true, + "requires": { + "glob-base": "^0.3.0", + "is-dotfile": "^1.0.0", + "is-extglob": "^1.0.0", + "is-glob": "^2.0.0" + } + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "^1.2.0" + } + }, + "parseqs": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.5.tgz", + "integrity": "sha1-1SCKNzjkZ2bikbouoXNoSSGouJ0=", + "dev": true, + "requires": { + "better-assert": "~1.0.0" + } + }, + "parseuri": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/parseuri/-/parseuri-0.0.5.tgz", + "integrity": "sha1-gCBKUNTbt3m/3G6+J3jZDkvOMgo=", + "dev": true, + "requires": { + "better-assert": "~1.0.0" + } + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "dev": true + }, + "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": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true, + "requires": { + "pinkie-promise": "^2.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "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-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "performance-now": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-0.2.0.tgz", + "integrity": "sha1-M+8wxcd9TqIcWlOGnZG1bY8lVeU=", + "dev": true + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "requires": { + "pinkie": "^2.0.0" + } + }, + "portscanner": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/portscanner/-/portscanner-2.1.1.tgz", + "integrity": "sha1-6rtAnk3iSVD1oqUW01rnaTQ/u5Y=", + "dev": true, + "requires": { + "async": "1.5.2", + "is-number-like": "^1.0.3" + } + }, + "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 + }, + "preserve": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz", + "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=", + "dev": true + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + }, + "qs": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.2.1.tgz", + "integrity": "sha1-zgPF/wk1vB2daanxTL0Y5WjWdiU=", + "dev": true + }, + "randomatic": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-3.1.1.tgz", + "integrity": "sha512-TuDE5KxZ0J461RVjrJZCJc+J+zCkTb1MbH9AQUq68sMhOMcy9jLcb3BrZKgp9q9Ncltdg4QVqWrH02W2EFFVYw==", + "dev": true, + "requires": { + "is-number": "^4.0.0", + "kind-of": "^6.0.0", + "math-random": "^1.0.1" + }, + "dependencies": { + "is-number": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", + "dev": true + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + } + } + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "dev": true + }, + "read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "dev": true, + "requires": { + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + } + }, + "read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "dev": true, + "requires": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" + } + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "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 + } + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + }, + "dependencies": { + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + } + }, + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + } + } + }, + "regex-cache": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz", + "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==", + "dev": true, + "requires": { + "is-equal-shallow": "^0.1.3" + } + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + } + }, + "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.81.0", + "resolved": "https://registry.npmjs.org/request/-/request-2.81.0.tgz", + "integrity": "sha1-xpKJRqDgbF+Nb4qTM0af/aRimKA=", + "dev": true, + "requires": { + "aws-sign2": "~0.6.0", + "aws4": "^1.2.1", + "caseless": "~0.12.0", + "combined-stream": "~1.0.5", + "extend": "~3.0.0", + "forever-agent": "~0.6.1", + "form-data": "~2.1.1", + "har-validator": "~4.2.1", + "hawk": "~3.1.3", + "http-signature": "~1.1.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.7", + "oauth-sign": "~0.8.1", + "performance-now": "^0.2.0", + "qs": "~6.4.0", + "safe-buffer": "^5.0.1", + "stringstream": "~0.0.4", + "tough-cookie": "~2.3.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.0.0" + }, + "dependencies": { + "qs": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.4.0.tgz", + "integrity": "sha1-E+JtKK1rD/qpExLNO/cI7TUecjM=", + "dev": true + } + } + }, + "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": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", + "dev": true + }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=", + "dev": true + }, + "resolve": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.1.tgz", + "integrity": "sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, + "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 + }, + "resp-modifier": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/resp-modifier/-/resp-modifier-6.0.2.tgz", + "integrity": "sha1-sSTeXE+6/LpUH0j/pzlw9KpFa08=", + "dev": true, + "requires": { + "debug": "^2.2.0", + "minimatch": "^3.0.2" + } + }, + "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 + }, + "rx": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/rx/-/rx-4.1.0.tgz", + "integrity": "sha1-pfE/957zt0D+MKqAP7CfmIBdR4I=", + "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==", + "dev": true + }, + "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==", + "dev": true + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "send": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.15.2.tgz", + "integrity": "sha1-+R+rRAO8+H5xb3DOtdsvV4vcF9Y=", + "dev": true, + "requires": { + "debug": "2.6.4", + "depd": "~1.1.0", + "destroy": "~1.0.4", + "encodeurl": "~1.0.1", + "escape-html": "~1.0.3", + "etag": "~1.8.0", + "fresh": "0.5.0", + "http-errors": "~1.6.1", + "mime": "1.3.4", + "ms": "1.0.0", + "on-finished": "~2.3.0", + "range-parser": "~1.2.0", + "statuses": "~1.3.1" + }, + "dependencies": { + "debug": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.4.tgz", + "integrity": "sha1-dYaps8OXQcAoKuM0RcTorHRzT+A=", + "dev": true, + "requires": { + "ms": "0.7.3" + }, + "dependencies": { + "ms": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.3.tgz", + "integrity": "sha1-cIFVpeROM/X9D8U+gdDUCpG+H/8=", + "dev": true + } + } + }, + "fresh": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.0.tgz", + "integrity": "sha1-9HTKXmqSRtb9jglTz6m5yAWvp44=", + "dev": true + }, + "http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "dev": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "dependencies": { + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "dev": true + } + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "ms": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-1.0.0.tgz", + "integrity": "sha1-Wa3NIu3FQ/e1OBhi0xOHsfS8lHM=", + "dev": true + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + } + } + }, + "serve-index": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.8.0.tgz", + "integrity": "sha1-fF2WwT+xMRAfk8HFd0+FFqHnjTs=", + "dev": true, + "requires": { + "accepts": "~1.3.3", + "batch": "0.5.3", + "debug": "~2.2.0", + "escape-html": "~1.0.3", + "http-errors": "~1.5.0", + "mime-types": "~2.1.11", + "parseurl": "~1.3.1" + }, + "dependencies": { + "debug": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.2.0.tgz", + "integrity": "sha1-+HBX6ZWxofauaklgZkE3vFbwOdo=", + "dev": true, + "requires": { + "ms": "0.7.1" + } + }, + "ms": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/ms/-/ms-0.7.1.tgz", + "integrity": "sha1-nNE8A62/8ltl7/3nzoZO6VIBcJg=", + "dev": true + } + } + }, + "serve-static": { + "version": "1.12.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.12.2.tgz", + "integrity": "sha1-5UbicmCBuBtLzsjpCAjrzdMjr7o=", + "dev": true, + "requires": { + "encodeurl": "~1.0.1", + "escape-html": "~1.0.3", + "parseurl": "~1.3.1", + "send": "0.15.2" + } + }, + "server-destroy": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/server-destroy/-/server-destroy-1.0.1.tgz", + "integrity": "sha1-8Tv5KOQrnD55OD5hzDmYtdFObN0=", + "dev": true + }, + "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" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "setprototypeof": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.2.tgz", + "integrity": "sha1-gaVSFB7BBLiOic44MQOtXGZWTQg=", + "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": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dev": true, + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "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" + } + }, + "sntp": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz", + "integrity": "sha1-ZUEYTMkK7qbG57NeJlkIJEPGYZg=", + "dev": true, + "requires": { + "hoek": "2.x.x" + } + }, + "socket.io": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-2.0.4.tgz", + "integrity": "sha1-waRZDO/4fs8TxyZS8Eb3FrKeYBQ=", + "dev": true, + "requires": { + "debug": "~2.6.6", + "engine.io": "~3.1.0", + "socket.io-adapter": "~1.1.0", + "socket.io-client": "2.0.4", + "socket.io-parser": "~3.1.1" + } + }, + "socket.io-adapter": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-1.1.2.tgz", + "integrity": "sha512-WzZRUj1kUjrTIrUKpZLEzFZ1OLj5FwLlAFQs9kuZJzJi5DKdU7FsWc36SNmA8iDOtwBQyT8FkrriRM8vXLYz8g==", + "dev": true + }, + "socket.io-client": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-2.0.4.tgz", + "integrity": "sha1-CRilUkBtxeVAs4Dc2Xr8SmQzL44=", + "dev": true, + "requires": { + "backo2": "1.0.2", + "base64-arraybuffer": "0.1.5", + "component-bind": "1.0.0", + "component-emitter": "1.2.1", + "debug": "~2.6.4", + "engine.io-client": "~3.1.0", + "has-cors": "1.1.0", + "indexof": "0.0.1", + "object-component": "0.0.3", + "parseqs": "0.0.5", + "parseuri": "0.0.5", + "socket.io-parser": "~3.1.1", + "to-array": "0.1.4" + } + }, + "socket.io-parser": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-3.1.3.tgz", + "integrity": "sha512-g0a2HPqLguqAczs3dMECuA1RgoGFPyvDqcbaDEdCWY9g59kdUAz3YRmaJBNKXflrHNwB7Q12Gkf/0CZXfdHR7g==", + "dev": true, + "requires": { + "component-emitter": "1.2.1", + "debug": "~3.1.0", + "has-binary2": "~1.0.2", + "isarray": "2.0.1" + }, + "dependencies": { + "debug": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", + "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", + "dev": true, + "requires": { + "ms": "2.0.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 + }, + "source-map-resolve": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz", + "integrity": "sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==", + "dev": true, + "requires": { + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.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" + } + }, + "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" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "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.3.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", + "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4=", + "dev": true + }, + "stream-throttle": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/stream-throttle/-/stream-throttle-0.1.3.tgz", + "integrity": "sha1-rdV8jXzHOoFjDTHNVdOWHPr7qcM=", + "dev": true, + "requires": { + "commander": "^2.2.0", + "limiter": "^1.0.5" + } + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": 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", + "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" + } + }, + "stringstream": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.6.tgz", + "integrity": "sha512-87GEBAkegbBcweToUrdzf3eLhWNg06FJTebl4BVJz/JgWy8CvEr9dRtX5qWphiynMSQlxxi+QqN0z5T32SLlhA==", + "dev": true + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "dev": true, + "requires": { + "is-utf8": "^0.2.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + }, + "tfunk": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/tfunk/-/tfunk-3.1.0.tgz", + "integrity": "sha1-OORBT8ZJd9h6/apy+sttKfgve1s=", + "dev": true, + "requires": { + "chalk": "^1.1.1", + "object-path": "^0.9.0" + } + }, + "to-array": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/to-array/-/to-array-0.1.4.tgz", + "integrity": "sha1-F+bBH3PdTz10zaek/zI46a2b+JA=", + "dev": true + }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + }, + "dependencies": { + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + } + } + } + }, + "tough-cookie": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.4.tgz", + "integrity": "sha512-TZ6TTfI5NtZnuyy/Kecv+CnoROnyXn2DN97LontgQpCwsX2XyLYCC0ENhYkehSOwAp8rTQKc/NUIF7BkQ5rKLA==", + "dev": true, + "requires": { + "punycode": "^1.4.1" + } + }, + "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 + }, + "ua-parser-js": { + "version": "0.7.12", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.12.tgz", + "integrity": "sha1-BMgamb3V3FImPqKdJMa/jUgYpLs=", + "dev": true + }, + "ultron": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ultron/-/ultron-1.1.1.tgz", + "integrity": "sha512-UIEXBNeYmKptWH6z8ZnqTeS8fV74zG0/eRU9VGkpzz+LIJNs8W/zM/L+7ctCkRrgbNnnR0xxw4bKOr0cW0N0Og==", + "dev": true + }, + "union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + } + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "dev": true + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "dev": true, + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "dev": true, + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + } + } + }, + "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 + }, + "utils-merge": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.0.tgz", + "integrity": "sha1-ApT7kiu5N1FTVBxPcJYjHyh8ivg=", + "dev": true + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "dev": true + }, + "uws": { + "version": "9.14.0", + "resolved": "https://registry.npmjs.org/uws/-/uws-9.14.0.tgz", + "integrity": "sha512-HNMztPP5A1sKuVFmdZ6BPVpBQd5bUjNC8EFMFiICK+oho/OQsAJy5hnIx4btMHiOk8j04f/DbIlqnEZ9d72dqg==", + "dev": true, + "optional": 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" + } + }, + "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" + }, + "dependencies": { + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + } + } + }, + "which-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", + "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=", + "dev": true + }, + "window-size": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.4.tgz", + "integrity": "sha1-+OGqHuWlPsW/FR/6CXQqatdpeHY=", + "dev": true + }, + "wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "dev": true, + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + } + }, + "ws": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-3.3.3.tgz", + "integrity": "sha512-nnWLa/NwZSt4KQJu51MYlCcSQ5g7INpOrOMt4XV8j4dqTXdmlUmSHQ8/oLC069ckre0fRsgfvsKwbTdtKLCDkA==", + "dev": true, + "requires": { + "async-limiter": "~1.0.0", + "safe-buffer": "~5.1.0", + "ultron": "~1.1.0" + } + }, + "xmlhttprequest-ssl": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-1.5.5.tgz", + "integrity": "sha1-wodrBhaKrcQOV9l+gRkayPQ5iz4=", + "dev": true + }, + "y18n": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", + "dev": true + }, + "yargs": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-6.4.0.tgz", + "integrity": "sha1-gW4ahm1VmMzzTlWW3c4i2S2kkNQ=", + "dev": true, + "requires": { + "camelcase": "^3.0.0", + "cliui": "^3.2.0", + "decamelize": "^1.1.1", + "get-caller-file": "^1.0.1", + "os-locale": "^1.4.0", + "read-pkg-up": "^1.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^1.0.2", + "which-module": "^1.0.0", + "window-size": "^0.2.0", + "y18n": "^3.2.1", + "yargs-parser": "^4.1.0" + }, + "dependencies": { + "camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", + "dev": true + }, + "window-size": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.2.0.tgz", + "integrity": "sha1-tDFbtCFKPXBY6+7okuE/ok2YsHU=", + "dev": true + } + } + }, + "yargs-parser": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-4.2.1.tgz", + "integrity": "sha1-KczqwNxPA8bIe0qfIX3RjJ90hxw=", + "dev": true, + "requires": { + "camelcase": "^3.0.0" + }, + "dependencies": { + "camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", + "dev": true + } + } + }, + "yeast": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", + "integrity": "sha1-AI4G2AlDIMNy28L47XagymyKxBk=", + "dev": true + } + } +} diff --git a/21 - Geolocation/typescripts.js b/21 - Geolocation/typescripts.js new file mode 100644 index 0000000000..091f7ebce8 --- /dev/null +++ b/21 - Geolocation/typescripts.js @@ -0,0 +1,12 @@ +var arrow = document.querySelector(".arrow"); +var speed = document.querySelector(".speed-value"); +navigator.geolocation.watchPosition(function (data) { + console.log(data); + if (data.coords.speed) { + speed.textContent = data.coords.speed.toFixed(2); + } + else { + speed.textContent = "0"; + } + arrow.style.transform = "rotate(" + data.coords.heading + "deg)"; +}, function () { return alert("We're gonna need those perms, buddy."); }); diff --git a/21 - Geolocation/typescripts.ts b/21 - Geolocation/typescripts.ts new file mode 100644 index 0000000000..bd1bff79a6 --- /dev/null +++ b/21 - Geolocation/typescripts.ts @@ -0,0 +1,26 @@ +/** + * JavaScript30 by Wes Bos, https://javascript30.com/ + * TypeScript implementation by Will Wager + * Project: Geolocation + * Concepts: Geolocation API + * Key takeaways: https://developer.mozilla.org/en-US/docs/Web/API/Geolocation_API + * Sidenotes: Limited browsers; must be over https + * Compilation command: + * tsc --removeComments --strictNullChecks --noImplicitAny --target es5 typescripts.ts + */ + +const arrow = document.querySelector(".arrow")! as SVGElement; +const speed = document.querySelector(".speed-value")! as HTMLSpanElement; + +navigator.geolocation.watchPosition( + data => { + console.log(data); + if (data.coords.speed) { + speed.textContent = data.coords.speed.toFixed(2); + } else { + speed.textContent = "0"; + } + arrow.style.transform = `rotate(${data.coords.heading}deg)`; + }, + () => alert("We're gonna need those perms, buddy.") +); From bed3bddf153b7517528d962976752c1bfca69a5a Mon Sep 17 00:00:00 2001 From: William Wager Date: Wed, 4 Mar 2020 10:09:42 -0500 Subject: [PATCH 23/34] Project 22 complete --- .../index-START.html | 45 ++++++++++--------- .../typescripts.js | 17 +++++++ .../typescripts.ts | 36 +++++++++++++++ 3 files changed, 78 insertions(+), 20 deletions(-) create mode 100644 22 - Follow Along Link Highlighter/typescripts.js create mode 100644 22 - Follow Along Link Highlighter/typescripts.ts diff --git a/22 - Follow Along Link Highlighter/index-START.html b/22 - Follow Along Link Highlighter/index-START.html index 8476112b5e..13a7bcbbbd 100644 --- a/22 - Follow Along Link Highlighter/index-START.html +++ b/22 - Follow Along Link Highlighter/index-START.html @@ -1,33 +1,38 @@ + 👀👀👀Follow Along Nav + - + -
      -

      Lorem ipsum dolor sit amet, consectetur adipisicing elit. Est explicabo unde natus necessitatibus esse obcaecati distinctio, aut itaque, qui vitae!

      -

      Aspernatur sapiente quae sint soluta modi, atque praesentium laborum pariatur earum quaerat cupiditate consequuntur facilis ullam dignissimos, aperiam quam veniam.

      -

      Cum ipsam quod, incidunt sit ex tempore placeat maxime corrupti possimus veritatis ipsum fugit recusandae est doloremque? Hic, quibusdam, nulla.

      -

      Esse quibusdam, ad, ducimus cupiditate nulla, quae magni odit totam ut consequatur eveniet sunt quam provident sapiente dicta neque quod.

      -

      Aliquam dicta sequi culpa fugiat consequuntur pariatur optio ad minima, maxime odio, distinctio magni impedit tempore enim repellendus repudiandae quas!

      -
      +
      +

      Lorem ipsum dolor sit amet, consectetur adipisicing elit. Est explicabo unde natus + necessitatibus esse obcaecati distinctio, aut itaque, qui vitae!

      +

      Aspernatur sapiente quae sint soluta modi, atque praesentium laborum pariatur earum quaerat cupiditate consequuntur facilis ullam dignissimos, aperiam quam veniam.

      +

      Cum ipsam quod, incidunt sit ex tempore placeat maxime corrupti possimus veritatis ipsum fugit recusandae est doloremque? Hic, quibusdam, nulla.

      +

      Esse quibusdam, ad, ducimus cupiditate nulla, quae magni odit totam ut consequatur + eveniet sunt quam provident sapiente dicta neque quod.

      +

      Aliquam dicta sequi culpa fugiat consequuntur pariatur optio ad minima, maxime odio, distinctio magni impedit tempore enim repellendus repudiandae quas!

      +
      - + - + \ No newline at end of file diff --git a/22 - Follow Along Link Highlighter/typescripts.js b/22 - Follow Along Link Highlighter/typescripts.js new file mode 100644 index 0000000000..2dbd671210 --- /dev/null +++ b/22 - Follow Along Link Highlighter/typescripts.js @@ -0,0 +1,17 @@ +var triggers = document.querySelectorAll('a'); +var highlight = document.createElement('span'); +highlight.classList.add('highlight'); +document.body.append(highlight); +function highlightLink() { + var linkCoords = this.getBoundingClientRect(); + var coords = { + width: linkCoords.width, + height: linkCoords.height, + top: linkCoords.top + window.scrollY, + left: linkCoords.left + window.scrollX, + }; + highlight.style.width = coords.width + 4 + "px"; + highlight.style.height = coords.height + "px"; + highlight.style.transform = "translate(" + (coords.left - 2) + "px, " + coords.top + "px)"; +} +triggers.forEach(function (a) { return a.addEventListener('mouseenter', highlightLink); }); diff --git a/22 - Follow Along Link Highlighter/typescripts.ts b/22 - Follow Along Link Highlighter/typescripts.ts new file mode 100644 index 0000000000..7ae4883b77 --- /dev/null +++ b/22 - Follow Along Link Highlighter/typescripts.ts @@ -0,0 +1,36 @@ +/** + * JavaScript30 by Wes Bos, https://javascript30.com/ + * TypeScript implementation by Will Wager + * Project: Follow Along Link Highlighter + * Concepts: Update and move highlighter with mouseenter; + * getting entered element's location + * Key takeaways: getBoundingClientRect + scroll; css translate transform + * Sidenotes: No additional typing was necessary for TypeScript. Tsc can get the + * propper types from querySelectors when element tags are used; + * One improvement could be adding the transition after the first highlight, so + * it doesn't slide in from the top left. + * Compilation command: + * tsc --removeComments --strictNullChecks --noImplicitAny --target es5 typescripts.ts + */ + +// 👀👀👀👀👀👀👀👀👀👀👀👀👀👀👀 + +const triggers = document.querySelectorAll('a'); +const highlight = document.createElement('span'); +highlight.classList.add('highlight'); +document.body.append(highlight); + +function highlightLink() { + const linkCoords = this.getBoundingClientRect(); + const coords = { + width: linkCoords.width, + height: linkCoords.height, + top: linkCoords.top + window.scrollY, + left: linkCoords.left + window.scrollX, + }; + highlight.style.width = `${coords.width + 4}px`; + highlight.style.height = `${coords.height}px`; + highlight.style.transform = `translate(${coords.left - 2}px, ${coords.top}px)`; +} + +triggers.forEach(a => a.addEventListener('mouseenter', highlightLink)); From 3c8d0721b8f8c504a755aed417f3f90b95c62fc1 Mon Sep 17 00:00:00 2001 From: William Wager Date: Wed, 4 Mar 2020 11:45:52 -0500 Subject: [PATCH 24/34] Project 23 complete --- 23 - Speech Synthesis/index-START.html | 40 ++++++++---------- 23 - Speech Synthesis/typescripts.js | 40 ++++++++++++++++++ 23 - Speech Synthesis/typescripts.ts | 58 ++++++++++++++++++++++++++ 3 files changed, 116 insertions(+), 22 deletions(-) create mode 100644 23 - Speech Synthesis/typescripts.js create mode 100644 23 - Speech Synthesis/typescripts.ts diff --git a/23 - Speech Synthesis/index-START.html b/23 - Speech Synthesis/index-START.html index e890008d36..1c51cab22f 100644 --- a/23 - Speech Synthesis/index-START.html +++ b/23 - Speech Synthesis/index-START.html @@ -1,41 +1,37 @@ + Speech Synthesis + -
      +
      -

      The Voiceinator 5000

      +

      The Voiceinator 5000

      - + - - + + - + - - - - + + + + -
      +
      - + - + + \ No newline at end of file diff --git a/23 - Speech Synthesis/typescripts.js b/23 - Speech Synthesis/typescripts.js new file mode 100644 index 0000000000..bfda0a0ad4 --- /dev/null +++ b/23 - Speech Synthesis/typescripts.js @@ -0,0 +1,40 @@ +const msg = new SpeechSynthesisUtterance(); +let voices = []; +const voicesDropdown = document.querySelector('[name="voice"]'); +const options = document.querySelectorAll('[type="range"], [name="text"]'); +const speakButton = document.querySelector('#speak'); +const stopButton = document.querySelector('#stop'); +msg.text = document.querySelector('[name="text"]').value; +function populateVoices() { + voices = this.getVoices(); + voicesDropdown.innerHTML = (voices + .map(voice => ``) + .join('')); +} +function setVoice() { + const newVoice = voices.find(voice => voice.name === this.value); + if (newVoice) { + msg.voice = newVoice; + toggle(); + return true; + } + else { + console.error('Selected voice not found'); + return false; + } +} +function toggle(e, startOver = true) { + speechSynthesis.cancel(); + if (startOver) { + speechSynthesis.speak(msg); + } +} +function setOption() { + msg[this.name] = Number(this.value); + toggle(); +} +speechSynthesis.addEventListener('voiceschanged', populateVoices); +voicesDropdown.addEventListener('change', setVoice); +options.forEach(option => option.addEventListener('change', setOption)); +speakButton.addEventListener('click', toggle); +stopButton.addEventListener('click', e => toggle(e, false)); diff --git a/23 - Speech Synthesis/typescripts.ts b/23 - Speech Synthesis/typescripts.ts new file mode 100644 index 0000000000..fef63df281 --- /dev/null +++ b/23 - Speech Synthesis/typescripts.ts @@ -0,0 +1,58 @@ +/** + * JavaScript30 by Wes Bos, https://javascript30.com/ + * TypeScript implementation by Will Wager + * Project: Speech Synthesis + * Concepts: Web Speech API + * Key takeaways: Specifying this in a handler function signature; + * Set options with element name pattern (not very TS friendly). + * Sidenotes: https://developer.mozilla.org/en-US/docs/Web/API/Web_Speech_API + * Chrome required. + * Targeted es6 to get Array.find; Allowed implicit any for msg[input.name]; + * Compilation command: + * tsc --removeComments --strictNullChecks --target es6 typescripts.ts + */ + +const msg = new SpeechSynthesisUtterance(); +let voices: SpeechSynthesisVoice[] = []; +const voicesDropdown = document.querySelector('[name="voice"]')! as HTMLSelectElement; +const options = document.querySelectorAll('[type="range"], [name="text"]'); +const speakButton = document.querySelector('#speak')! as HTMLButtonElement; +const stopButton = document.querySelector('#stop')! as HTMLButtonElement; +msg.text = (document.querySelector('[name="text"]')! as HTMLInputElement).value; + +function populateVoices(this: SpeechSynthesis) { + voices = this.getVoices(); + voicesDropdown.innerHTML = (voices + .map(voice => ``) + .join('')); +} + +function setVoice() { + const newVoice = voices.find(voice => voice.name === this.value); + if (newVoice) { + msg.voice = newVoice; + toggle(); + return true; + } else { + console.error('Selected voice not found'); + return false; + } +} + +function toggle(e?: Event, startOver = true) { + speechSynthesis.cancel(); + if (startOver) { + speechSynthesis.speak(msg); + } +} + +function setOption() { + msg[this.name] = Number(this.value); + toggle(); +} + +speechSynthesis.addEventListener('voiceschanged', populateVoices); +voicesDropdown.addEventListener('change', setVoice); +options.forEach(option => option.addEventListener('change', setOption)); +speakButton.addEventListener('click', toggle); +stopButton.addEventListener('click', e => toggle(e, false)); From c88fc59296b71ac2bd1d05962c841afff92014b0 Mon Sep 17 00:00:00 2001 From: William Wager Date: Wed, 4 Mar 2020 13:02:34 -0500 Subject: [PATCH 25/34] Project 24 complete --- 24 - Sticky Nav/index-START.html | 161 ++++++++++++++++++++++++++----- 24 - Sticky Nav/style-START.css | 15 ++- 24 - Sticky Nav/typescripts.js | 13 +++ 24 - Sticky Nav/typescripts.ts | 25 +++++ 4 files changed, 191 insertions(+), 23 deletions(-) create mode 100644 24 - Sticky Nav/typescripts.js create mode 100644 24 - Sticky Nav/typescripts.ts diff --git a/24 - Sticky Nav/index-START.html b/24 - Sticky Nav/index-START.html index e7bc67e9a5..ac5e509d3b 100644 --- a/24 - Sticky Nav/index-START.html +++ b/24 - Sticky Nav/index-START.html @@ -1,10 +1,12 @@ + Sticky Nav +
      @@ -24,38 +26,153 @@

      A story about getting lost.

      -

      Lorem ipsum dolor sit amet, consectetur adipisicing elit. Tempore tempora rerum, est autem cupiditate, corporis a qui libero ipsum delectus quidem dolor at nulla, adipisci veniam in reiciendis aut asperiores omnis blanditiis quod quas laborum nam! Fuga ad tempora in aspernatur pariatur fugit quibusdam dolores sunt esse magni, ut, dignissimos.

      -

      Lorem ipsum dolor sit amet, consectetur adipisicing elit. Tempore tempora rerum, est autem cupiditate, corporis a qui libero ipsum delectus quidem dolor at nulla, adipisci veniam in reiciendis aut asperiores omnis blanditiis quod quas laborum nam! Fuga ad tempora in aspernatur pariatur fugit quibusdam dolores sunt esse magni, ut, dignissimos.

      -

      Lorem ipsum dolor sit amet, consectetur adipisicing elit. Tempore tempora rerum, est autem cupiditate, corporis a qui libero ipsum delectus quidem dolor at nulla, adipisci veniam in reiciendis aut asperiores omnis blanditiis quod quas laborum nam! Fuga ad tempora in aspernatur pariatur fugit quibusdam dolores sunt esse magni, ut, dignissimos.

      -

      Lorem ipsum dolor sit amet, consectetur adipisicing elit. Tempore tempora rerum, est autem cupiditate, corporis a qui libero ipsum delectus quidem dolor at nulla, adipisci veniam in reiciendis aut asperiores omnis blanditiis quod quas laborum nam! Fuga ad tempora in aspernatur pariatur fugit quibusdam dolores sunt esse magni, ut, dignissimos.

      -

      Lorem ipsum dolor sit amet, consectetur adipisicing elit. Tempore tempora rerum, est autem cupiditate, corporis a qui libero ipsum delectus quidem dolor at nulla, adipisci veniam in reiciendis aut asperiores omnis blanditiis quod quas laborum nam! Fuga ad tempora in aspernatur pariatur fugit quibusdam dolores sunt esse magni, ut, dignissimos.

      -

      Lorem ipsum dolor sit amet, consectetur adipisicing elit. Tempore tempora rerum, est autem cupiditate, corporis a qui libero ipsum delectus quidem dolor at nulla, adipisci veniam in reiciendis aut asperiores omnis blanditiis quod quas laborum nam! Fuga ad tempora in aspernatur pariatur fugit quibusdam dolores sunt esse magni, ut, dignissimos.

      -

      Lorem ipsum dolor sit amet, consectetur adipisicing elit. Tempore tempora rerum, est autem cupiditate, corporis a qui libero ipsum delectus quidem dolor at nulla, adipisci veniam in reiciendis aut asperiores omnis blanditiis quod quas laborum nam! Fuga ad tempora in aspernatur pariatur fugit quibusdam dolores sunt esse magni, ut, dignissimos.

      -

      Lorem ipsum dolor sit amet, consectetur adipisicing elit. Tempore tempora rerum, est autem cupiditate, corporis a qui libero ipsum delectus quidem dolor at nulla, adipisci veniam in reiciendis aut asperiores omnis blanditiis quod quas laborum nam! Fuga ad tempora in aspernatur pariatur fugit quibusdam dolores sunt esse magni, ut, dignissimos.

      -

      Lorem ipsum dolor sit amet, consectetur adipisicing elit. Tempore tempora rerum, est autem cupiditate, corporis a qui libero ipsum delectus quidem dolor at nulla, adipisci veniam in reiciendis aut asperiores omnis blanditiis quod quas laborum nam! Fuga ad tempora in aspernatur pariatur fugit quibusdam dolores sunt esse magni, ut, dignissimos.

      -

      Lorem ipsum dolor sit amet, consectetur adipisicing elit. Tempore tempora rerum, est autem cupiditate, corporis a qui libero ipsum delectus quidem dolor at nulla, adipisci veniam in reiciendis aut asperiores omnis blanditiis quod quas laborum nam! Fuga ad tempora in aspernatur pariatur fugit quibusdam dolores sunt esse magni, ut, dignissimos.

      +

      Lorem ipsum dolor sit amet, consectetur adipisicing elit. Tempore tempora rerum, est autem cupiditate, corporis a + qui libero ipsum delectus quidem dolor at nulla, adipisci veniam in reiciendis aut asperiores omnis blanditiis + quod quas laborum nam! Fuga ad tempora in aspernatur pariatur fugit quibusdam dolores sunt esse magni, ut, + dignissimos.

      +

      Lorem ipsum dolor sit amet, consectetur adipisicing elit. Tempore tempora rerum, est autem cupiditate, corporis a + qui libero ipsum delectus quidem dolor at nulla, adipisci veniam in reiciendis aut asperiores omnis blanditiis + quod quas laborum nam! Fuga ad tempora in aspernatur pariatur fugit quibusdam dolores sunt esse magni, ut, + dignissimos.

      +

      Lorem ipsum dolor sit amet, consectetur adipisicing elit. Tempore tempora rerum, est autem cupiditate, corporis a + qui libero ipsum delectus quidem dolor at nulla, adipisci veniam in reiciendis aut asperiores omnis blanditiis + quod quas laborum nam! Fuga ad tempora in aspernatur pariatur fugit quibusdam dolores sunt esse magni, ut, + dignissimos.

      +

      Lorem ipsum dolor sit amet, consectetur adipisicing elit. Tempore tempora rerum, est autem cupiditate, corporis a + qui libero ipsum delectus quidem dolor at nulla, adipisci veniam in reiciendis aut asperiores omnis blanditiis + quod quas laborum nam! Fuga ad tempora in aspernatur pariatur fugit quibusdam dolores sunt esse magni, ut, + dignissimos.

      +

      Lorem ipsum dolor sit amet, consectetur adipisicing elit. Tempore tempora rerum, est autem cupiditate, corporis a + qui libero ipsum delectus quidem dolor at nulla, adipisci veniam in reiciendis aut asperiores omnis blanditiis + quod quas laborum nam! Fuga ad tempora in aspernatur pariatur fugit quibusdam dolores sunt esse magni, ut, + dignissimos.

      +

      Lorem ipsum dolor sit amet, consectetur adipisicing elit. Tempore tempora rerum, est autem cupiditate, corporis a + qui libero ipsum delectus quidem dolor at nulla, adipisci veniam in reiciendis aut asperiores omnis blanditiis + quod quas laborum nam! Fuga ad tempora in aspernatur pariatur fugit quibusdam dolores sunt esse magni, ut, + dignissimos.

      +

      Lorem ipsum dolor sit amet, consectetur adipisicing elit. Tempore tempora rerum, est autem cupiditate, corporis a + qui libero ipsum delectus quidem dolor at nulla, adipisci veniam in reiciendis aut asperiores omnis blanditiis + quod quas laborum nam! Fuga ad tempora in aspernatur pariatur fugit quibusdam dolores sunt esse magni, ut, + dignissimos.

      +

      Lorem ipsum dolor sit amet, consectetur adipisicing elit. Tempore tempora rerum, est autem cupiditate, corporis a + qui libero ipsum delectus quidem dolor at nulla, adipisci veniam in reiciendis aut asperiores omnis blanditiis + quod quas laborum nam! Fuga ad tempora in aspernatur pariatur fugit quibusdam dolores sunt esse magni, ut, + dignissimos.

      +

      Lorem ipsum dolor sit amet, consectetur adipisicing elit. Tempore tempora rerum, est autem cupiditate, corporis a + qui libero ipsum delectus quidem dolor at nulla, adipisci veniam in reiciendis aut asperiores omnis blanditiis + quod quas laborum nam! Fuga ad tempora in aspernatur pariatur fugit quibusdam dolores sunt esse magni, ut, + dignissimos.

      +

      Lorem ipsum dolor sit amet, consectetur adipisicing elit. Tempore tempora rerum, est autem cupiditate, corporis a + qui libero ipsum delectus quidem dolor at nulla, adipisci veniam in reiciendis aut asperiores omnis blanditiis + quod quas laborum nam! Fuga ad tempora in aspernatur pariatur fugit quibusdam dolores sunt esse magni, ut, + dignissimos.

      -

      Lorem ipsum dolor sit amet, consectetur adipisicing elit. Voluptates, deserunt facilis et iste corrupti omnis tenetur est. Iste ut est dicta dolor itaque adipisci, dolorum minima, veritatis earum provident error molestias. Ratione magni illo sint vel velit ut excepturi consectetur suscipit, earum modi accusamus voluptatem nostrum, praesentium numquam, reiciendis voluptas sit id quisquam. Consequatur in quis reprehenderit modi perspiciatis necessitatibus saepe, quidem, suscipit iure natus dignissimos ipsam, eligendi deleniti accusantium, rerum quibusdam fugit perferendis et optio recusandae sed ratione. Culpa, dolorum reprehenderit harum ab voluptas fuga, nisi eligendi natus maiores illum quas quos et aperiam aut doloremque optio maxime fugiat doloribus. Eum dolorum expedita quam, nesciunt

      +

      Lorem ipsum dolor sit amet, consectetur adipisicing elit. Voluptates, deserunt facilis et iste corrupti omnis + tenetur est. Iste ut est dicta dolor itaque adipisci, dolorum minima, veritatis earum provident error molestias. + Ratione magni illo sint vel velit ut excepturi consectetur suscipit, earum modi accusamus voluptatem nostrum, + praesentium numquam, reiciendis voluptas sit id quisquam. Consequatur in quis reprehenderit modi perspiciatis + necessitatibus saepe, quidem, suscipit iure natus dignissimos ipsam, eligendi deleniti accusantium, rerum + quibusdam fugit perferendis et optio recusandae sed ratione. Culpa, dolorum reprehenderit harum ab voluptas fuga, + nisi eligendi natus maiores illum quas quos et aperiam aut doloremque optio maxime fugiat doloribus. Eum dolorum + expedita quam, nesciunt

      -

      at provident praesentium atque quas rerum optio dignissimos repudiandae ullam illum quibusdam. Vel ad error quibusdam, illo ex totam placeat. Quos excepturi fuga, molestiae ea quisquam minus, ratione dicta consectetur officia omnis, doloribus voluptatibus? Veniam ipsum veritatis architecto, provident quas consequatur doloremque quam quidem earum expedita, ad delectus voluptatum, omnis praesentium nostrum qui aspernatur ea eaque adipisci et cumque ab? Ea voluptatum dolore itaque odio. Eius minima distinctio harum, officia ab nihil exercitationem. Tempora rem nemo nam temporibus molestias facilis minus ipsam quam doloribus consequatur debitis nesciunt tempore officiis aperiam quisquam, molestiae voluptates cum, fuga culpa. Distinctio accusamus quibusdam, tempore perspiciatis dolorum optio facere consequatur quidem ullam beatae architecto, ipsam sequi officiis dignissimos amet impedit natus necessitatibus tenetur repellendus dolor rem! Dicta dolorem, iure, facilis illo ex nihil ipsa amet officia, optio temporibus eum autem odit repellendus nisi. Possimus modi, corrupti error debitis doloribus dicta libero earum, sequi porro ut excepturi nostrum ea voluptatem nihil culpa? Ullam expedita eligendi obcaecati reiciendis velit provident omnis quas qui in corrupti est dolore facere ad hic, animi soluta assumenda consequuntur reprehenderit! Voluptate dolor nihil veniam laborum voluptas nisi pariatur sed optio accusantium quam consectetur, corrupti, sequi et consequuntur, excepturi doloremque. Tempore quis velit corporis neque fugit non sequi eaque rem hic. Facere, inventore, aspernatur. Accusantium modi atque, asperiores qui nobis soluta cumque suscipit excepturi possimus doloremque odit saepe perferendis temporibus molestiae nostrum voluptatum quis id sint quidem nesciunt culpa. Rerum labore dolor beatae blanditiis praesentium explicabo velit optio esse aperiam similique, voluptatem cum, maiores ipsa tempore. Reiciendis sed culpa atque inventore, nam ullam enim expedita consectetur id velit iusto alias vitae explicabo nemo neque odio reprehenderit soluta sint eaque. Aperiam, qui ut tenetur, voluptate doloremque officiis dicta quaerat voluptatem rerum natus magni. Eum amet autem dolor ullam.

      - - - -

      Lorem ipsum dolor sit amet, consectetur adipisicing elit. Distinctio maiores adipisci quibusdam repudiandae dolor vero placeat esse sit! Quibusdam saepe aperiam explicabo placeat optio, consequuntur nihil voluptatibus expedita quia vero perferendis, deserunt et incidunt eveniet temporibus doloremque possimus facilis. Possimus labore, officia dolore! Eaque ratione saepe, alias harum laboriosam deserunt laudantium blanditiis eum explicabo placeat reiciendis labore iste sint. Consectetur expedita dignissimos, non quos distinctio, eos rerum facilis eligendi. Asperiores laudantium, rerum ratione consequatur, culpa consectetur possimus atque ab tempore illum non dolor nesciunt. Neque, rerum. A vel non incidunt, quod doloremque dignissimos necessitatibus aliquid laboriosam architecto at cupiditate commodi expedita in, quae blanditiis. Deserunt labore sequi, repellat laboriosam est, doloremque culpa reiciendis tempore excepturi. Enim nostrum fugit itaque vel corporis ullam sed tenetur ipsa qui rem quam error sint, libero. Laboriosam rem, ratione. Autem blanditiis laborum neque repudiandae quam, cumque, voluptate veritatis itaque, placeat veniam ad nisi. Expedita, laborum reprehenderit ratione soluta velit natus, odit mollitia. Corporis rerum minima fugiat in nostrum. Assumenda natus cupiditate hic quidem ex, quas, amet ipsum esse dolore facilis beatae maxime qui inventore, iste? Maiores dignissimos dolore culpa debitis voluptatem harum, excepturi enim reiciendis, tempora ab ipsam illum aspernatur quasi qui porro saepe iure sunt eligendi tenetur quaerat ducimus quas sequi omnis aperiam suscipit! Molestiae obcaecati officiis quo, ratione eveniet, provident pariatur. Veniam quasi expedita distinctio, itaque molestiae sequi, dolorum nisi repellendus quia facilis iusto dignissimos nam? Tenetur fugit quos autem nihil, perspiciatis expedita enim tempore, alias ab maiores quis necessitatibus distinctio molestias eum, quidem. Delectus impedit quidem laborum, fugit vel neque quo, ipsam, quasi aspernatur quas odio nihil? Veniam amet reiciendis blanditiis quis reprehenderit repudiandae neque, ab ducimus, odit excepturi voluptate saepe ipsam. Voluptatem eum error voluptas porro officiis, amet! Molestias, fugit, ut! Tempore non magnam, amet, facere ducimus accusantium eos veritatis neque.

      +

      at provident praesentium atque quas rerum optio dignissimos repudiandae ullam illum quibusdam. Vel ad error + quibusdam, illo ex totam placeat. Quos excepturi fuga, molestiae ea quisquam minus, ratione dicta consectetur + officia omnis, doloribus voluptatibus? Veniam ipsum veritatis architecto, provident quas consequatur doloremque + quam quidem earum expedita, ad delectus voluptatum, omnis praesentium nostrum qui aspernatur ea eaque adipisci et + cumque ab? Ea voluptatum dolore itaque odio. Eius minima distinctio harum, officia ab nihil exercitationem. + Tempora rem nemo nam temporibus molestias facilis minus ipsam quam doloribus consequatur debitis nesciunt tempore + officiis aperiam quisquam, molestiae voluptates cum, fuga culpa. Distinctio accusamus quibusdam, tempore + perspiciatis dolorum optio facere consequatur quidem ullam beatae architecto, ipsam sequi officiis dignissimos + amet impedit natus necessitatibus tenetur repellendus dolor rem! Dicta dolorem, iure, facilis illo ex nihil ipsa + amet officia, optio temporibus eum autem odit repellendus nisi. Possimus modi, corrupti error debitis doloribus + dicta libero earum, sequi porro ut excepturi nostrum ea voluptatem nihil culpa? Ullam expedita eligendi obcaecati + reiciendis velit provident omnis quas qui in corrupti est dolore facere ad hic, animi soluta assumenda + consequuntur reprehenderit! Voluptate dolor nihil veniam laborum voluptas nisi pariatur sed optio accusantium quam + consectetur, corrupti, sequi et consequuntur, excepturi doloremque. Tempore quis velit corporis neque fugit non + sequi eaque rem hic. Facere, inventore, aspernatur. Accusantium modi atque, asperiores qui nobis soluta cumque + suscipit excepturi possimus doloremque odit saepe perferendis temporibus molestiae nostrum voluptatum quis id sint + quidem nesciunt culpa. Rerum labore dolor beatae blanditiis praesentium explicabo velit optio esse aperiam + similique, voluptatem cum, maiores ipsa tempore. Reiciendis sed culpa atque inventore, nam ullam enim expedita + consectetur id velit iusto alias vitae explicabo nemo neque odio reprehenderit soluta sint eaque. Aperiam, qui ut + tenetur, voluptate doloremque officiis dicta quaerat voluptatem rerum natus magni. Eum amet autem dolor ullam.

      + + + +

      Lorem ipsum dolor sit amet, consectetur adipisicing elit. Distinctio maiores adipisci quibusdam repudiandae dolor + vero placeat esse sit! Quibusdam saepe aperiam explicabo placeat optio, consequuntur nihil voluptatibus expedita + quia vero perferendis, deserunt et incidunt eveniet temporibus doloremque possimus facilis. Possimus labore, + officia dolore! Eaque ratione saepe, alias harum laboriosam deserunt laudantium blanditiis eum explicabo placeat + reiciendis labore iste sint. Consectetur expedita dignissimos, non quos distinctio, eos rerum facilis eligendi. + Asperiores laudantium, rerum ratione consequatur, culpa consectetur possimus atque ab tempore illum non dolor + nesciunt. Neque, rerum. A vel non incidunt, quod doloremque dignissimos necessitatibus aliquid laboriosam + architecto at cupiditate commodi expedita in, quae blanditiis. Deserunt labore sequi, repellat laboriosam est, + doloremque culpa reiciendis tempore excepturi. Enim nostrum fugit itaque vel corporis ullam sed tenetur ipsa qui + rem quam error sint, libero. Laboriosam rem, ratione. Autem blanditiis laborum neque repudiandae quam, cumque, + voluptate veritatis itaque, placeat veniam ad nisi. Expedita, laborum reprehenderit ratione soluta velit natus, + odit mollitia. Corporis rerum minima fugiat in nostrum. Assumenda natus cupiditate hic quidem ex, quas, amet ipsum + esse dolore facilis beatae maxime qui inventore, iste? Maiores dignissimos dolore culpa debitis voluptatem harum, + excepturi enim reiciendis, tempora ab ipsam illum aspernatur quasi qui porro saepe iure sunt eligendi tenetur + quaerat ducimus quas sequi omnis aperiam suscipit! Molestiae obcaecati officiis quo, ratione eveniet, provident + pariatur. Veniam quasi expedita distinctio, itaque molestiae sequi, dolorum nisi repellendus quia facilis iusto + dignissimos nam? Tenetur fugit quos autem nihil, perspiciatis expedita enim tempore, alias ab maiores quis + necessitatibus distinctio molestias eum, quidem. Delectus impedit quidem laborum, fugit vel neque quo, ipsam, + quasi aspernatur quas odio nihil? Veniam amet reiciendis blanditiis quis reprehenderit repudiandae neque, ab + ducimus, odit excepturi voluptate saepe ipsam. Voluptatem eum error voluptas porro officiis, amet! Molestias, + fugit, ut! Tempore non magnam, amet, facere ducimus accusantium eos veritatis neque.

      -

      Lorem ipsum dolor sit amet, consectetur adipisicing elit. Distinctio maiores adipisci quibusdam repudiandae dolor vero placeat esse sit! Quibusdam saepe aperiam explicabo placeat optio, consequuntur nihil voluptatibus expedita quia vero perferendis, deserunt et incidunt eveniet temporibus doloremque possimus facilis. Possimus labore, officia dolore! Eaque ratione saepe, alias harum laboriosam deserunt laudantium blanditiis eum explicabo placeat reiciendis labore iste sint. Consectetur expedita dignissimos, non quos distinctio, eos rerum facilis eligendi. Asperiores laudantium, rerum ratione consequatur, culpa consectetur possimus atque ab tempore illum non dolor nesciunt. Neque, rerum. A vel non incidunt, quod doloremque dignissimos necessitatibus aliquid laboriosam architecto at cupiditate commodi expedita in, quae blanditiis. Deserunt labore sequi, repellat laboriosam est, doloremque culpa reiciendis tempore excepturi. Enim nostrum fugit itaque vel corporis ullam sed tenetur ipsa qui rem quam error sint, libero. Laboriosam rem, ratione. Autem blanditiis laborum neque repudiandae quam, cumque, voluptate veritatis itaque, placeat veniam ad nisi. Expedita, laborum reprehenderit ratione soluta velit natus, odit mollitia. Corporis rerum minima fugiat in nostrum. Assumenda natus cupiditate hic quidem ex, quas, amet ipsum esse dolore facilis beatae maxime qui inventore, iste? Maiores dignissimos dolore culpa debitis voluptatem harum, excepturi enim reiciendis, tempora ab ipsam illum aspernatur quasi qui porro saepe iure sunt eligendi tenetur quaerat ducimus quas sequi omnis aperiam suscipit! Molestiae obcaecati officiis quo, ratione eveniet, provident pariatur. Veniam quasi expedita distinctio, itaque molestiae sequi, dolorum nisi repellendus quia facilis iusto dignissimos nam? Tenetur fugit quos autem nihil, perspiciatis expedita enim tempore, alias ab maiores quis necessitatibus distinctio molestias eum, quidem. Delectus impedit quidem laborum, fugit vel neque quo, ipsam, quasi aspernatur quas odio nihil? Veniam amet reiciendis blanditiis quis reprehenderit repudiandae neque, ab ducimus, odit excepturi voluptate saepe ipsam. Voluptatem eum error voluptas porro officiis, amet! Molestias, fugit, ut! Tempore non magnam, amet, facere ducimus accusantium eos veritatis neque.

      -

      Lorem ipsum dolor sit amet, consectetur adipisicing elit. Distinctio maiores adipisci quibusdam repudiandae dolor vero placeat esse sit! Quibusdam saepe aperiam explicabo placeat optio, consequuntur nihil voluptatibus expedita quia vero perferendis, deserunt et incidunt eveniet temporibus doloremque possimus facilis. Possimus labore, officia dolore! Eaque ratione saepe, alias harum laboriosam deserunt laudantium blanditiis eum explicabo placeat reiciendis labore iste sint. Consectetur expedita dignissimos, non quos distinctio, eos rerum facilis eligendi. Asperiores laudantium, rerum ratione consequatur, culpa consectetur possimus atque ab tempore illum non dolor nesciunt. Neque, rerum. A vel non incidunt, quod doloremque dignissimos necessitatibus aliquid laboriosam architecto at cupiditate commodi expedita in, quae blanditiis. Deserunt labore sequi, repellat laboriosam est, doloremque culpa reiciendis tempore excepturi. Enim nostrum fugit itaque vel corporis ullam sed tenetur ipsa qui rem quam error sint, libero. Laboriosam rem, ratione. Autem blanditiis laborum neque repudiandae quam, cumque, voluptate veritatis itaque, placeat veniam ad nisi. Expedita, laborum reprehenderit ratione soluta velit natus, odit mollitia. Corporis rerum minima fugiat in nostrum. Assumenda natus cupiditate hic quidem ex, quas, amet ipsum esse dolore facilis beatae maxime qui inventore, iste? Maiores dignissimos dolore culpa debitis voluptatem harum, excepturi enim reiciendis, tempora ab ipsam illum aspernatur quasi qui porro saepe iure sunt eligendi tenetur quaerat ducimus quas sequi omnis aperiam suscipit! Molestiae obcaecati officiis quo, ratione eveniet, provident pariatur. Veniam quasi expedita distinctio, itaque molestiae sequi, dolorum nisi repellendus quia facilis iusto dignissimos nam? Tenetur fugit quos autem nihil, perspiciatis expedita enim tempore, alias ab maiores quis necessitatibus distinctio molestias eum, quidem. Delectus impedit quidem laborum, fugit vel neque quo, ipsam, quasi aspernatur quas odio nihil? Veniam amet reiciendis blanditiis quis reprehenderit repudiandae neque, ab ducimus, odit excepturi voluptate saepe ipsam. Voluptatem eum error voluptas porro officiis, amet! Molestias, fugit, ut! Tempore non magnam, amet, facere ducimus accusantium eos veritatis neque.

      +

      Lorem ipsum dolor sit amet, consectetur adipisicing elit. Distinctio maiores adipisci quibusdam repudiandae dolor + vero placeat esse sit! Quibusdam saepe aperiam explicabo placeat optio, consequuntur nihil voluptatibus expedita + quia vero perferendis, deserunt et incidunt eveniet temporibus doloremque possimus facilis. Possimus labore, + officia dolore! Eaque ratione saepe, alias harum laboriosam deserunt laudantium blanditiis eum explicabo placeat + reiciendis labore iste sint. Consectetur expedita dignissimos, non quos distinctio, eos rerum facilis eligendi. + Asperiores laudantium, rerum ratione consequatur, culpa consectetur possimus atque ab tempore illum non dolor + nesciunt. Neque, rerum. A vel non incidunt, quod doloremque dignissimos necessitatibus aliquid laboriosam + architecto at cupiditate commodi expedita in, quae blanditiis. Deserunt labore sequi, repellat laboriosam est, + doloremque culpa reiciendis tempore excepturi. Enim nostrum fugit itaque vel corporis ullam sed tenetur ipsa qui + rem quam error sint, libero. Laboriosam rem, ratione. Autem blanditiis laborum neque repudiandae quam, cumque, + voluptate veritatis itaque, placeat veniam ad nisi. Expedita, laborum reprehenderit ratione soluta velit natus, + odit mollitia. Corporis rerum minima fugiat in nostrum. Assumenda natus cupiditate hic quidem ex, quas, amet ipsum + esse dolore facilis beatae maxime qui inventore, iste? Maiores dignissimos dolore culpa debitis voluptatem harum, + excepturi enim reiciendis, tempora ab ipsam illum aspernatur quasi qui porro saepe iure sunt eligendi tenetur + quaerat ducimus quas sequi omnis aperiam suscipit! Molestiae obcaecati officiis quo, ratione eveniet, provident + pariatur. Veniam quasi expedita distinctio, itaque molestiae sequi, dolorum nisi repellendus quia facilis iusto + dignissimos nam? Tenetur fugit quos autem nihil, perspiciatis expedita enim tempore, alias ab maiores quis + necessitatibus distinctio molestias eum, quidem. Delectus impedit quidem laborum, fugit vel neque quo, ipsam, + quasi aspernatur quas odio nihil? Veniam amet reiciendis blanditiis quis reprehenderit repudiandae neque, ab + ducimus, odit excepturi voluptate saepe ipsam. Voluptatem eum error voluptas porro officiis, amet! Molestias, + fugit, ut! Tempore non magnam, amet, facere ducimus accusantium eos veritatis neque.

      +

      Lorem ipsum dolor sit amet, consectetur adipisicing elit. Distinctio maiores adipisci quibusdam repudiandae dolor + vero placeat esse sit! Quibusdam saepe aperiam explicabo placeat optio, consequuntur nihil voluptatibus expedita + quia vero perferendis, deserunt et incidunt eveniet temporibus doloremque possimus facilis. Possimus labore, + officia dolore! Eaque ratione saepe, alias harum laboriosam deserunt laudantium blanditiis eum explicabo placeat + reiciendis labore iste sint. Consectetur expedita dignissimos, non quos distinctio, eos rerum facilis eligendi. + Asperiores laudantium, rerum ratione consequatur, culpa consectetur possimus atque ab tempore illum non dolor + nesciunt. Neque, rerum. A vel non incidunt, quod doloremque dignissimos necessitatibus aliquid laboriosam + architecto at cupiditate commodi expedita in, quae blanditiis. Deserunt labore sequi, repellat laboriosam est, + doloremque culpa reiciendis tempore excepturi. Enim nostrum fugit itaque vel corporis ullam sed tenetur ipsa qui + rem quam error sint, libero. Laboriosam rem, ratione. Autem blanditiis laborum neque repudiandae quam, cumque, + voluptate veritatis itaque, placeat veniam ad nisi. Expedita, laborum reprehenderit ratione soluta velit natus, + odit mollitia. Corporis rerum minima fugiat in nostrum. Assumenda natus cupiditate hic quidem ex, quas, amet ipsum + esse dolore facilis beatae maxime qui inventore, iste? Maiores dignissimos dolore culpa debitis voluptatem harum, + excepturi enim reiciendis, tempora ab ipsam illum aspernatur quasi qui porro saepe iure sunt eligendi tenetur + quaerat ducimus quas sequi omnis aperiam suscipit! Molestiae obcaecati officiis quo, ratione eveniet, provident + pariatur. Veniam quasi expedita distinctio, itaque molestiae sequi, dolorum nisi repellendus quia facilis iusto + dignissimos nam? Tenetur fugit quos autem nihil, perspiciatis expedita enim tempore, alias ab maiores quis + necessitatibus distinctio molestias eum, quidem. Delectus impedit quidem laborum, fugit vel neque quo, ipsam, + quasi aspernatur quas odio nihil? Veniam amet reiciendis blanditiis quis reprehenderit repudiandae neque, ab + ducimus, odit excepturi voluptate saepe ipsam. Voluptatem eum error voluptas porro officiis, amet! Molestias, + fugit, ut! Tempore non magnam, amet, facere ducimus accusantium eos veritatis neque.

      - + - + + \ No newline at end of file diff --git a/24 - Sticky Nav/style-START.css b/24 - Sticky Nav/style-START.css index b83b9c01ae..663f393244 100644 --- a/24 - Sticky Nav/style-START.css +++ b/24 - Sticky Nav/style-START.css @@ -25,10 +25,14 @@ body { transition: transform 0.5s; } +.fixed-nav .site-wrap { + transform: scale(1); +} + header { text-align: center; height: 50vh; - background: url(http://wes.io/iEgP/wow-so-deep.jpg) bottom center no-repeat; + background: url(https://source.unsplash.com/random/2000x500) bottom center no-repeat; background-size: cover; display: flex; align-items: center; @@ -50,6 +54,11 @@ nav { z-index: 1; } +.fixed-nav nav { + position: fixed; + box-shadow: 0 5px rgba(0,0,0,0.1); +} + nav ul { margin: 0; padding:0; @@ -74,6 +83,10 @@ li.logo { font-size: 30px; } +.fixed-nav li.logo { + max-width: 20%; +} + li.logo a { color: black; } diff --git a/24 - Sticky Nav/typescripts.js b/24 - Sticky Nav/typescripts.js new file mode 100644 index 0000000000..c5fd11dfe0 --- /dev/null +++ b/24 - Sticky Nav/typescripts.js @@ -0,0 +1,13 @@ +var nav = document.querySelector('#main'); +var topOfNav = nav.offsetTop; +function fixNav() { + if (window.scrollY >= topOfNav) { + document.body.style.paddingTop = nav.offsetHeight + 'px'; + document.body.classList.add('fixed-nav'); + } + else { + document.body.style.paddingTop = '0'; + document.body.classList.remove('fixed-nav'); + } +} +window.addEventListener('scroll', fixNav); diff --git a/24 - Sticky Nav/typescripts.ts b/24 - Sticky Nav/typescripts.ts new file mode 100644 index 0000000000..6acb5d5691 --- /dev/null +++ b/24 - Sticky Nav/typescripts.ts @@ -0,0 +1,25 @@ +/** + * JavaScript30 by Wes Bos, https://javascript30.com/ + * TypeScript implementation by Will Wager + * Project: Sticky Nav + * Concepts: Updating class on scroll + * Key takeaways: Let CSS do the work; Add padding when nav position changes. + * Sidenotes: Some HTML5 elements don't implement a custom DOM interface, and use HTMLElement. + * Compilation command: + * tsc --removeComments --strictNullChecks --noImplicitAny --target es5 typescripts.ts + */ + +const nav = document.querySelector('#main')! as HTMLElement; +const topOfNav = nav.offsetTop; + +function fixNav() { + if (window.scrollY >= topOfNav) { + document.body.style.paddingTop = nav.offsetHeight + 'px'; + document.body.classList.add('fixed-nav'); + } else { + document.body.style.paddingTop = '0'; + document.body.classList.remove('fixed-nav'); + } +} + +window.addEventListener('scroll', fixNav); \ No newline at end of file From 58d45ac2dedefb90e10d8a03fbb9c21498846dcb Mon Sep 17 00:00:00 2001 From: William Wager Date: Wed, 4 Mar 2020 13:03:24 -0500 Subject: [PATCH 26/34] Adding Wes's favicon --- favicon.ico | Bin 0 -> 41858 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 favicon.ico diff --git a/favicon.ico b/favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..ca475eca8d87e3c72805d3549562a086a43511d9 GIT binary patch literal 41858 zcmeHv2|Sfs_x~{;O6G{lK{O~s5=BUoqQRV$Ar~Q214+hIRH&N_2}PO5Oqqv@%2cMx zJe7#!WS-A|uWrxp=il$n_rCYN?|to$?b&DVwb%Nt_3UTw{p`K=gTqnaXmHHTICLf8 zPEg};IyfATK=|QzEXprLd17K;e+%MpW*j)2g2E5K*D2y~%Vbam6rjGE5DvH11&3RQ zexs@==ZAcB!Ql{}Zv*)s651wb$yH-BKi9J_l%Oye~pm-_BYS~MyP{@SK~9}n88W%qoFDCsjd;S-^X!s*ry4y zcFX545z>$cWk3V8PzS>J-29g^z?}biiX4t;vq)3q3>42GtPmj$c~Ay4Knwh!?!AGD zFL(=vr^z3t=f3bvLo$xEekN~!GxQ}w8uB0j4bXy)P#16v%=}RA3jz8Ezg{96i8c_w zL`eVt6yz^;FdeXZ3$J}h&aQW)FA>teC*&YqA^zTg%tMCwPY&Pq2fy_<^fLq$6;Oo! z=SzT&=bP|Pw&9{~ix&7#v%q`Qr=|=|l9PykZUmmd`mP|2 zAK(eRe<=V$82@6?SPJ8zX~!Rnzyo*z&tKO5f6*18vDE9s82R!ajKBkU{hBa?#x%fs z9nArJQS|8@`x39A>(vDj@*xlCAVM1Q7SdpOkPp0o4tRr%p9=3LX35_nd%?Wq2BL?1 zcdTug%vU=|mVY}$-i+oA(v3sp1I;9|0Lo*p8Tb+*4S7%oG(Zb=pf2zLUceK0gN&aF zm`-q?M$!EmL|~twHUo2|UetD*(fqJuYL+}XKmTREwYF}M3=!sDkOyTz1GG>F>H-ho z1w1iZ{g`~1d#W^%zRU}6_m7j~(epQf>Os5RhUQxz5zkL(K2?f%j-Y&)Tgf3kAwnAR zpbTh$7V1D<-~qgVC(JoP#<%laxF_!K$H*5^Taj!el38j#ku5q$$g?Ov5!HqHA;>U9 z_5{A2Q*-3oXui7o^}v@1X~=^zpaEK_19gE1@B*H|8)Sg2h3x?BxBB%U`2xb1jQRJ z50nohgEpczybs++On*p29+dqW9v};3CL`IuC%`)cH?lp~*9d9I`>R4ddbikAPb4o# zav?$*^8Ts-_Y(S5%>IzZ?(biP0opjUIf&o3_rD4Qj4Qu(Z24DUf<9znKk~1TvB-1L z0*e;-*ID43<$%BZC#+MTB~+XdivP1tu?GG4Cj9Fxu*iAQ0*e+{w7{YT7A>%7f&VrO zz`9^GdKdRcYgDjK_3wxv8!!Nt-x_+*S`)0ftU&MKu>P|0FODD+WCI4k@>>JEKUSlC zS6GY5Lwka-W(8|Fe?6()tJszSIT4ROvIaahsz=0yH zQ9>H_3??q;3alf;nm4RvW9yKRhCC<(8lZ(b zP#1UrFW?EhK?cae>{DO?_9nn@23yC4G~{6cXrT@S_z%2*C-8>fAPZ!IY`_3m025&Qr4Whqgt5Z|?L~kL z_#O3C_bF7}7~N0Uvw-~-?4APGAw&xi3$Tv>?E@mVrvPOb9YzT}fEVxt-XH@4$OPGd z0k8lj495=?|M!0v+G~OKW`rW_KkY?2uSZu|GzP-n55PN#?mM*KJ*W)sH;nCIKj^aq z(0&aBpmTfwzxIbTrW()yE#?mdJb)MQ1l~XgvOp%t1`L1&Fab8e_+tU;!TyipyP+?> zKrn8DP1q1$akO^_`$!OAuNa=IhOhf|uvY=L0lGW=KeSQUcY?h?to=h8@*n^W&_W$- zp96RSPi!9=WPwbe0}Ox#e3AegV8m?kh2htKxoEr-LVCj9$3yh|fd3QhH;N%Xuz&bd zV>t8^U^{5*`_Yy7$52PUv%76xF zq0W!D`%Z37y&C_2JG-GpuayYKwk;tEIhjyc1T0s!hZCR3IxnQ_8k9F zzBf@n19JilJ9dRUDEqqy=o@&y&K)r9V1LN_w%_H_1X9(q0(-UCQO9yVwAJK|o5 z3Hrs23-+-g{d0Zg!n%KlG(211qqdICe<1y5_7Q)DjwIBMFn?-D|0jlj_dfg|wHeF- zes1pZNBJ+-U$nrY1r{x^Xn{owELvdE0>8%s-?#%U{``wA0Df8uD7vHgKYm(}@lE(W z_ja+)q6HQ$uxNor3oKe-(E^JWShT>R1r{x^Xn{owELz~7XaP8@YlqG(|0l&i>wGcz za)5uw(&|rS=KqigSON2I@k9B!cAJUrzcupfz#_B*IK%#Tihv2j2Uo!SX9jGi7kp>I z=d0lJ^q22f!8fe_?Ga%COn?mnhV{?XALCW~^(;O3$${_9-ys4PIMWZ<{?*|v^34K2 zNASG>nSX}}SO61X`&S3(Q@}U175UV{cR~IR5wHNJKdZl6XhZNR27kka5qwp<|7H;| zEyM`vg}&1Zb^0x7@aq*p?MnptjDp`Ne2WjR@ZB8ng@p*|e@9#>e<3!&3Yam!<=>+3 zLR#?2hVS2ipRg?&U*P+R@I4xk1^%jVjtKnUz>f^`359&{`v+f6$b&LSV{suZRtLNO z6fM-n&LS+N1=)ZBWCA9@1{eV=Ux0a z3wQ!=pa)q{4zd9QU|Bfd1FV1an90Qkbfw~2r^_^mGtaCQJ>WA0yY76NEt-ht7= z83XvH5%^bQwSgYKRSEuM-}5C%@CF$m3p)b>^ne90Eet>l*n#%< z`1OL17_=c6TPo1p0s_du@L|&63>|#W2F_8WA|Ks_0sMl0%x@XSsjcYSPFP!p^pA~Q zKUN=PfGm)So!`T-05;4HfElo_K|1`_Z_a>EHrNgD!5N3KueJ?E_u>I+Z%k0hu6sAr`;}7$E>=?5qax|1G}n z;7<*GE7%VDdpO$w-Apda}BLcj8D{|9+c z1~fnmb)YWr0A5&s2Qokw$o%?Pet`m*7Gi{YfE{!IT|g($4Rrje0N;IsGbzhaT{y1? zXKdkohXk@U@CMA9sGo-K_5ECcxft9Ztj)j}2IDfEBZ4z?pw~jIkcK=c0~(-(Iv@{t z0I#1qABEunOn?ouD_{ofpabXvI)QHAekTvB5B%Xw7KRPlB=&tfIFAC~e}nHaVrQYS zdOvm@LH7^7qX_o^vm59G%a&hNqbIXF)W-}%Po5I@iL z*OfxEg}w{Un85lBoWFzfYS?oMHh?tbK^f2hE!07Oe_8;YKsV44bOoJ3cNllU4p9Cl ziu+OAaE2Jhu7$c|Z2ks3a z0eT7h7WH1Vz@h~fEwE^TMGGuiV9^4L7Fe{vq6HQ$uxNor z3;bRSeDgVg#h?FW7VtTAU=Je$Hv>|eaj%M!27E07BAyam>X_xlaX2Biy-GW^&NU5& zIRzix-8y8o&B`|2!E7(3*M9u9$M<5rshM|D=;fcw*+3{{?iiNa&@ZqdUzE~6-`hZm zxnxk1Q(bg}2;OtxnzDn6yBCgLPbj2M&soMwdydGvTDi=s4@a9J@WX6Q>jOtxX=^pgghK^Wi|fZz=D_{#o{mm*h{x*syPGuvFdU#jcQ! zBVJD&PCv-6raDinDL=zx{v8Kpo8{>zp6m*@NT>Z}qKcNjde&S0QFN}QJ1I+QqYA|q zs!r=n+9IZTJD=)<;#_Z2B_~}vt*tW~?kh0d>%=`qs4LHB9ql#e4$!Mbh zC}!quGH2Nw4HDwQ=^YKyHKjbBXXdV4vSPhEZI@sB`~9<-FSClc2KLW3tSU-qcz^gg zs>5KGlBt=ElRnLYbMJm&V?5rZ6J%DxPxFddp=Y4Js2^6 zkzu;3r*j)ObylA@AJyHg97|N8s9({3zKnUesoLd7oM(x$@m&iJQ zC~Uj@GowzX9DxJ{=_HZ&o{9|j!c%884aPe|5(@fhgbc=w1Kr{q9v(e}croH?R*_ew zex}_*rV&fEcbs+H>~m<BE)Q?4Y<1*&t{@fPA7&4>8midAAgM<=LKcG)Yj+ zSGYkL%hck;_*UuSj64!cPt0%ZXBA~e+^HPfmAoZCS*l&$UB6_#doF>RXXmTLK_ZTt z=jOJae$-&Xn5)LBq^3?S;Y7vm;=WtQ&TnZ7_*_=HhvA-xQRLw3rJS$o8@#iwuqzw` zIai(VLTS+h=NW^avX9)*2|DLNpgF`Fn|8Oq;*JE1@|bD;;WkXTI%nKx6Ok_*oGcT?Vkn8>XC~LQ{Q`1sw_GwZbn~N<}vtK(ua6OSy?kX-?ayFQt#G>O$9wU>hg>@MWvzbs#fwz4evwS-D?Wa^X2hA!fd>v zv|Z?}G$k*eTtCD_VPvN>(|}9&jd|FS)#LDZSCKQ6yWYp>N?q)eCAqF7E4& zC5aGacc-dbl}i%ehT%V-KY?S8Jl`8~v#`Q6EJ!g`Jy3tplsGYRaEY4?tBB$yue4P);;qCJgrL9_VZtIzGLM)c6A2{Ak&J0tk57!AQ5M(#FEy!!r z!PfYSvHH220O>&KjKArLV^(}#lT^)g;g(DatsNr;rAKPK(lW{1n!2U~PuDc|pFgpYFkISP)+&`V zv3&9g;iMOHw0h(yv&+Hwp_J~iHTS3CflqLeY$4zT#p|K zJ;VDuZI++JpIgo6wU;`fRjc`0{|vKr-}PO~R})SdOxspJ7Y)v&^)SpW5LG^8;&kS- zWBpq?26DR~&WkxcyvBNlJKJzs|7se)y-HRxB?D9ZlFLq>y|jh0q&0iC@}j{w3o()N ztWFcv{?YU}jxDKU!Y!_nqz6I-=6YGNTF0C~X$QWBOj6c%lcLW;^UqtW z@Q3>xh1pl{RO7cizWc$1)iZmB;E2lx4GnsGyn>vbH`z00zoD@jV^PF=-1{*6wswe9eh$xf z{{3y;<>ZK1mwH)uy@OOdp(oWhxU&cqU)CeiN1j>#VffN3Hkx+T_E6r*%Tk}sJGw7z z4iw=GpQh-prj;k(Jub4gsq4j%w@2~FBPQJ)nVz?wN2&&V?39r=nleA7UsQVPApg^t zf%Vp`LU_IolZ|B2K*Rkf=o%&rnAz~9tMcl&Cj&`Y1hs^7)4l~!swukH`qPUyR(;RC zgTK~|cz-d5JCE5>Wuq*O6oNIz#Q zswN|*5zme@dSKL)HbQREi{PCU%6_9`|As};o8T3aDU>}Z?9jjG(*25NZriT#S-%7t zp5zaO_{g!{(KP=k)~f%3Kq}J_V@Qb6LatG)#apRDqfpd@+l-U+U%CQdE$MZfqJH$`M%i( zrsIhGh><{p?3}yBo(DsxHrcl%8rBR@?)Tv6Ugdql)kacrBdO|1vGUIEGM}bRT5r=6 zYI&_a-a+2kQ5`36MSNl_WdvbgOi*F@iYc0SixeEurc`MU*S06wxomEC^k0i9Ue_08 zeR#}g<+#H@v}bDKD&6!J`2-6Zobis@8Of*-iHBtw5_BaJqB(OL%+F|RI~-^AA9P9x zl+J39)REjsR&yBH*U40GvCd!In(Ai66D=Ge(U_GcJX!NhAfdl&GCX^I-q}mN@&+I7 zw|rQV&}!HCar@d@GOwv@>3iZ9A(r$B4N3cxk{2nK$__ppa%r}Hk1NgE<0_PIJ$Cv# z3R0=;g~8AsK9Yz38_}&d@wTBmhSRg#jc|{H3OUc^-g(Jx*>yO5qIP(MkHcoG`tsf9 zMWd!=;;-8EjH`P3(`;Np$?NfEcnxpm`H~trogt1*WAFIml9#i{&v2z1#9E14DG*4^ zlN6boCb_Z=Kc-sRl*;~g~uk6d)m_4S^!RBE@D^$u$xz#h^J0C-L zBY_sDFquz}^H|<;5q6&7X_(NAyrMZ$+~pJz-D%ECD`%iNVi?RRI(ZGR=zc>1|1x)d zLebM6`Xy}##ozZa4bZgH(8>|bd38*9PoBA5t+CWDr@-%hL?`i+XN)-i;l2mcZS~SO zxMx@%=4six`{Lc!O}4N{uR`57`$)%C`J|0FuN#5VZ6D=o4$O%emD9R=q?*kri#Zoa zeO@a+gLjnjNM)YPD}2hJzP(|RLBPr5`0Cn94{p-Z^zdCcZ9_KcXm!igiArs|#!Q2S zZjfkrI>##v#_w-1d?%RVVG+7qKJX45+e01}j&qmuLW9RvW*gFmr!+}Y7bo_*n_pd< z#KRpRtU&Ih^T(I>KXR-P+caqRtdG-ql&mc$uu=57>)hAY?kK9zQ<(eZ;@ ztqt@@_MO&DTR%$`Oh*n$+!Ah>yb@FMrqC>pC)&c<&)wfUTF~!dnatJx)1@_X#!T&H ziM{bMJY}WLB9qeAcW?@i+1#>dQ#gqF>8*~qn~aMj8UrE zrqEljhBzINWi`0A90(H}e8iT^F3ES2v32fqP8!t3+n%19@ndG0*RdjPw<>QaF1uDF zWXYsHL$#)rS*yK#ASdJ8vNT!kEou9D!pb65#eB559vejp`3dZssAj?)6&|B9A6-Vh z@hyiBNwd*!=#=@cs@n#FEAPj*=qUQS5OOE?MQ&O@&t9CVDWB|Gn8knVbfrW8a(4>} zJtckCW3$$h;~pCd@R2Wv8<#n5J$&&Ey*vl0QNXDB<0_qgx@Urd`?BvyC)aY}#C*7} ziKz1rEwwQ?>$0?<`%KbYz#~co(QrsQYI1z0Z>IINOuRndrS*=6rl6C_ZU#DMN zXUvf3{GlP~i~Tb}4ckr(#(Z2Aqibq(ma_QimRsadZn}U}D(0=%d#1G7&3pHtSD?-a zTuuEe{_`P4r-za({o^Urn!UeYdZ&@Wi*=itZ=qY(v=3ro(&WuaqEQaOX9%(}(xlHU@2rO4b}-Bl_Kx`QvPhATM0~B*Qb=jL9JMDq@qA~i^y6IwWU#?WaEdd1}8<$iln8? zlMnF^T^&6ZUFH{W#MQ`BdYgvns89YLUtYZ&kxS2pYbJBnqHfshqQz11Wm?_5>XjF% zVrW=Oc@s??OygJQWH#39P;ZGjRJjXvgpQ-SyL;KS^v%|YCT5LDIF;T}+jZ6H#_PFD zXhe6YI>Ef(ceTO51sY?gZns3UXH6U3?U=m@tgQ3yVbf`74pVZOg%lS=8?w{|exOSxrTf>fTpCm6?;}!pr+1eiMc0m^qg15 z)6aQLqKUDupR|6KaV$8NW_HGHr#MsmAa|zJf%CmF^>43SYa9MfIXhUdW@akp1J|*O zJ}Y{bwzLK}51X3z#CS3utWGyNGRdP<9XhFMQz7VTb9U<13G21}VdncUNd)YqZh3IC ze@2(L{`;GCT%uuwxz!%P!+vHyFVXHRQBTV zN;P^?{ruo*{lb;8v|=F%DfDdeC<JeO5-1s7kJIWLky6`u4RC!eJ)M)^t+X=BJZe>zvfO+vt2-bqIRPC>}Gtzmg0n}ik9A( zp#)N7alkvPmNc1{*+iwjtK){&XWS@m;VI>2{KY%R6H2Hy+SX^9(hTwgp-tJVQNpo6`vj@=>?_MXfo#3#Ib*@y-1;)oFj+6%v%1?cl z%%HSX@O1`8&3T@--43ocSXh5%uT7|UiBVv)`^tP&(9$dU-9(I;y zE3NUni|y!MGYj_V*U;MvD^m0A9GgQ*P?gOFWY~$&33$a8M!Y`j;99PI$v%dZo!hO? zyy5dI4YXB!s z5zn^ER$kk8Ri8QU$Yv%x=OmIQA@Nu%S0d^zW?OC@>5AHE>9cNc(jeQ;-YsGcO>*k? zcXQd~CmuvNQ+9TpouIyjSLak8VczsvU2^_r*YkkQcILZY3GU>QFb^ZqRkRc0MKw+K z!&M`_tLp&4VG4Xg5`ip!N^9*ao5O=8}OW73JL+b5JYx%#dt-$A zdETx|y(hqk^PiESEd1W5Hp%hs{p<+-Sw5mITN{oRoOKV-65i)#llXU4>@#!oonsPAT!6qkAUMhiMp1uyL4pp1V;l)gG|kxn@?gTjc%V% z_0FQMvgXx_+*D#II($WV)KkGI(^2{Qu}cyOb4r7@XC-ed`R3~n$yOX_)v7P1-(;_N z=5uCUo9bb~{^Mw-vC00r#QD6iT$;(laei#k;srA;9ilHzW$FegTKaU?PrepBu1>9! zi-e2c;tbk1v@gIWYUZd~Olgk0l~4Ee9-5uGj)(i6?sG0)VR&6Ta=h{3^9D}~*$zg5 zeUHv0{hw`bW(K8hT^j;S_9848WA2rjWQLtI9xvJ;c>t}C_9y&X` zS%H^yJrlQOtu|+lh4B^X$RZHrU_8IQZ5VX8! zyn}H3qjd~*L~mr7YnouY=-vENq-|oIXpFgeq|2+d2(8QnOR{H|@xMtLPBlB@dU@TB zx+bPXv5Cxq=o-_l;TDXpoQGd%u@Fw-jRl-`p7iI5_wB1=mK^sTH;htRmY{2#@T^9z z%a1Jg+={{Lq0%zV%Eps4djk%{Z!#GlDONTQ)uZxK@Lk1m?7~^bsP$@*ma{7HgL?z2 z-<5Cc(BJh&=1De=heD1PP3m6B$XlP8PuXsk5@&VVo1EemrJ^8?O3AENZ2Uq!o=`4 zjU_p#Fh=Q!ui3pa|Eq)c*BTx8OJ81p`E*~<>#?b~wLBZDYXT@u_WQa$2xz|QtY2`Z zgzrG~{6IWs*I@Vtvgm+cew9f*{Myg8LUp`tDFfEEC)gu&t_!#)9oG8Jhu1KQJmVCpG3jvj#A#c zdP|utdkTD8<0!25joJyGm!_oc5Lh#;U-WYLU`}_DCjU?}7d};naFV)hr7qK{2}YT- znv#9d;-u?gxjuI)s4ja3W<V=sF*FJ5usI{LJzCVf!v`qr}GSzA%o+P1*uO zW3_J0Ny+Z9F6YZb&bD{mn-@@gCaa=a*|kigdyn$8NJ8rq#zGPuWeQ0{Ogv{MI>OLb z46U7YJtQA_B3a-g|L%!=XhoNDr*(Rk;R~S=C2CqtwBL|rxIW)n(vX|an2B7Ous$gx zsIWQoF^_RqukPuI{c4rP2j%f@_daMF1(%_LwJOViF5{_>B;8!leF_nl#E)U*i|cmm zW)e0^TydXo_w%1ltr;#`qjtnoF++=Q+)gU+os}_^F6t{*tF2x_-Wd1wkKTf z9?xsu-)(8_@gs{*5_w#Sdu_Xt!=ACX1V2|HWj$A(sc5UZ=* zQUyMFXdI?UsThzXPV!cy(Z-Z)Tvs+>rwo8ULH>Llkg|H{3ZD%hB#x7enf2r+n9O$giwW-Qy*?I*6LD-rUCX;&Z%*5q zyzcaTXO)xZ)9;Mdh3a$JI<}b=eO%gZ#^m~@X2<2?q&Lbu_?2b_9p@NEmw1jd?#L~_^_07 zk)@EX&U=;d(+7L9X7fmnY7NoF8OP8p=Hu*^*MY{z3Dks*M4MqDqC@%6M*A6aab^m& zO{u|0?r8CK%MqA^l~QXj@1-fhsN3|1O%+^c~C0g-#y7b(wuVV!!mvr0jK*RM_0VcsZI%`Mh*NW<1F%o&us_X24z`N{fQ6-s!WV1)|`!gPDwTGTi74zkwEXkRn zb!?{&4BuByaMGv3_o{mz0VYBCv< zS0B|$Q5$a$Q9u5s=zU#LadCR<``UvvLPsv_j*4)tze~*ImS+$SV|**2_~;Nt;u%Tv zIprr*M_Cln@|^gx(R6>QGg}1oq;a~}sbUM=*hCtZQW$aTcJHz8&AcZgtx~#7x0~1E zfKBjaCeI}}p5A$fcj-aYRIyF|!q3_oE(y^q@P|Y^-zM~94ks36vI>LlHLb`CAt3#^ z?Ljeh=eWX&yV>+sgb`gFVHoY9AlCqQ-KGHD&4wjg?mLE?isW+LI-Fn~5;i4_v+Y_f zb5^1$XZwNSt<*}@2U^uK3r4FY^sOrfDs?Gv6Q})kk3??@Asek(DL)b1W?wd&e|yA% zdFduK|BZ2?gaId+tD)JHH&pI;u)D9RM^%h!A8UzyFSIKlc{{OB!|=l=0vAit;CG@f z5hS`^>(;#+s61nL9BF;5W# zIZlzrkeM`aG%NN-#xhTf{2M#d8Uh2p3tytZZ?SPC!(8a*mMhDbc^bDJ@Kd>Sph5$e zrGP8tMO$v0on5N*Zg(o$0s&aGRTNt62RhDBH zHc8&Ox$MN+Dh`~Tc@L-SxV_hHr%#->GVrL^c2st4`*`M+#EE_amsiz5P;a`XTCIjy zI@({A8u@Udd(VGhz*j$PBYmTm`dcn@ca?F?4^o-%F9y!G&$33Wd#?sN$ z@T^zxD1I+9r5C&909x0wndfI-v2-oHWbKkQ^pYC5?~%(5VKFg6rno|R Date: Wed, 4 Mar 2020 13:44:45 -0500 Subject: [PATCH 27/34] Adding remaining TS files --- .../typescripts.ts | 10 ++++++++++ 26 - Stripe Follow Along Nav/typescripts.ts | 10 ++++++++++ 27 - Click and Drag/typescripts.ts | 10 ++++++++++ 28 - Video Speed Controller/typescripts.ts | 10 ++++++++++ 29 - Countdown Timer/typescripts.ts | 10 ++++++++++ 30 - Whack A Mole/typescripts.ts | 10 ++++++++++ 6 files changed, 60 insertions(+) create mode 100644 25 - Event Capture, Propagation, Bubbling and Once/typescripts.ts create mode 100644 26 - Stripe Follow Along Nav/typescripts.ts create mode 100644 27 - Click and Drag/typescripts.ts create mode 100644 28 - Video Speed Controller/typescripts.ts create mode 100644 29 - Countdown Timer/typescripts.ts create mode 100644 30 - Whack A Mole/typescripts.ts diff --git a/25 - Event Capture, Propagation, Bubbling and Once/typescripts.ts b/25 - Event Capture, Propagation, Bubbling and Once/typescripts.ts new file mode 100644 index 0000000000..2621ff1235 --- /dev/null +++ b/25 - Event Capture, Propagation, Bubbling and Once/typescripts.ts @@ -0,0 +1,10 @@ +/** + * JavaScript30 by Wes Bos, https://javascript30.com/ + * TypeScript implementation by Will Wager + * Project: + * Concepts: + * Key takeaways: + * Sidenotes: + * Compilation command: + * tsc --removeComments --strictNullChecks --noImplicitAny --target es5 typescripts.ts + */ diff --git a/26 - Stripe Follow Along Nav/typescripts.ts b/26 - Stripe Follow Along Nav/typescripts.ts new file mode 100644 index 0000000000..2621ff1235 --- /dev/null +++ b/26 - Stripe Follow Along Nav/typescripts.ts @@ -0,0 +1,10 @@ +/** + * JavaScript30 by Wes Bos, https://javascript30.com/ + * TypeScript implementation by Will Wager + * Project: + * Concepts: + * Key takeaways: + * Sidenotes: + * Compilation command: + * tsc --removeComments --strictNullChecks --noImplicitAny --target es5 typescripts.ts + */ diff --git a/27 - Click and Drag/typescripts.ts b/27 - Click and Drag/typescripts.ts new file mode 100644 index 0000000000..2621ff1235 --- /dev/null +++ b/27 - Click and Drag/typescripts.ts @@ -0,0 +1,10 @@ +/** + * JavaScript30 by Wes Bos, https://javascript30.com/ + * TypeScript implementation by Will Wager + * Project: + * Concepts: + * Key takeaways: + * Sidenotes: + * Compilation command: + * tsc --removeComments --strictNullChecks --noImplicitAny --target es5 typescripts.ts + */ diff --git a/28 - Video Speed Controller/typescripts.ts b/28 - Video Speed Controller/typescripts.ts new file mode 100644 index 0000000000..2621ff1235 --- /dev/null +++ b/28 - Video Speed Controller/typescripts.ts @@ -0,0 +1,10 @@ +/** + * JavaScript30 by Wes Bos, https://javascript30.com/ + * TypeScript implementation by Will Wager + * Project: + * Concepts: + * Key takeaways: + * Sidenotes: + * Compilation command: + * tsc --removeComments --strictNullChecks --noImplicitAny --target es5 typescripts.ts + */ diff --git a/29 - Countdown Timer/typescripts.ts b/29 - Countdown Timer/typescripts.ts new file mode 100644 index 0000000000..2621ff1235 --- /dev/null +++ b/29 - Countdown Timer/typescripts.ts @@ -0,0 +1,10 @@ +/** + * JavaScript30 by Wes Bos, https://javascript30.com/ + * TypeScript implementation by Will Wager + * Project: + * Concepts: + * Key takeaways: + * Sidenotes: + * Compilation command: + * tsc --removeComments --strictNullChecks --noImplicitAny --target es5 typescripts.ts + */ diff --git a/30 - Whack A Mole/typescripts.ts b/30 - Whack A Mole/typescripts.ts new file mode 100644 index 0000000000..2621ff1235 --- /dev/null +++ b/30 - Whack A Mole/typescripts.ts @@ -0,0 +1,10 @@ +/** + * JavaScript30 by Wes Bos, https://javascript30.com/ + * TypeScript implementation by Will Wager + * Project: + * Concepts: + * Key takeaways: + * Sidenotes: + * Compilation command: + * tsc --removeComments --strictNullChecks --noImplicitAny --target es5 typescripts.ts + */ From de57810d1a55709a20c7df0647af007b7e840402 Mon Sep 17 00:00:00 2001 From: William Wager Date: Wed, 4 Mar 2020 13:57:40 -0500 Subject: [PATCH 28/34] Project 25 complete --- .../index-START.html | 67 ++++++++++--------- .../typescripts.js | 14 ++++ .../typescripts.ts | 25 ++++++- 3 files changed, 71 insertions(+), 35 deletions(-) create mode 100644 25 - Event Capture, Propagation, Bubbling and Once/typescripts.js diff --git a/25 - Event Capture, Propagation, Bubbling and Once/index-START.html b/25 - Event Capture, Propagation, Bubbling and Once/index-START.html index 7bd5931e01..06ffda71e0 100644 --- a/25 - Event Capture, Propagation, Bubbling and Once/index-START.html +++ b/25 - Event Capture, Propagation, Bubbling and Once/index-START.html @@ -1,9 +1,11 @@ + Understanding JavaScript's Capture +
      @@ -13,36 +15,37 @@
      - - - - + + + + - + + \ No newline at end of file diff --git a/25 - Event Capture, Propagation, Bubbling and Once/typescripts.js b/25 - Event Capture, Propagation, Bubbling and Once/typescripts.js new file mode 100644 index 0000000000..b802a5f555 --- /dev/null +++ b/25 - Event Capture, Propagation, Bubbling and Once/typescripts.js @@ -0,0 +1,14 @@ +var divs = document.querySelectorAll('div'); +var button = document.querySelector('button'); +function logText(e) { + console.log(this.classList.value); +} +divs.forEach(function (div) { return div.addEventListener('click', logText, { + capture: false, + once: true, +}); }); +button.addEventListener('click', function () { + console.log('Click!!!'); +}, { + once: true, +}); diff --git a/25 - Event Capture, Propagation, Bubbling and Once/typescripts.ts b/25 - Event Capture, Propagation, Bubbling and Once/typescripts.ts index 2621ff1235..bbc341fca3 100644 --- a/25 - Event Capture, Propagation, Bubbling and Once/typescripts.ts +++ b/25 - Event Capture, Propagation, Bubbling and Once/typescripts.ts @@ -1,10 +1,29 @@ /** * JavaScript30 by Wes Bos, https://javascript30.com/ * TypeScript implementation by Will Wager - * Project: - * Concepts: - * Key takeaways: + * Project: Event Capture, Propogation, Bubbling and Once + * Concepts: Event propogation - capture & bubbling + * Key takeaways: Event propogation; listener options - capture, once * Sidenotes: * Compilation command: * tsc --removeComments --strictNullChecks --noImplicitAny --target es5 typescripts.ts */ + +const divs = document.querySelectorAll('div'); +const button = document.querySelector('button')!; + +function logText(e: Event) { + console.log(this.classList.value); + // e.stopPropagation(); +} + +divs.forEach(div => div.addEventListener('click', logText, { + capture: false, + once: true, +})); + +button.addEventListener('click', () => { + console.log('Click!!!'); +}, { + once: true, +}); From 11eb190dede7a33535c73404641d060ac84dbc40 Mon Sep 17 00:00:00 2001 From: William Wager Date: Wed, 4 Mar 2020 14:44:33 -0500 Subject: [PATCH 29/34] Project 26 complete --- 26 - Stripe Follow Along Nav/index-START.html | 311 +++++++++--------- 26 - Stripe Follow Along Nav/typescripts.js | 29 ++ 26 - Stripe Follow Along Nav/typescripts.ts | 47 ++- 3 files changed, 234 insertions(+), 153 deletions(-) create mode 100644 26 - Stripe Follow Along Nav/typescripts.js diff --git a/26 - Stripe Follow Along Nav/index-START.html b/26 - Stripe Follow Along Nav/index-START.html index 608d0a6716..d36e6cba21 100644 --- a/26 - Stripe Follow Along Nav/index-START.html +++ b/26 - Stripe Follow Along Nav/index-START.html @@ -1,9 +1,11 @@ + Follow Along Nav +

      Cool

      - - - + + + - + + \ No newline at end of file diff --git a/26 - Stripe Follow Along Nav/typescripts.js b/26 - Stripe Follow Along Nav/typescripts.js new file mode 100644 index 0000000000..a926cf90a4 --- /dev/null +++ b/26 - Stripe Follow Along Nav/typescripts.js @@ -0,0 +1,29 @@ +var triggers = document.querySelectorAll('.cool > li'); +var background = document.querySelector('.dropdownBackground'); +var nav = document.querySelector('.top'); +function handleEnter() { + var _this = this; + this.classList.add('trigger-enter'); + setTimeout(function () { + return _this.classList.contains('trigger-enter') && _this.classList.add('trigger-enter-active'); + }, 150); + background.classList.add('open'); + var dropdown = this.querySelector('.dropdown'); + var dropdownCoords = dropdown.getBoundingClientRect(); + var navCoords = nav.getBoundingClientRect(); + var coords = { + width: dropdownCoords.width, + height: dropdownCoords.height, + top: dropdownCoords.top - navCoords.top, + left: dropdownCoords.left - navCoords.left, + }; + background.style.setProperty('width', coords.width + "px"); + background.style.setProperty('height', coords.height + "px"); + background.style.setProperty('transform', "translate(" + coords.left + "px, " + coords.top + "px)"); +} +function handleLeave() { + this.classList.remove('trigger-enter', 'trigger-enter-active'); + background.classList.remove('open'); +} +triggers.forEach(function (trigger) { return trigger.addEventListener('mouseenter', handleEnter); }); +triggers.forEach(function (trigger) { return trigger.addEventListener('mouseleave', handleLeave); }); diff --git a/26 - Stripe Follow Along Nav/typescripts.ts b/26 - Stripe Follow Along Nav/typescripts.ts index 2621ff1235..dee3601837 100644 --- a/26 - Stripe Follow Along Nav/typescripts.ts +++ b/26 - Stripe Follow Along Nav/typescripts.ts @@ -1,10 +1,49 @@ /** * JavaScript30 by Wes Bos, https://javascript30.com/ * TypeScript implementation by Will Wager - * Project: - * Concepts: - * Key takeaways: - * Sidenotes: + * Project: Stripe Follow Along Dropdown + * Concepts: Updating and showing dropdown on "hover" + * Key takeaways: Use the dropdown's container as the trigger; + * Adjust the same background element for each; + * Calculate bg size from dropdown's getBoundingClientRect; + * Calculate bg coordinates from dropdown's rectangle and + * subtract the offset of the container + * Sidenotes: Further improvement is adding fold-down animation when first entering the ul. * Compilation command: * tsc --removeComments --strictNullChecks --noImplicitAny --target es5 typescripts.ts */ + +const triggers = document.querySelectorAll('.cool > li')! as NodeListOf; +const background = document.querySelector('.dropdownBackground')! as HTMLDivElement; +const nav = document.querySelector('.top')! as HTMLElement; + +function handleEnter() { + this.classList.add('trigger-enter'); + setTimeout(() => + this.classList.contains('trigger-enter') && this.classList.add('trigger-enter-active'), 150); + background.classList.add('open'); + + const dropdown = this.querySelector('.dropdown'); + const dropdownCoords = dropdown.getBoundingClientRect(); + const navCoords = nav.getBoundingClientRect(); + + const coords = { + width: dropdownCoords.width, + height: dropdownCoords.height, + top: dropdownCoords.top - navCoords.top, + left: dropdownCoords.left - navCoords.left, + }; + + background.style.setProperty('width', `${coords.width}px`); + background.style.setProperty('height', `${coords.height}px`); + background.style.setProperty('transform', `translate(${coords.left}px, ${coords.top}px)`); + +} + +function handleLeave() { + this.classList.remove('trigger-enter', 'trigger-enter-active'); + background.classList.remove('open'); +} + +triggers.forEach(trigger => trigger.addEventListener('mouseenter', handleEnter)); +triggers.forEach(trigger => trigger.addEventListener('mouseleave', handleLeave)); From 0bce3ea2f1a7f809d6498097e21de404e25afdba Mon Sep 17 00:00:00 2001 From: William Wager Date: Wed, 4 Mar 2020 15:26:32 -0500 Subject: [PATCH 30/34] Project 27 complete --- 27 - Click and Drag/index-START.html | 10 ++++---- 27 - Click and Drag/typescripts.js | 25 ++++++++++++++++++++ 27 - Click and Drag/typescripts.ts | 35 ++++++++++++++++++++++++---- 3 files changed, 62 insertions(+), 8 deletions(-) create mode 100644 27 - Click and Drag/typescripts.js diff --git a/27 - Click and Drag/index-START.html b/27 - Click and Drag/index-START.html index b8609315f7..708ab05a18 100644 --- a/27 - Click and Drag/index-START.html +++ b/27 - Click and Drag/index-START.html @@ -1,10 +1,12 @@ + Click and Drag +
      01
      @@ -34,8 +36,8 @@
      25
      - + + + - - + \ No newline at end of file diff --git a/27 - Click and Drag/typescripts.js b/27 - Click and Drag/typescripts.js new file mode 100644 index 0000000000..1860679e9c --- /dev/null +++ b/27 - Click and Drag/typescripts.js @@ -0,0 +1,25 @@ +var slider = document.querySelector('.items'); +var isDown = false; +var startX, scrollLeft; +slider.addEventListener('mousedown', function (e) { + isDown = true; + slider.classList.add('active'); + startX = e.pageX - slider.offsetLeft; + scrollLeft = slider.scrollLeft; +}); +slider.addEventListener('mouseleave', function () { + isDown = false; + slider.classList.remove('active'); +}); +slider.addEventListener('mouseup', function () { + isDown = false; + slider.classList.remove('active'); +}); +slider.addEventListener('mousemove', function (e) { + if (!isDown) + return; + e.preventDefault(); + var x = e.pageX - slider.offsetLeft; + var walk = (x - startX) * 3; + slider.scrollLeft = scrollLeft - walk; +}); diff --git a/27 - Click and Drag/typescripts.ts b/27 - Click and Drag/typescripts.ts index 2621ff1235..5bed7f8980 100644 --- a/27 - Click and Drag/typescripts.ts +++ b/27 - Click and Drag/typescripts.ts @@ -1,10 +1,37 @@ /** * JavaScript30 by Wes Bos, https://javascript30.com/ * TypeScript implementation by Will Wager - * Project: - * Concepts: - * Key takeaways: - * Sidenotes: + * Project: Click and Drag to Scroll + * Concepts: Mouse events to set a div's horizontal scroll. + * Key takeaways: Drag and drop event pattern; isDown (isDrawing) pattern; + * Recalculate scroll from mousedown event. + * Sidenotes: Drag and dropping an element can be done similarly. * Compilation command: * tsc --removeComments --strictNullChecks --noImplicitAny --target es5 typescripts.ts */ + +const slider = document.querySelector('.items')! as HTMLDivElement; +let isDown = false; +let startX: number, scrollLeft: number; + +slider.addEventListener('mousedown', (e: MouseEvent) => { + isDown = true; + slider.classList.add('active'); + startX = e.pageX - slider.offsetLeft; + scrollLeft = slider.scrollLeft; +}); +slider.addEventListener('mouseleave', () => { + isDown = false; + slider.classList.remove('active'); +}); +slider.addEventListener('mouseup', () => { + isDown = false; + slider.classList.remove('active'); +}); +slider.addEventListener('mousemove', (e) => { + if (!isDown) return; + e.preventDefault(); + const x = e.pageX - slider.offsetLeft; + const walk = (x - startX) * 3; + slider.scrollLeft = scrollLeft - walk; +}); From 9eb7134f5fa2782242d9e97ae84870d35d7a7711 Mon Sep 17 00:00:00 2001 From: William Wager Date: Wed, 4 Mar 2020 20:24:08 -0500 Subject: [PATCH 31/34] Project 28 complete --- 28 - Video Speed Controller/index-START.html | 11 +++++--- 28 - Video Speed Controller/typescripts.js | 15 ++++++++++ 28 - Video Speed Controller/typescripts.ts | 29 +++++++++++++++++--- 3 files changed, 47 insertions(+), 8 deletions(-) create mode 100644 28 - Video Speed Controller/typescripts.js diff --git a/28 - Video Speed Controller/index-START.html b/28 - Video Speed Controller/index-START.html index 8bd536b18b..81e24b26b1 100644 --- a/28 - Video Speed Controller/index-START.html +++ b/28 - Video Speed Controller/index-START.html @@ -1,20 +1,23 @@ + Video Speed Scrubber +
      - +
      - + - + + \ No newline at end of file diff --git a/28 - Video Speed Controller/typescripts.js b/28 - Video Speed Controller/typescripts.js new file mode 100644 index 0000000000..371f2dc84f --- /dev/null +++ b/28 - Video Speed Controller/typescripts.js @@ -0,0 +1,15 @@ +var speed = document.querySelector('.speed'); +var bar = document.querySelector('.speed-bar'); +var video = document.querySelector('.flex'); +function handleMove(e) { + var y = e.pageY - this.offsetTop; + var percent = y / this.offsetHeight; + var min = 0.4; + var max = 4; + var height = Math.round(percent * 100) + '%'; + var playbackRate = percent * (max - min) + min; + bar.style.height = height; + bar.textContent = playbackRate.toFixed(2) + 'x'; + video.playbackRate = playbackRate; +} +speed.addEventListener('mousemove', handleMove); diff --git a/28 - Video Speed Controller/typescripts.ts b/28 - Video Speed Controller/typescripts.ts index 2621ff1235..73c93d281d 100644 --- a/28 - Video Speed Controller/typescripts.ts +++ b/28 - Video Speed Controller/typescripts.ts @@ -1,10 +1,31 @@ /** * JavaScript30 by Wes Bos, https://javascript30.com/ * TypeScript implementation by Will Wager - * Project: - * Concepts: - * Key takeaways: - * Sidenotes: + * Project: Video Speed Controller + * Concepts: Calculating percent of element above mouse position; Video API + * Key takeaways: Use pageX/Y and offsetTop/Left when scrolling doesn't matter. + * https://stackoverflow.com/questions/6073505/what-is-the-difference-between-screenx-y-clientx-y-and-pagex-y + * https://stackoverflow.com/questions/44172651/difference-between-getboundingclientrect-top-and-offsettop + * Sidenotes: As a general rule, I'll start casting everything selected from the DOM, + * whether the code requires it or not. * Compilation command: * tsc --removeComments --strictNullChecks --noImplicitAny --target es5 typescripts.ts */ + +const speed = document.querySelector('.speed')! as HTMLDivElement; +const bar = document.querySelector('.speed-bar')! as HTMLDivElement; +const video = document.querySelector('.flex')! as HTMLVideoElement; + +function handleMove(e: MouseEvent) { + const y = e.pageY - this.offsetTop; + const percent = y / this.offsetHeight; + const min = 0.4; + const max = 4; + const height = Math.round(percent * 100) + '%'; + const playbackRate = percent * (max - min) + min; + bar.style.height = height; + bar.textContent = playbackRate.toFixed(2) + 'x'; + video.playbackRate = playbackRate; +} + +speed.addEventListener('mousemove', handleMove); From dd8ba2517de80f739a8a05ebad234368c32f30bd Mon Sep 17 00:00:00 2001 From: William Wager Date: Wed, 4 Mar 2020 23:33:15 -0500 Subject: [PATCH 32/34] Project 29 complete. --- 29 - Countdown Timer/index.html | 7 +++- 29 - Countdown Timer/typescripts.ts | 65 +++++++++++++++++++++++++++-- 2 files changed, 66 insertions(+), 6 deletions(-) diff --git a/29 - Countdown Timer/index.html b/29 - Countdown Timer/index.html index d54f447dd9..cace278615 100644 --- a/29 - Countdown Timer/index.html +++ b/29 - Countdown Timer/index.html @@ -1,11 +1,13 @@ + Countdown Timer +
      @@ -24,6 +26,7 @@

      - + - + + \ No newline at end of file diff --git a/29 - Countdown Timer/typescripts.ts b/29 - Countdown Timer/typescripts.ts index 2621ff1235..c4cbb57ba8 100644 --- a/29 - Countdown Timer/typescripts.ts +++ b/29 - Countdown Timer/typescripts.ts @@ -1,10 +1,67 @@ /** * JavaScript30 by Wes Bos, https://javascript30.com/ * TypeScript implementation by Will Wager - * Project: - * Concepts: - * Key takeaways: - * Sidenotes: + * Project: Countdown Timer + * Concepts: Using Date and setInterval. Displaying countdowns to the DOM. + * Key takeaways: Use Date, not a counter with setInterval. + * Preceeding zero for single digits pattern. + * Sidenotes: name attribute allows access through document global, but it's not very + * Typescript friendly. * Compilation command: * tsc --removeComments --strictNullChecks --noImplicitAny --target es5 typescripts.ts */ + +interface MyDocument extends Document { + customForm: HTMLFormElement; +} + +let countdown: number; +const timerDisplay = document.querySelector('.display__time-left')! as HTMLHeadingElement; +const endTime = document.querySelector('.display__end-time')! as HTMLParagraphElement; +const buttons = document.querySelectorAll('[data-time]')! as NodeListOf; + +function timer(seconds: number) { + clearInterval(countdown); + const now = Date.now(); + const then = now + seconds * 1000; + displayTimeLeft(seconds); + displayEndTime(then); + + countdown = setInterval(() => { + const secondsLeft = Math.round((then - Date.now()) / 1000); + if (secondsLeft < 0) { + clearInterval(countdown); + return; + } + displayTimeLeft(secondsLeft); + }, 1000); +} + +function displayTimeLeft(seconds: number) { + const minutes = Math.floor(seconds / 60); + const remainderSeconds = seconds % 60; + const display = `${minutes}:${remainderSeconds < 10 ? '0' : ''}${remainderSeconds}`; + document.title = display; + timerDisplay.textContent = display; +} + +function displayEndTime(timestamp: number) { + const end = new Date(timestamp); + const hour = end.getHours(); + const adjustedHour = hour > 12 ? hour - 12 : hour; + const minutes = end.getMinutes(); + endTime.textContent = `Be back at ${adjustedHour}:${minutes < 10 ? '0' : ''}${minutes}`; +} + +function startTimer() { + const seconds = Number(this.dataset.time); + timer(seconds); +} + +buttons.forEach(button => button.addEventListener('click', startTimer)); +(document as MyDocument).customForm.addEventListener('submit', function (this: HTMLFormElement, e: Event) { + e.preventDefault(); + const mins = this.minutes.value; + timer(mins * 60); + this.reset(); +}) \ No newline at end of file From 93dd5d279afec97a08bb7b71a663d6136d9c722e Mon Sep 17 00:00:00 2001 From: William Wager Date: Thu, 5 Mar 2020 17:58:20 -0500 Subject: [PATCH 33/34] Including JS from project 29 --- 29 - Countdown Timer/typescripts.js | 44 +++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 29 - Countdown Timer/typescripts.js diff --git a/29 - Countdown Timer/typescripts.js b/29 - Countdown Timer/typescripts.js new file mode 100644 index 0000000000..4631cf6cb0 --- /dev/null +++ b/29 - Countdown Timer/typescripts.js @@ -0,0 +1,44 @@ +var countdown; +var timerDisplay = document.querySelector('.display__time-left'); +var endTime = document.querySelector('.display__end-time'); +var buttons = document.querySelectorAll('[data-time]'); +function timer(seconds) { + clearInterval(countdown); + var now = Date.now(); + var then = now + seconds * 1000; + displayTimeLeft(seconds); + displayEndTime(then); + countdown = setInterval(function () { + var secondsLeft = Math.round((then - Date.now()) / 1000); + if (secondsLeft < 0) { + clearInterval(countdown); + return; + } + displayTimeLeft(secondsLeft); + }, 1000); +} +function displayTimeLeft(seconds) { + var minutes = Math.floor(seconds / 60); + var remainderSeconds = seconds % 60; + var display = minutes + ":" + (remainderSeconds < 10 ? '0' : '') + remainderSeconds; + document.title = display; + timerDisplay.textContent = display; +} +function displayEndTime(timestamp) { + var end = new Date(timestamp); + var hour = end.getHours(); + var adjustedHour = hour > 12 ? hour - 12 : hour; + var minutes = end.getMinutes(); + endTime.textContent = "Be back at " + adjustedHour + ":" + (minutes < 10 ? '0' : '') + minutes; +} +function startTimer() { + var seconds = Number(this.dataset.time); + timer(seconds); +} +buttons.forEach(function (button) { return button.addEventListener('click', startTimer); }); +document.customForm.addEventListener('submit', function (e) { + e.preventDefault(); + var mins = this.minutes.value; + timer(mins * 60); + this.reset(); +}); From 375e320e53f71be2b71b144f07fcccec878fa4a3 Mon Sep 17 00:00:00 2001 From: William Wager Date: Thu, 5 Mar 2020 18:14:34 -0500 Subject: [PATCH 34/34] Final project 30 complete --- 30 - Whack A Mole/index-START.html | 12 +++--- 30 - Whack A Mole/typescripts.js | 44 +++++++++++++++++++++ 30 - Whack A Mole/typescripts.ts | 62 ++++++++++++++++++++++++++++-- 3 files changed, 107 insertions(+), 11 deletions(-) create mode 100644 30 - Whack A Mole/typescripts.js diff --git a/30 - Whack A Mole/index-START.html b/30 - Whack A Mole/index-START.html index 2014ff458c..e5c2859912 100644 --- a/30 - Whack A Mole/index-START.html +++ b/30 - Whack A Mole/index-START.html @@ -1,11 +1,13 @@ + Whack A Mole! +

      Whack-a-mole! 0

      @@ -32,11 +34,7 @@

      Whack-a-mole! 0

      - + - + + \ No newline at end of file diff --git a/30 - Whack A Mole/typescripts.js b/30 - Whack A Mole/typescripts.js new file mode 100644 index 0000000000..e04f25215d --- /dev/null +++ b/30 - Whack A Mole/typescripts.js @@ -0,0 +1,44 @@ +var holes = document.querySelectorAll('.hole'); +var scoreBoard = document.querySelector('.score'); +var moles = document.querySelectorAll('.mole'); +var lastHole; +var timeUp = false; +var score = 0; +function randomTime(min, max) { + return Math.round(Math.random() * (max - min) + min); +} +function randomHole(holes) { + var idx = Math.floor(Math.random() * holes.length); + var hole = holes[idx]; + if (hole === lastHole) { + console.log('SAME HOLE NOT ALLOWED!'); + return randomHole(holes); + } + lastHole = hole; + return hole; +} +function peep() { + var time = randomTime(200, 1000); + var hole = randomHole(holes); + hole.classList.add('up'); + setTimeout(function () { + hole.classList.remove('up'); + if (!timeUp) + peep(); + }, time); +} +function startGame() { + scoreBoard.textContent = '0'; + timeUp = false; + score = 0; + peep(); + setTimeout(function () { return timeUp = true; }, 10000); +} +function bonk(e) { + if (!e.isTrusted) + return; + score++; + this.classList.remove('up'); + scoreBoard.textContent = String(score); +} +moles.forEach(function (mole) { return mole.addEventListener('click', bonk); }); diff --git a/30 - Whack A Mole/typescripts.ts b/30 - Whack A Mole/typescripts.ts index 2621ff1235..6229fab1d6 100644 --- a/30 - Whack A Mole/typescripts.ts +++ b/30 - Whack A Mole/typescripts.ts @@ -1,10 +1,64 @@ /** * JavaScript30 by Wes Bos, https://javascript30.com/ * TypeScript implementation by Will Wager - * Project: - * Concepts: - * Key takeaways: - * Sidenotes: + * Project: Whack A Mole + * Concepts: Getting random values; Recursive setTimeout; Game Development + * Key takeaways: Random from max and min pattern; Recursive call on repeat random hole pattern; + * Looping with setTimeout; Stopping one setTimeout loop with another setTimeout; + * Preventing automated clicks; + * Sidenotes: Since hole opbjects are passed around pretty often, it may be useful to create a + * separate Hole subtype of HTMLDivElement. + * Additional improvements: Stylize start button; save high score list to local storage (or on a server!); + * Difficulty settings; Set game length; Progressively get faster moles as time left gets lower. * Compilation command: * tsc --removeComments --strictNullChecks --noImplicitAny --target es5 typescripts.ts */ + +const holes = document.querySelectorAll('.hole')! as NodeListOf; +const scoreBoard = document.querySelector('.score')! as HTMLSpanElement; +const moles = document.querySelectorAll('.mole')! as NodeListOf; +let lastHole: HTMLDivElement; +let timeUp = false; +let score = 0; + +function randomTime(min: number, max: number) { + return Math.round(Math.random() * (max - min) + min); +} + +function randomHole(holes: NodeListOf): HTMLDivElement { + const idx = Math.floor(Math.random() * holes.length); + const hole = holes[idx]; + if (hole === lastHole) { + console.log('SAME HOLE NOT ALLOWED!'); + return randomHole(holes); + } + lastHole = hole; + return hole; +} + +function peep() { + const time = randomTime(200, 1000); + const hole = randomHole(holes); + hole.classList.add('up'); + setTimeout(() => { + hole.classList.remove('up'); + if (!timeUp) peep(); + }, time); +} + +function startGame() { + scoreBoard.textContent = '0'; + timeUp = false; + score = 0; + peep(); + setTimeout(() => timeUp = true, 10000); +} + +function bonk(e: MouseEvent) { + if (!e.isTrusted) return; // Take that cheater. + score++; + this.classList.remove('up'); + scoreBoard.textContent = String(score); +} + +moles.forEach(mole => mole.addEventListener('click', bonk));