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/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(); 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..1c89266ae8 --- /dev/null +++ b/03 - CSS Variables/typescripts.ts @@ -0,0 +1,18 @@ +/** + * 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() { + 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)); 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); 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)); 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..d4e6b1f3ab --- /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, but --target es5 does not cause errors... + * 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/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 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 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); 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 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 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(''); 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 + - + - + + \ 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}`); 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); +} + 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 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.") +); 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)); 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)); 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 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 new file mode 100644 index 0000000000..bbc341fca3 --- /dev/null +++ b/25 - Event Capture, Propagation, Bubbling and Once/typescripts.ts @@ -0,0 +1,29 @@ +/** + * JavaScript30 by Wes Bos, https://javascript30.com/ + * TypeScript implementation by Will Wager + * 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, +}); 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 new file mode 100644 index 0000000000..dee3601837 --- /dev/null +++ b/26 - Stripe Follow Along Nav/typescripts.ts @@ -0,0 +1,49 @@ +/** + * JavaScript30 by Wes Bos, https://javascript30.com/ + * TypeScript implementation by Will Wager + * 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)); 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 new file mode 100644 index 0000000000..5bed7f8980 --- /dev/null +++ b/27 - Click and Drag/typescripts.ts @@ -0,0 +1,37 @@ +/** + * JavaScript30 by Wes Bos, https://javascript30.com/ + * TypeScript implementation by Will Wager + * 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; +}); 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 new file mode 100644 index 0000000000..73c93d281d --- /dev/null +++ b/28 - Video Speed Controller/typescripts.ts @@ -0,0 +1,31 @@ +/** + * JavaScript30 by Wes Bos, https://javascript30.com/ + * TypeScript implementation by Will Wager + * 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); 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.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(); +}); diff --git a/29 - Countdown Timer/typescripts.ts b/29 - Countdown Timer/typescripts.ts new file mode 100644 index 0000000000..c4cbb57ba8 --- /dev/null +++ b/29 - Countdown Timer/typescripts.ts @@ -0,0 +1,67 @@ +/** + * JavaScript30 by Wes Bos, https://javascript30.com/ + * TypeScript implementation by Will Wager + * 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 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 new file mode 100644 index 0000000000..6229fab1d6 --- /dev/null +++ b/30 - Whack A Mole/typescripts.ts @@ -0,0 +1,64 @@ +/** + * JavaScript30 by Wes Bos, https://javascript30.com/ + * TypeScript implementation by Will Wager + * 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)); diff --git a/favicon.ico b/favicon.ico new file mode 100644 index 0000000000..ca475eca8d Binary files /dev/null and b/favicon.ico differ diff --git a/readme.md b/readme.md index bb861dd631..173b746170 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. + * 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` + +---- + 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/).