├── .DS_Store
├── .gitignore
├── Ch 01
├── quiz
│ ├── index.html
│ ├── main.js
│ └── styles.css
└── rainbow
│ ├── main.js
│ └── rainbow.html
├── Ch 02
└── quiz
│ ├── index.html
│ ├── main.js
│ └── styles.css
├── Ch 03
└── quiz
│ ├── index.html
│ ├── main.js
│ └── styles.css
├── Ch 04
└── quiz
│ ├── index.html
│ ├── main.js
│ └── styles.css
├── Ch 05
└── quiz
│ ├── index.html
│ ├── main.js
│ └── styles.css
├── Ch 06
├── heroes.html
└── quiz
│ ├── index.html
│ ├── main.js
│ └── styles.css
├── Ch 07
└── quiz
│ ├── index.html
│ ├── main.js
│ └── styles.css
├── Ch 10
├── numberCruncher
│ └── numberCruncher.test.js
├── quiz
│ ├── index.html
│ ├── main.js
│ └── styles.css
└── squareRoot.test.js
├── Ch 11
└── quiz
│ ├── index.html
│ ├── main.js
│ └── styles.css
├── Ch 12
└── quiz
│ ├── index.html
│ ├── main.js
│ └── styles.css
├── Ch 13
├── .DS_Store
├── ajax
│ ├── ajax.html
│ └── main.js
├── quiz
│ ├── .DS_Store
│ ├── index.html
│ ├── main.js
│ ├── questions.json
│ └── styles.css
└── todo
│ ├── main.js
│ └── todo.html
├── Ch 14
├── .DS_Store
├── canvas
│ ├── canvas.html
│ └── main.js
├── quiz
│ ├── index.html
│ ├── main.js
│ └── styles.css
├── websocket
│ ├── main.js
│ └── websocket.html
└── worker
│ ├── factors.html
│ ├── factors.js
│ └── main.js
├── Ch 15
├── .DS_Store
├── MVC
│ ├── list.html
│ └── main.js
├── quiz
│ ├── .DS_Store
│ ├── dist
│ │ ├── bundle.min.js
│ │ ├── index.html
│ │ └── styles.css
│ ├── package-lock.json
│ ├── package.json
│ ├── src
│ │ ├── .DS_Store
│ │ ├── game.js
│ │ ├── main.js
│ │ ├── quiz.js
│ │ ├── utilities.js
│ │ └── view.js
│ └── webpack.config.js
└── webpack-example
│ ├── .DS_Store
│ ├── bundle.js
│ ├── main.js
│ ├── package-lock.json
│ ├── package.json
│ ├── webpack.config.js
│ └── webpack.html
├── Ch 8
├── .DS_Store
├── hero
│ ├── hero.html
│ └── main.js
├── quiz
│ ├── index.html
│ ├── main.js
│ └── styles.css
└── search
│ ├── main.js
│ └── search.html
├── Ch 9
├── animation
│ ├── animation.html
│ ├── main.js
│ └── styles.css
└── quiz
│ ├── index.html
│ ├── main.js
│ └── styles.css
├── dojo.svg
└── questions.json
/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/spbooks/jsninja2/99190428cc21281912042f69ae2306c958bdc268/.DS_Store
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.swp
2 | *.xml~
3 | *.rb~
4 | *.css~
5 | *.js~
6 | tmp/
7 | log/
8 | .DS_Store
9 |
10 |
--------------------------------------------------------------------------------
/Ch 01/quiz/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Quiz Ninja
7 |
8 |
9 |
10 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/Ch 01/quiz/main.js:
--------------------------------------------------------------------------------
1 | alert('Welcome to Quiz Ninja!');
2 |
--------------------------------------------------------------------------------
/Ch 01/quiz/styles.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css?family=Baloo+Da|Roboto');
2 |
3 | body{
4 | background: #5F1C1C;
5 | font-family: 'Roboto', sans-serif;
6 | }
7 | .dojo{
8 | background: url(https://gistcdn.githack.com/alexmwalker/6acbe9040d9fe6e5e9fd758a25e1b2a5/raw/635810bd1a925c06b5c0bc0c861d62fe53597078/dojo.svg) no-repeat;
9 | width: 100%;
10 | height: 800px;
11 | background-size: 100% auto;
12 | padding-top: 10px;
13 | }
14 | .quiz-body{
15 | background: rgba(255,255,255,1);
16 | margin: 150px 33%;
17 | padding: 10px 20px 50px 20px;
18 | -webkit-box-shadow: 4px 4px 11px 3px rgba(0,0,0,0.3);
19 | -moz-box-shadow: 4px 4px 11px 3px rgba(0,0,0,0.3);
20 | box-shadow: 4px 4px 11px 3px rgba(0,0,0,0.3);
21 | }
22 | h1{
23 | color: #611BBD;
24 | font-family: 'Baloo Da', cursive;
25 | font-weight: 900;
26 | text-align: center;
27 | font-size: 48px;
28 | margin: 0;
29 | }
30 | button {
31 | color: #ffffff;
32 | background-color: #611BBD;
33 | border-color: #130269;
34 | border-radius: 4px;
35 | margin: 0.2em 0;
36 | display: block;
37 | width: 100%;
38 | font-size: 24px;
39 | }
40 | #question {
41 | font-size: 24px;
42 | }
43 |
44 | #result{
45 | color: #fff;
46 | margin: 0.2em 0;
47 | width: 100%;
48 | text-align: center;
49 | }
50 | .correct {
51 | background-color: #0c0;
52 | }
53 | .wrong {
54 | color: #fff;
55 | background-color: #c00;
56 | }
57 |
--------------------------------------------------------------------------------
/Ch 01/rainbow/main.js:
--------------------------------------------------------------------------------
1 | const btn = document.getElementById('button');
2 |
3 | const rainbow = ['red','orange','yellow','green','blue','rebeccapurple','violet'];
4 |
5 | function change() {
6 | document.body.style.background = rainbow[Math.floor(7*Math.random())];
7 | }
8 | btn.addEventListener('click', change);
9 |
--------------------------------------------------------------------------------
/Ch 01/rainbow/rainbow.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | I Can Click A Rainbow
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/Ch 02/quiz/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Quiz Ninja
7 |
8 |
9 |
10 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/Ch 02/quiz/main.js:
--------------------------------------------------------------------------------
1 | const question = "What is Superman's real name?"
2 | const answer = prompt(question);
3 | alert(`You answered ${answer}`);
4 |
--------------------------------------------------------------------------------
/Ch 02/quiz/styles.css:
--------------------------------------------------------------------------------
1 | body{
2 | background: #5F1C1C;
3 | font-family: 'Spectral', serif;
4 | }
5 | .dojo{
6 | background: url(https://gistcdn.githack.com/alexmwalker/6acbe9040d9fe6e5e9fd758a25e1b2a5/raw/635810bd1a925c06b5c0bc0c861d62fe53597078/dojo.svg) no-repeat;
7 | width: 100%;
8 | height: 800px;
9 | background-size: 100% auto;
10 | padding-top: 10px;
11 | }
12 | .quiz-body{
13 | background: rgba(255,255,255,1);
14 | margin: 150px 33%;
15 | padding: 10px 20px 50px 20px;
16 | -webkit-box-shadow: 4px 4px 11px 3px rgba(0,0,0,0.3);
17 | -moz-box-shadow: 4px 4px 11px 3px rgba(0,0,0,0.3);
18 | box-shadow: 4px 4px 11px 3px rgba(0,0,0,0.3);
19 | }
20 | h1{
21 | font-weight: 900;
22 | text-align: center;
23 | font-size: 36px
24 | }
25 | button {
26 | color: #ffffff;
27 | background-color: #611BBD;
28 | border-color: #130269;
29 | border-radius: 4px;
30 | margin: 1em
31 | }
32 |
33 | #response button {
34 | display: block;
35 | width: 100%;
36 | margin: 6px 0;
37 | }
38 |
--------------------------------------------------------------------------------
/Ch 03/quiz/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Quiz Ninja
7 |
8 |
9 |
10 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/Ch 03/quiz/main.js:
--------------------------------------------------------------------------------
1 | const quiz = [
2 | ["What is Superman's real name?","Clark Kent"],
3 | ["What is Wonderwoman's real name?","Dianna Prince"],
4 | ["What is Batman's real name?","Bruce Wayne"]
5 | ];
6 |
7 | let score = 0;
8 |
9 | for(const [question,answer] of quiz){
10 | const response = prompt(question);
11 | if(response === answer){
12 | alert('Correct!');
13 | score++;
14 | } else {
15 | alert(`Wrong! The correct answer was ${answer}`);
16 | }
17 | }
18 |
19 | alert(`Game Over, you scored ${score} point${score !== 1 ? 's' : ''}`);
20 |
--------------------------------------------------------------------------------
/Ch 03/quiz/styles.css:
--------------------------------------------------------------------------------
1 | body{
2 | background: #5F1C1C;
3 | font-family: 'Spectral', serif;
4 | }
5 | .dojo{
6 | background: url(https://gistcdn.githack.com/alexmwalker/6acbe9040d9fe6e5e9fd758a25e1b2a5/raw/635810bd1a925c06b5c0bc0c861d62fe53597078/dojo.svg) no-repeat;
7 | width: 100%;
8 | height: 800px;
9 | background-size: 100% auto;
10 | padding-top: 10px;
11 | }
12 | .quiz-body{
13 | background: rgba(255,255,255,1);
14 | margin: 150px 33%;
15 | padding: 10px 20px 50px 20px;
16 | -webkit-box-shadow: 4px 4px 11px 3px rgba(0,0,0,0.3);
17 | -moz-box-shadow: 4px 4px 11px 3px rgba(0,0,0,0.3);
18 | box-shadow: 4px 4px 11px 3px rgba(0,0,0,0.3);
19 | }
20 | h1{
21 | font-weight: 900;
22 | text-align: center;
23 | font-size: 36px
24 | }
25 | button {
26 | color: #ffffff;
27 | background-color: #611BBD;
28 | border-color: #130269;
29 | border-radius: 4px;
30 | margin: 1em
31 | }
32 |
33 | #response button {
34 | display: block;
35 | width: 100%;
36 | margin: 6px 0;
37 | }
38 |
--------------------------------------------------------------------------------
/Ch 04/quiz/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Quiz Ninja
7 |
8 |
9 |
10 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/Ch 04/quiz/main.js:
--------------------------------------------------------------------------------
1 | const quiz = [
2 | ["What is Superman's real name?","Clark Kent"],
3 | ["What is Wonderwoman's real name?","Dianna Prince"],
4 | ["What is Batman's real name?","Bruce Wayne"]
5 | ];
6 |
7 | function start(quiz){
8 | let score = 0;
9 |
10 | // main game loop
11 | for(const [question,answer] of quiz){
12 | const response = ask(question);
13 | check(response,answer);
14 | }
15 | // end of main game loop
16 |
17 | gameOver();
18 |
19 | // function declarations
20 | function ask(question){
21 | return prompt(question);
22 | }
23 |
24 | function check(response,answer){
25 | if(response === answer){
26 | alert('Correct!');
27 | score++;
28 | } else {
29 | alert(`Wrong! The correct answer was ${answer}`);
30 | }
31 | }
32 |
33 | function gameOver(){
34 | alert(`Game Over, you scored ${score} point${score !== 1 ? 's' : ''}`);
35 | }
36 | }
37 | start(quiz);
38 |
--------------------------------------------------------------------------------
/Ch 04/quiz/styles.css:
--------------------------------------------------------------------------------
1 | body{
2 | background: #5F1C1C;
3 | font-family: 'Spectral', serif;
4 | }
5 | .dojo{
6 | background: url(https://gistcdn.githack.com/alexmwalker/6acbe9040d9fe6e5e9fd758a25e1b2a5/raw/635810bd1a925c06b5c0bc0c861d62fe53597078/dojo.svg) no-repeat;
7 | width: 100%;
8 | height: 800px;
9 | background-size: 100% auto;
10 | padding-top: 10px;
11 | }
12 | .quiz-body{
13 | background: rgba(255,255,255,1);
14 | margin: 150px 33%;
15 | padding: 10px 20px 50px 20px;
16 | -webkit-box-shadow: 4px 4px 11px 3px rgba(0,0,0,0.3);
17 | -moz-box-shadow: 4px 4px 11px 3px rgba(0,0,0,0.3);
18 | box-shadow: 4px 4px 11px 3px rgba(0,0,0,0.3);
19 | }
20 | h1{
21 | font-weight: 900;
22 | text-align: center;
23 | font-size: 36px
24 | }
25 | button {
26 | color: #ffffff;
27 | background-color: #611BBD;
28 | border-color: #130269;
29 | border-radius: 4px;
30 | margin: 1em
31 | }
32 |
33 | #response button {
34 | display: block;
35 | width: 100%;
36 | margin: 6px 0;
37 | }
38 |
--------------------------------------------------------------------------------
/Ch 05/quiz/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Quiz Ninja
7 |
8 |
9 |
10 |
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/Ch 05/quiz/main.js:
--------------------------------------------------------------------------------
1 | const quiz = [
2 | { name: "Superman",realName: "Clark Kent" },
3 | { name: "Wonderwoman",realName: "Dianna Prince" },
4 | { name: "Batman",realName: "Bruce Wayne" },
5 | ];
6 |
7 | const game = {
8 | start(quiz){
9 | this.questions = [...quiz];
10 | this.score = 0;
11 | // main game loop
12 | for(const question of this.questions){
13 | this.question = question;
14 | this.ask();
15 | }
16 | // end of main game loop
17 | this.gameOver();
18 | },
19 | ask(){
20 | const question = `What is ${this.question.name}'s real name?`;
21 | const response = prompt(question);
22 | this.check(response);
23 | },
24 | check(response){
25 | const answer = this.question.realName;
26 | if(response === answer){
27 | alert('Correct!');
28 | this.score++;
29 | } else {
30 | alert(`Wrong! The correct answer was ${answer}`);
31 | }
32 | },
33 | gameOver(){
34 | alert(`Game Over, you scored ${this.score} point${this.score !== 1 ? 's' : ''}`);
35 | }
36 | }
37 |
38 | game.start(quiz);
39 |
--------------------------------------------------------------------------------
/Ch 05/quiz/styles.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css?family=Baloo+Da|Roboto');
2 |
3 | body{
4 | background: #5F1C1C;
5 | font-family: 'Roboto', sans-serif;
6 | }
7 | .dojo{
8 | background: url(https://gistcdn.githack.com/alexmwalker/6acbe9040d9fe6e5e9fd758a25e1b2a5/raw/635810bd1a925c06b5c0bc0c861d62fe53597078/dojo.svg) no-repeat;
9 | width: 100%;
10 | height: 800px;
11 | background-size: 100% auto;
12 | padding-top: 10px;
13 | }
14 | .quiz-body{
15 | background: rgba(255,255,255,1);
16 | margin: 150px 33%;
17 | padding: 10px 20px 50px 20px;
18 | -webkit-box-shadow: 4px 4px 11px 3px rgba(0,0,0,0.3);
19 | -moz-box-shadow: 4px 4px 11px 3px rgba(0,0,0,0.3);
20 | box-shadow: 4px 4px 11px 3px rgba(0,0,0,0.3);
21 | }
22 | h1{
23 | color: #611BBD;
24 | font-family: 'Baloo Da', cursive;
25 | font-weight: 900;
26 | text-align: center;
27 | font-size: 48px;
28 | margin: 0;
29 | }
30 | button {
31 | color: #ffffff;
32 | background-color: #611BBD;
33 | border-color: #130269;
34 | border-radius: 4px;
35 | margin: 0.2em 0;
36 | display: block;
37 | width: 100%;
38 | font-size: 24px;
39 | }
40 | #question {
41 | font-size: 24px;
42 | }
43 |
44 | #result{
45 | color: #fff;
46 | margin: 0.2em 0;
47 | width: 100%;
48 | text-align: center;
49 | }
50 | .correct {
51 | background-color: #0c0;
52 | }
53 | .wrong {
54 | color: #fff;
55 | background-color: #c00;
56 | }
57 |
--------------------------------------------------------------------------------
/Ch 06/heroes.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Justice League
6 |
7 |
8 |
11 |
12 | - Superman
13 | - Batman
14 | - Wonder Woman
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/Ch 06/quiz/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Quiz Ninja
7 |
8 |
9 |
10 |
11 |
12 |
15 |
Score: 0
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/Ch 06/quiz/main.js:
--------------------------------------------------------------------------------
1 | const quiz = [
2 | { name: "Superman",realName: "Clark Kent" },
3 | { name: "Wonderwoman",realName: "Dianna Prince" },
4 | { name: "Batman",realName: "Bruce Wayne" },
5 | ];
6 |
7 | // View Object
8 | const view = {
9 | score: document.querySelector('#score strong'),
10 | question: document.getElementById('question'),
11 | result: document.getElementById('result'),
12 | info: document.getElementById('info'),
13 | render(target,content,attributes) {
14 | for(const key in attributes) {
15 | target.setAttribute(key, attributes[key]);
16 | }
17 | target.innerHTML = content;
18 | }
19 | };
20 |
21 | // Game Object
22 | const game = {
23 | start(quiz){
24 | this.score = 0;
25 | this.questions = [...quiz];
26 | // main game loop
27 | for(const question of this.questions){
28 | this.question = question;
29 | this.ask();
30 | }
31 | // end of main game loop
32 | this.gameOver();
33 | },
34 | ask(){
35 | const question = `What is ${this.question.name}'s real name?`;
36 | view.render(view.question,question);
37 | const response = prompt(question);
38 | this.check(response);
39 | },
40 | check(response){
41 | const answer = this.question.realName;
42 | if(response === answer){
43 | view.render(view.result,'Correct!',{'class':'correct'});
44 | alert('Correct!');
45 | this.score++;
46 | view.render(view.score,this.score);
47 | } else {
48 | view.render(view.result,`Wrong! The correct answer was ${answer}`,{'class':'wrong'});
49 | alert(`Wrong! The correct answer was ${answer}`);
50 | }
51 | },
52 | gameOver(){
53 | view.render(view.info,`Game Over, you scored ${this.score} point${this.score !== 1 ? 's' : ''}`);
54 | }
55 | }
56 |
57 | game.start(quiz);
58 |
--------------------------------------------------------------------------------
/Ch 06/quiz/styles.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css?family=Baloo+Da|Roboto');
2 |
3 | body{
4 | background: #5F1C1C;
5 | font-family: 'Roboto', sans-serif;
6 | }
7 | .dojo{
8 | background: url(https://gistcdn.githack.com/alexmwalker/6acbe9040d9fe6e5e9fd758a25e1b2a5/raw/635810bd1a925c06b5c0bc0c861d62fe53597078/dojo.svg) no-repeat;
9 | width: 100%;
10 | height: 800px;
11 | background-size: 100% auto;
12 | padding-top: 10px;
13 | }
14 | .quiz-body{
15 | background: rgba(255,255,255,1);
16 | margin: 150px 33%;
17 | padding: 10px 20px 50px 20px;
18 | -webkit-box-shadow: 4px 4px 11px 3px rgba(0,0,0,0.3);
19 | -moz-box-shadow: 4px 4px 11px 3px rgba(0,0,0,0.3);
20 | box-shadow: 4px 4px 11px 3px rgba(0,0,0,0.3);
21 | }
22 | h1{
23 | color: #611BBD;
24 | font-family: 'Baloo Da', cursive;
25 | font-weight: 900;
26 | text-align: center;
27 | font-size: 48px;
28 | margin: 0;
29 | }
30 | button {
31 | color: #ffffff;
32 | background-color: #611BBD;
33 | border-color: #130269;
34 | border-radius: 4px;
35 | margin: 0.2em 0;
36 | display: block;
37 | width: 100%;
38 | font-size: 24px;
39 | }
40 | #question {
41 | font-size: 24px;
42 | }
43 |
44 | #result{
45 | color: #fff;
46 | margin: 0.2em 0;
47 | width: 100%;
48 | text-align: center;
49 | }
50 | .correct {
51 | background-color: #0c0;
52 | }
53 | .wrong {
54 | color: #fff;
55 | background-color: #c00;
56 | }
57 |
--------------------------------------------------------------------------------
/Ch 07/quiz/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Quiz Ninja
7 |
8 |
9 |
11 |
12 |
13 | Score: 0
14 | Quiz Ninja!
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/Ch 07/quiz/main.js:
--------------------------------------------------------------------------------
1 | const quiz = [
2 | { name: "Superman",realName: "Clark Kent" },
3 | { name: "Wonderwoman",realName: "Dianna Prince" },
4 | { name: "Batman",realName: "Bruce Wayne" },
5 | ];
6 |
7 | // View Object
8 | const view = {
9 | score: document.querySelector('#score strong'),
10 | question: document.getElementById('question'),
11 | result: document.getElementById('result'),
12 | info: document.getElementById('info'),
13 | start: document.getElementById('start'),
14 | render(target,content,attributes) {
15 | for(const key in attributes) {
16 | target.setAttribute(key, attributes[key]);
17 | }
18 | target.innerHTML = content;
19 | },
20 | show(element){
21 | element.style.display = 'block';
22 | },
23 | hide(element){
24 | element.style.display = 'none';
25 | }
26 | };
27 |
28 | // Game Object
29 | const game = {
30 | start(quiz){
31 | this.score = 0;
32 | this.questions = [...quiz];
33 | view.hide(view.start);
34 | // main game loop
35 | for(const question of this.questions){
36 | this.question = question;
37 | this.ask();
38 | }
39 | // end of main game loop
40 | this.gameOver();
41 | },
42 | ask(){
43 | const question = `What is ${this.question.name}'s real name?`;
44 | view.render(view.question,question);
45 | const response = prompt(question);
46 | this.check(response);
47 | },
48 | check(response){
49 | const answer = this.question.realName;
50 | if(response === answer){
51 | view.render(view.result,'Correct!',{'class':'correct'});
52 | alert('Correct!');
53 | this.score++;
54 | view.render(view.score,this.score);
55 | } else {
56 | view.render(view.result,`Wrong! The correct answer was ${answer}`,{'class':'wrong'});
57 | alert(`Wrong! The correct answer was ${answer}`);
58 | }
59 | },
60 | gameOver(){
61 | view.render(view.info,`Game Over, you scored ${this.score} point${this.score !== 1 ? 's' : ''}`);
62 | view.show(view.start);
63 | }
64 | }
65 |
66 | view.start.addEventListener('click', () => game.start(quiz), false);
67 |
--------------------------------------------------------------------------------
/Ch 07/quiz/styles.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css?family=Baloo+Da|Roboto');
2 |
3 | body{
4 | background: #5F1C1C;
5 | font-family: 'Roboto', sans-serif;
6 | }
7 | .dojo{
8 | background: url(https://gistcdn.githack.com/alexmwalker/6acbe9040d9fe6e5e9fd758a25e1b2a5/raw/635810bd1a925c06b5c0bc0c861d62fe53597078/dojo.svg) no-repeat;
9 | width: 100%;
10 | height: 800px;
11 | background-size: 100% auto;
12 | padding-top: 10px;
13 | }
14 | .quiz-body{
15 | background: rgba(255,255,255,1);
16 | margin: 150px 33%;
17 | padding: 10px 20px 50px 20px;
18 | -webkit-box-shadow: 4px 4px 11px 3px rgba(0,0,0,0.3);
19 | -moz-box-shadow: 4px 4px 11px 3px rgba(0,0,0,0.3);
20 | box-shadow: 4px 4px 11px 3px rgba(0,0,0,0.3);
21 | }
22 | h1{
23 | color: #611BBD;
24 | font-family: 'Baloo Da', cursive;
25 | font-weight: 900;
26 | text-align: center;
27 | font-size: 48px;
28 | margin: 0;
29 | }
30 | button {
31 | color: #ffffff;
32 | background-color: #611BBD;
33 | border-color: #130269;
34 | border-radius: 4px;
35 | margin: 0.2em 0;
36 | display: block;
37 | width: 100%;
38 | font-size: 24px;
39 | }
40 | #question {
41 | font-size: 24px;
42 | }
43 |
44 | #result{
45 | color: #fff;
46 | margin: 0.2em 0;
47 | width: 100%;
48 | text-align: center;
49 | }
50 | .correct {
51 | background-color: #0c0;
52 | }
53 | .wrong {
54 | color: #fff;
55 | background-color: #c00;
56 | }
57 |
--------------------------------------------------------------------------------
/Ch 10/numberCruncher/numberCruncher.test.js:
--------------------------------------------------------------------------------
1 | 'use strict';
2 |
3 | function factorsOf(n) {
4 | if(Number.isNaN(Number(n))) {
5 | throw new RangeError('Argument Error: Value must be an integer');
6 | }
7 | if(n < 0) {
8 | throw new RangeError('Argument Error: Number must be positive');
9 | }
10 | if(!Number.isInteger(n)) {
11 | throw new RangeError('Argument Error: Number must be an integer');
12 | }
13 | const factors = [];
14 | for (let i=1 , max = Math.sqrt(n); i <= max ; i++) {
15 | if (n%i === 0){
16 | factors.push(i,n/i);
17 | }
18 | }
19 | return factors.sort(function(a,b){ return a > b; });
20 | }
21 |
22 | function isPrime(n) {
23 | try{
24 | return factorsOf(n).length === 2;
25 | } catch(error) {
26 | return false;
27 | }
28 | }
29 |
30 | test('returns factors of 12', () => {
31 | expect(factorsOf(12)).toEqual([1,2,3,4,6,12]);
32 | });
33 |
34 | test('2 is prime', () => {
35 | expect(isPrime(2)).toBe(true);
36 | });
37 |
38 | test('10 is not prime', () => {
39 | expect(isPrime(10)).not.toBe(true);
40 | });
41 |
42 | test('Exception for non-numerical data', () => {
43 | expect(() => {
44 | factorsOf('twelve');
45 | }).toThrow();
46 | });
47 |
48 | test('Exception for negative numbers', () => {
49 | expect(() => {
50 | factorsOf(-1);
51 | }).toThrow();
52 | });
53 |
54 | test('Exception for non-integer numbers', () => {
55 | expect(() => {
56 | factorsOf(3.14159);
57 | }).toThrow();
58 | });
59 |
60 | test('non-numerical data returns not prime', () => {
61 | expect(isPrime('two')).toBe(false);
62 | });
63 |
64 | test('non-integer numbers return not prime', () => {
65 | expect(isPrime(1.2)).toBe(false);
66 | });
67 |
68 | test('negative numbers return not prime', () => {
69 | expect(isPrime(-1)).toBe(false);
70 | });
71 |
--------------------------------------------------------------------------------
/Ch 10/quiz/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Quiz Ninja
7 |
8 |
9 |
10 |
11 |
12 |
13 | Score: 0
14 | Quiz Ninja!
15 |
16 |
17 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/Ch 10/quiz/main.js:
--------------------------------------------------------------------------------
1 | const quiz = [
2 | { name: "Superman",realName: "Clark Kent" },
3 | { name: "Wonderwoman",realName: "Dianna Prince" },
4 | { name: "Batman",realName: "Bruce Wayne" },
5 | ];
6 | // View Object
7 | const view = {
8 | score: document.querySelector('#score strong'),
9 | question: document.querySelector('#question'),
10 | result: document.querySelector('#result'),
11 | info: document.querySelector('#info'),
12 | start: document.querySelector('#start'),
13 | response: document.querySelector('#response'),
14 | timer: document.querySelector('#timer strong'),
15 | render(target,content,attributes) {
16 | for(const key in attributes) {
17 | target.setAttribute(key, attributes[key]);
18 | }
19 | target.innerHTML = content;
20 | },
21 | show(element){
22 | element.style.display = 'block';
23 | },
24 | hide(element){
25 | element.style.display = 'none';
26 | },
27 | resetForm(){
28 | this.response.answer.value = '';
29 | this.response.answer.focus();
30 | },
31 | setup(){
32 | this.show(this.question);
33 | this.show(this.response);
34 | this.show(this.result);
35 | this.hide(this.start);
36 | this.render(this.score,game.score);
37 | this.render(this.result,'');
38 | this.render(this.info,'');
39 | this.resetForm();
40 | },
41 | teardown(){
42 | this.hide(this.question);
43 | this.hide(this.response);
44 | this.show(this.start);
45 | }
46 | };
47 |
48 | const game = {
49 | start(quiz){
50 | console.log('start() invoked');
51 | this.score = 0;
52 | this.questions = [...quiz];
53 | view.setup();
54 | this.secondsRemaining = 20;
55 | this.timer = setInterval( this.countdown , 1000 );
56 | this.ask();
57 | },
58 | countdown() {
59 | game.secondsRemaining--;
60 | view.render(view.timer,game.secondsRemaining);
61 | if(game.secondsRemaining <= 0) {
62 | game.gameOver();
63 | }
64 | },
65 | ask(name){
66 | console.log('ask() invoked');
67 | if(this.questions.length > 0) {
68 | this.question = this.questions.pop();
69 | const question = `What is ${this.question.name}'s real name?`;
70 | view.render(view.question,question);
71 | }
72 | else {
73 | this.gameOver();
74 | }
75 | },
76 | check(event){
77 | console.log('check(event) invoked');
78 | event.preventDefault();
79 | const response = view.response[0].value;
80 | const answer = this.question.realName;
81 | if(response === answer){
82 | view.render(view.result,'Correct!',{'class':'correct'});
83 | this.score++;
84 | view.render(view.score,this.score);
85 | } else {
86 | view.render(view.result,`Wrong! The correct answer was ${answer}`,{'class':'wrong'});
87 | }
88 | view.resetForm();
89 | this.ask();
90 | },
91 | gameOver(){
92 | console.log('gameOver() invoked');
93 | view.render(view.info,`Game Over, you scored ${this.score} point${this.score !== 1 ? 's' : ''}`);
94 | view.teardown();
95 | clearInterval(this.timer);
96 | }
97 | }
98 |
99 | view.start.addEventListener('click', () => game.start(quiz), false);
100 | view.response.addEventListener('submit', (event) => game.check(event), false);
101 | view.hide(view.response);
102 |
--------------------------------------------------------------------------------
/Ch 10/quiz/styles.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css?family=Baloo+Da|Roboto');
2 |
3 | body{
4 | background: #5F1C1C;
5 | font-family: 'Roboto', sans-serif;
6 | }
7 | .dojo{
8 | background: url(https://gistcdn.githack.com/alexmwalker/6acbe9040d9fe6e5e9fd758a25e1b2a5/raw/635810bd1a925c06b5c0bc0c861d62fe53597078/dojo.svg) no-repeat;
9 | width: 100%;
10 | height: 800px;
11 | background-size: 100% auto;
12 | padding-top: 10px;
13 | }
14 | .quiz-body{
15 | background: rgba(255,255,255,1);
16 | margin: 150px 33%;
17 | padding: 10px 20px 50px 20px;
18 | -webkit-box-shadow: 4px 4px 11px 3px rgba(0,0,0,0.3);
19 | -moz-box-shadow: 4px 4px 11px 3px rgba(0,0,0,0.3);
20 | box-shadow: 4px 4px 11px 3px rgba(0,0,0,0.3);
21 | }
22 | h1{
23 | color: #611BBD;
24 | font-family: 'Baloo Da', cursive;
25 | font-weight: 900;
26 | text-align: center;
27 | font-size: 48px;
28 | margin: 0;
29 | }
30 | button {
31 | color: #ffffff;
32 | background-color: #611BBD;
33 | border-color: #130269;
34 | border-radius: 4px;
35 | margin: 0.2em 0;
36 | display: block;
37 | width: 100%;
38 | font-size: 24px;
39 | }
40 | #question {
41 | font-size: 24px;
42 | }
43 |
44 | #result{
45 | color: #fff;
46 | margin: 0.2em 0;
47 | width: 100%;
48 | text-align: center;
49 | }
50 | .correct {
51 | background-color: #0c0;
52 | }
53 | .wrong {
54 | color: #fff;
55 | background-color: #c00;
56 | }
57 |
--------------------------------------------------------------------------------
/Ch 10/squareRoot.test.js:
--------------------------------------------------------------------------------
1 | function squareRoot(number) {
2 | 'use strict';
3 | if (number < 0) {
4 | throw new RangeError('You can't find the square root negative numbers')
5 | }
6 | return Math.sqrt(number);
7 | };
8 |
9 | test('square root of 4 is 2', () => {
10 | expect(squareRoot(4)).toBe(2);
11 | });
12 |
--------------------------------------------------------------------------------
/Ch 11/quiz/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Quiz Ninja
7 |
8 |
9 |
10 |
11 |
12 |
13 | Score: 0
14 | Quiz Ninja!
15 |
16 |
17 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/Ch 11/quiz/main.js:
--------------------------------------------------------------------------------
1 | const quiz = [
2 | { name: "Superman",realName: "Clark Kent" },
3 | { name: "Wonderwoman",realName: "Dianna Prince" },
4 | { name: "Batman",realName: "Bruce Wayne" },
5 | ];
6 |
7 | // Utility functions
8 | function random(a,b=1) {
9 | // if only 1 argument is provided, we need to swap the values of a and b
10 | if (b === 1) {
11 | [a,b] = [b,a];
12 | }
13 | return Math.floor((b-a+1) * Math.random()) + a;
14 | }
15 |
16 | function shuffle(array) {
17 | for (let i = array.length; i; i--) {
18 | let j = random(i)-1;
19 | [array[i - 1], array[j]] = [array[j], array[i - 1]];
20 | }
21 | }
22 |
23 | // View Object
24 | const view = {
25 | score: document.querySelector('#score strong'),
26 | question: document.querySelector('#question'),
27 | result: document.querySelector('#result'),
28 | info: document.querySelector('#info'),
29 | start: document.querySelector('#start'),
30 | response: document.querySelector('#response'),
31 | timer: document.querySelector('#timer strong'),
32 | render(target,content,attributes) {
33 | for(const key in attributes) {
34 | target.setAttribute(key, attributes[key]);
35 | }
36 | target.innerHTML = content;
37 | },
38 | show(element){
39 | element.style.display = 'block';
40 | },
41 | hide(element){
42 | element.style.display = 'none';
43 | },
44 | resetForm(){
45 | this.response.answer.value = '';
46 | this.response.answer.focus();
47 | },
48 | setup(){
49 | this.show(this.question);
50 | this.show(this.response);
51 | this.show(this.result);
52 | this.hide(this.start);
53 | this.render(this.score,game.score);
54 | this.render(this.result,'');
55 | this.render(this.info,'');
56 | this.resetForm();
57 | },
58 | teardown(){
59 | this.hide(this.question);
60 | this.hide(this.response);
61 | this.show(this.start);
62 | }
63 | };
64 |
65 | const game = {
66 | start(quiz){
67 | console.log('start() invoked');
68 | this.score = 0;
69 | this.questions = [...quiz];
70 | view.setup();
71 | this.secondsRemaining = 20;
72 | this.timer = setInterval( this.countdown , 1000 );
73 | this.ask();
74 | },
75 | countdown() {
76 | game.secondsRemaining--;
77 | view.render(view.timer,game.secondsRemaining);
78 | if(game.secondsRemaining <= 0) {
79 | game.gameOver();
80 | }
81 | },
82 | ask(name){
83 | console.log('ask() invoked');
84 | if(this.questions.length > 0) {
85 | shuffle(this.questions);
86 | this.question = this.questions.pop();
87 | const question = `What is ${this.question.name}'s real name?`;
88 | view.render(view.question,question);
89 | }
90 | else {
91 | this.gameOver();
92 | }
93 | },
94 | check(event){
95 | console.log('check(event) invoked');
96 | event.preventDefault();
97 | const response = view.response[0].value;
98 | const answer = this.question.realName;
99 | if(response === answer){
100 | view.render(view.result,'Correct!',{'class':'correct'});
101 | this.score++;
102 | view.render(view.score,this.score);
103 | } else {
104 | view.render(view.result,`Wrong! The correct answer was ${answer}`,{'class':'wrong'});
105 | }
106 | view.resetForm();
107 | this.ask();
108 | },
109 | gameOver(){
110 | console.log('gameOver() invoked');
111 | view.render(view.info,`Game Over, you scored ${this.score} point${this.score !== 1 ? 's' : ''}`);
112 | view.teardown();
113 | clearInterval(this.timer);
114 | }
115 | }
116 |
117 | view.start.addEventListener('click', () => game.start(quiz), false);
118 | view.response.addEventListener('submit', (event) => game.check(event), false);
119 | view.hide(view.response);
120 |
--------------------------------------------------------------------------------
/Ch 11/quiz/styles.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css?family=Baloo+Da|Roboto');
2 |
3 | body{
4 | background: #5F1C1C;
5 | font-family: 'Roboto', sans-serif;
6 | }
7 | .dojo{
8 | background: url(https://gistcdn.githack.com/alexmwalker/6acbe9040d9fe6e5e9fd758a25e1b2a5/raw/635810bd1a925c06b5c0bc0c861d62fe53597078/dojo.svg) no-repeat;
9 | width: 100%;
10 | height: 800px;
11 | background-size: 100% auto;
12 | padding-top: 10px;
13 | }
14 | .quiz-body{
15 | background: rgba(255,255,255,1);
16 | margin: 150px 33%;
17 | padding: 10px 20px 50px 20px;
18 | -webkit-box-shadow: 4px 4px 11px 3px rgba(0,0,0,0.3);
19 | -moz-box-shadow: 4px 4px 11px 3px rgba(0,0,0,0.3);
20 | box-shadow: 4px 4px 11px 3px rgba(0,0,0,0.3);
21 | }
22 | h1{
23 | color: #611BBD;
24 | font-family: 'Baloo Da', cursive;
25 | font-weight: 900;
26 | text-align: center;
27 | font-size: 48px;
28 | margin: 0;
29 | }
30 | button {
31 | color: #ffffff;
32 | background-color: #611BBD;
33 | border-color: #130269;
34 | border-radius: 4px;
35 | margin: 0.2em 0;
36 | display: block;
37 | width: 100%;
38 | font-size: 24px;
39 | }
40 | #question {
41 | font-size: 24px;
42 | }
43 |
44 | #result{
45 | color: #fff;
46 | margin: 0.2em 0;
47 | width: 100%;
48 | text-align: center;
49 | }
50 | .correct {
51 | background-color: #0c0;
52 | }
53 | .wrong {
54 | color: #fff;
55 | background-color: #c00;
56 | }
57 |
--------------------------------------------------------------------------------
/Ch 12/quiz/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Quiz Ninja
7 |
8 |
9 |
10 |
11 |
12 |
13 | Quiz Ninja!
14 | Time: 20
15 | Score: 0
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Ch 12/quiz/main.js:
--------------------------------------------------------------------------------
1 | const quiz = [
2 | { name: "Superman",realName: "Clark Kent" },
3 | { name: "Wonderwoman",realName: "Dianna Prince" },
4 | { name: "Batman",realName: "Bruce Wayne" },
5 | { name: "The Hulk",realName: "Bruce Banner" },
6 | { name: "Spider-man",realName: "Peter Parker" },
7 | { name: "Cyclops",realName: "Scott Summers" }
8 | ];
9 |
10 | // Utility functions
11 | function random(a,b=1) {
12 | // if only 1 argument is provided, we need to swap the values of a and b
13 | if (b === 1) {
14 | [a,b] = [b,a];
15 | }
16 | return Math.floor((b-a+1) * Math.random()) + a;
17 | }
18 |
19 | function shuffle(array) {
20 | for (let i = array.length; i; i--) {
21 | let j = random(i)-1;
22 | [array[i - 1], array[j]] = [array[j], array[i - 1]];
23 | }
24 | }
25 |
26 | // View Object
27 | const view = {
28 | score: document.querySelector('#score strong'),
29 | question: document.querySelector('#question'),
30 | result: document.querySelector('#result'),
31 | info: document.querySelector('#info'),
32 | start: document.querySelector('#start'),
33 | response: document.querySelector('#response'),
34 | timer: document.querySelector('#timer strong'),
35 | render(target,content,attributes) {
36 | for(const key in attributes) {
37 | target.setAttribute(key, attributes[key]);
38 | }
39 | target.innerHTML = content;
40 | },
41 | show(element){
42 | element.style.display = 'block';
43 | },
44 | hide(element){
45 | element.style.display = 'none';
46 | },
47 | setup(){
48 | this.show(this.question);
49 | this.show(this.response);
50 | this.show(this.result);
51 | this.hide(this.start);
52 | this.render(this.score,game.score);
53 | this.render(this.result,'');
54 | this.render(this.info,'');
55 | },
56 | teardown(){
57 | this.hide(this.question);
58 | this.hide(this.response);
59 | this.show(this.start);
60 | },
61 | buttons(array){
62 | return array.map(value => ``).join('');
63 | }
64 | };
65 |
66 | const game = {
67 | start(quiz){
68 | console.log('start() invoked');
69 | this.score = 0;
70 | this.questions = [...quiz];
71 | view.setup();
72 | this.secondsRemaining = 20;
73 | this.timer = setInterval( this.countdown , 1000 );
74 | this.ask();
75 | },
76 | countdown() {
77 | game.secondsRemaining--;
78 | view.render(view.timer,game.secondsRemaining);
79 | if(game.secondsRemaining <= 0) {
80 | game.gameOver();
81 | }
82 | },
83 | ask(name){
84 | console.log('ask() invoked');
85 | if(this.questions.length > 2) {
86 | shuffle(this.questions);
87 | this.question = this.questions.pop();
88 | const options = [this.questions[0].realName, this.questions[1].realName, this.question.realName];
89 | shuffle(options);
90 | const question = `What is ${this.question.name}'s real name?`;
91 | view.render(view.question,question);
92 | view.render(view.response,view.buttons(options));
93 | }
94 | else {
95 | this.gameOver();
96 | }
97 | },
98 | check(event){
99 | console.log('check(event) invoked');
100 | const response = event.target.textContent;
101 | const answer = this.question.realName;
102 | if(response === answer){
103 | view.render(view.result,'Correct!',{'class':'correct'});
104 | this.score++;
105 | view.render(view.score,this.score);
106 | } else {
107 | view.render(view.result,`Wrong! The correct answer was ${answer}`,{'class':'wrong'});
108 | }
109 | this.ask();
110 | },
111 | gameOver(){
112 | console.log('gameOver() invoked');
113 | view.render(view.info,`Game Over, you scored ${this.score} point${this.score !== 1 ? 's' : ''}`);
114 | view.teardown();
115 | clearInterval(this.timer);
116 | }
117 | }
118 |
119 | view.start.addEventListener('click', () => game.start(quiz), false);
120 | view.response.addEventListener('click', (event) => game.check(event), false);
121 |
--------------------------------------------------------------------------------
/Ch 12/quiz/styles.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css?family=Baloo+Da|Roboto');
2 |
3 | body{
4 | background: #5F1C1C;
5 | font-family: 'Roboto', sans-serif;
6 | }
7 | .dojo{
8 | background: url(https://gistcdn.githack.com/alexmwalker/6acbe9040d9fe6e5e9fd758a25e1b2a5/raw/635810bd1a925c06b5c0bc0c861d62fe53597078/dojo.svg) no-repeat;
9 | width: 100%;
10 | height: 800px;
11 | background-size: 100% auto;
12 | padding-top: 10px;
13 | }
14 | .quiz-body{
15 | background: rgba(255,255,255,1);
16 | margin: 150px 33%;
17 | padding: 10px 20px 50px 20px;
18 | -webkit-box-shadow: 4px 4px 11px 3px rgba(0,0,0,0.3);
19 | -moz-box-shadow: 4px 4px 11px 3px rgba(0,0,0,0.3);
20 | box-shadow: 4px 4px 11px 3px rgba(0,0,0,0.3);
21 | }
22 | h1{
23 | color: #611BBD;
24 | font-family: 'Baloo Da', cursive;
25 | font-weight: 900;
26 | text-align: center;
27 | font-size: 48px;
28 | margin: 0;
29 | }
30 | button {
31 | color: #ffffff;
32 | background-color: #611BBD;
33 | border-color: #130269;
34 | border-radius: 4px;
35 | margin: 0.2em 0;
36 | display: block;
37 | width: 100%;
38 | font-size: 24px;
39 | }
40 | #question {
41 | font-size: 24px;
42 | }
43 |
44 | #result{
45 | color: #fff;
46 | margin: 0.2em 0;
47 | width: 100%;
48 | text-align: center;
49 | }
50 | .correct {
51 | background-color: #0c0;
52 | }
53 | .wrong {
54 | color: #fff;
55 | background-color: #c00;
56 | }
57 |
--------------------------------------------------------------------------------
/Ch 13/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/spbooks/jsninja2/99190428cc21281912042f69ae2306c958bdc268/Ch 13/.DS_Store
--------------------------------------------------------------------------------
/Ch 13/ajax/ajax.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Ajax Example
6 |
7 |
8 |
9 |
10 |
11 | Ajax response will appear here
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/Ch 13/ajax/main.js:
--------------------------------------------------------------------------------
1 | const textButton = document.getElementById('number');
2 | const apiButton = document.getElementById('chuck');
3 | const outputDiv = document.getElementById('output');
4 |
5 | const textURL = 'http://numbersapi.com/random';
6 | const apiURL = 'https://api.chucknorris.io/jokes/random';
7 |
8 | textButton.addEventListener('click', function() {
9 | fetch(textURL)
10 | .then( function(response) {
11 | outputDiv.innerHTML = 'Waiting for response...';
12 | if(response.ok) {
13 | return response;
14 | }
15 | throw Error(response.statusText);
16 | })
17 | .then( response => response.text() )
18 | .then( text => outputDiv.innerText = text )
19 | .catch( error => console.log('There was an error:', error))
20 | },false);
21 |
22 | apiButton.addEventListener('click', function() {
23 | fetch(apiURL)
24 | .then( function(response) {
25 | outputDiv.innerHTML = 'Waiting for response...';
26 | if(response.ok) {
27 | return response;
28 | }
29 | throw Error(response.statusText);
30 | })
31 | .then( response => { alert(response.headers.get('Content-Type')); return response.json();} )
32 | .then( data => outputDiv.innerText = data.value )
33 | .catch( error => console.log('There was an error:', error))
34 | },false);
35 |
36 | function makeRequest(url) {
37 | fetch(apiURL)
38 | .then( function(response) {
39 | outputDiv.innerHTML = 'Waiting for response...';
40 | if(response.ok) {
41 | return response;
42 | }
43 | throw Error(response.statusText);
44 | })
45 | }
46 |
--------------------------------------------------------------------------------
/Ch 13/quiz/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/spbooks/jsninja2/99190428cc21281912042f69ae2306c958bdc268/Ch 13/quiz/.DS_Store
--------------------------------------------------------------------------------
/Ch 13/quiz/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Quiz Ninja
7 |
8 |
9 |
10 |
11 |
12 |
13 | Quiz Ninja!
14 | Time: 20
15 | Score: 0
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/Ch 13/quiz/main.js:
--------------------------------------------------------------------------------
1 | const url = 'https://spbooks.github.io/jsninja2/questions.json';
2 |
3 | fetch(url)
4 | .then(res => res.json())
5 | .then(quiz => {
6 | view.start.addEventListener('click', () => game.start(quiz.questions), false);
7 | view.response.addEventListener('click', (event) => game.check(event), false);
8 | });
9 |
10 | // Utility functions
11 | function random(a,b=1) {
12 | // if only 1 argument is provided, we need to swap the values of a and b
13 | if (b === 1) {
14 | [a,b] = [b,a];
15 | }
16 | return Math.floor((b-a+1) * Math.random()) + a;
17 | }
18 |
19 | function shuffle(array) {
20 | for (let i = array.length; i; i--) {
21 | let j = random(i)-1;
22 | [array[i - 1], array[j]] = [array[j], array[i - 1]];
23 | }
24 | }
25 |
26 | // View Object
27 | const view = {
28 | score: document.querySelector('#score strong'),
29 | question: document.querySelector('#question'),
30 | result: document.querySelector('#result'),
31 | info: document.querySelector('#info'),
32 | start: document.querySelector('#start'),
33 | response: document.querySelector('#response'),
34 | timer: document.querySelector('#timer strong'),
35 | render(target,content,attributes) {
36 | for(const key in attributes) {
37 | target.setAttribute(key, attributes[key]);
38 | }
39 | target.innerHTML = content;
40 | },
41 | show(element){
42 | element.style.display = 'block';
43 | },
44 | hide(element){
45 | element.style.display = 'none';
46 | },
47 | setup(){
48 | this.show(this.question);
49 | this.show(this.response);
50 | this.show(this.result);
51 | this.hide(this.start);
52 | this.render(this.score,game.score);
53 | this.render(this.result,'');
54 | this.render(this.info,'');
55 | },
56 | teardown(){
57 | this.hide(this.question);
58 | this.hide(this.response);
59 | this.show(this.start);
60 | },
61 | buttons(array){
62 | return array.map(value => ``).join('');
63 | }
64 | };
65 |
66 | const game = {
67 | start(quiz){
68 | console.log('start() invoked');
69 | this.score = 0;
70 | this.questions = [...quiz];
71 | view.setup();
72 | this.secondsRemaining = 20;
73 | this.timer = setInterval( this.countdown , 1000 );
74 | this.ask();
75 | },
76 | countdown() {
77 | game.secondsRemaining--;
78 | view.render(view.timer,game.secondsRemaining);
79 | if(game.secondsRemaining <= 0) {
80 | game.gameOver();
81 | }
82 | },
83 | ask(name){
84 | console.log('ask() invoked');
85 | if(this.questions.length > 2) {
86 | shuffle(this.questions);
87 | this.question = this.questions.pop();
88 | const options = [this.questions[0].realName, this.questions[1].realName, this.question.realName];
89 | shuffle(options);
90 | const question = `What is ${this.question.name}'s real name?`;
91 | view.render(view.question,question);
92 | view.render(view.response,view.buttons(options));
93 | }
94 | else {
95 | this.gameOver();
96 | }
97 | },
98 | check(event){
99 | console.log('check(event) invoked');
100 | const response = event.target.textContent;
101 | const answer = this.question.realName;
102 | if(response === answer){
103 | console.log('correct');
104 | view.render(view.result,'Correct!',{'class':'correct'});
105 | this.score++;
106 | view.render(view.score,this.score);
107 | } else {
108 | console.log('wrong');
109 | view.render(view.result,`Wrong! The correct answer was ${answer}`,{'class':'wrong'});
110 | }
111 | this.ask();
112 | },
113 | gameOver(){
114 | console.log('gameOver() invoked');
115 | view.render(view.info,`Game Over, you scored ${this.score} point${this.score !== 1 ? 's' : ''}`);
116 | view.teardown();
117 | clearInterval(this.timer);
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/Ch 13/quiz/questions.json:
--------------------------------------------------------------------------------
1 | {
2 | "questions": [{
3 | "name": "Superman",
4 | "realName": "Clarke Kent"
5 | },
6 | {
7 | "name": "Batman",
8 | "realName": "Bruce Wayne"
9 | },
10 | {
11 | "name": "Wonder Woman",
12 | "realName": "Dianna Prince"
13 | },
14 | {
15 | "name": "Spider-Man",
16 | "realName": "Peter Parker"
17 | },
18 | {
19 | "name": "Green Lantern",
20 | "realName": "Hal Jordan"
21 | },
22 | {
23 | "name": "Green Arrow",
24 | "realName": "Oliver Queen"
25 | },
26 | {
27 | "name": "The Flash",
28 | "realName": "Barry Allen"
29 | },
30 | {
31 | "name": "The Hulk",
32 | "realName": "Bruce Banner"
33 | },
34 | {
35 | "name": "Iron Man",
36 | "realName": "Tony Stark"
37 | },
38 | {
39 | "name": "The Punisher",
40 | "realName": "Frank Castle"
41 | },
42 | {
43 | "name": "Daredevil",
44 | "realName": "Matt Murdoch"
45 | },
46 | {
47 | "name": "Cyclops",
48 | "realName": "Scott Summers"
49 | },
50 | {
51 | "name": "Ghost Rider",
52 | "realName": "Johnny Blaze"
53 | },
54 | {
55 | "name": "Hawkeye",
56 | "realName": "Clint Barton"
57 | },
58 | {
59 | "name": "Aquaman",
60 | "realName": "Arthur Curry"
61 | },
62 | {
63 | "name": "Catwoman",
64 | "realName": "Selina Kyle"
65 | },
66 | {
67 | "name": "Beast",
68 | "realName": "Hank McCoy"
69 | },
70 | {
71 | "name": "Professor X",
72 | "realName": "Charles Xavier"
73 | },
74 | {
75 | "name": "Captain America",
76 | "realName": "Steve Rogers"
77 | },
78 | {
79 | "name": "Collossus",
80 | "realName": "Piotr Rasputin"
81 | },
82 | {
83 | "name": "Mr Fantastic",
84 | "realName": "Reed Richards"
85 | },
86 | {
87 | "name": "Invisible Girl",
88 | "realName": "Sue Storm"
89 | },
90 | {
91 | "name": "Iceman",
92 | "realName": "Bobby Drake"
93 | },
94 | {
95 | "name": "Martian Manhunter",
96 | "realName": "J'onn J'onzz "
97 | },
98 | {
99 | "name": "Two Face",
100 | "realName": "Harvey Dent"
101 | },
102 | {
103 | "name": "The Riddler",
104 | "realName": "Edward Nigma"
105 | },
106 | {
107 | "name": "Black Canary",
108 | "realName": "Dinah Lance"
109 | },
110 | {
111 | "name": "Killer Croc",
112 | "realName": "Waylon Jones"
113 | },
114 | {
115 | "name": "The Atom",
116 | "realName": "Ray Palmer"
117 | },
118 | {
119 | "name": "Animal Man",
120 | "realName": "Buddy Baker"
121 | },
122 | {
123 | "name": "Blue Beetle",
124 | "realName": "Jaime Reyes"
125 | },
126 | {
127 | "name": "Booster Gold",
128 | "realName": "Michael Carter"
129 | },
130 | {
131 | "name": "Captain Atom",
132 | "realName": "Nate Adam"
133 | },
134 | {
135 | "name": "Captain Marvel",
136 | "realName": "Carol Danvers"
137 | },
138 | {
139 | "name": "The Creeper",
140 | "realName": "Jack Ryder"
141 | },
142 | {
143 | "name": "Deathstroke",
144 | "realName": "Slade Wilson"
145 | },
146 | {
147 | "name": "Storm",
148 | "realName": "Ororo Munroe"
149 | },
150 | {
151 | "name": "Magneto",
152 | "realName": "Max Eisenhardt"
153 | },
154 | {
155 | "name": "The Human Torch",
156 | "realName": "Johnny Storm"
157 | },
158 | {
159 | "name": "Deadpool",
160 | "realName": "Wade Wilson"
161 | },
162 | {
163 | "name": "Black Panther",
164 | "realName": "T'Challa"
165 | },
166 | {
167 | "name": "The Thing",
168 | "realName": "Ben Grimm"
169 | },
170 | {
171 | "name": "Wolverine",
172 | "realName": "James Howlett"
173 | },
174 | {
175 | "name": "Nightcrawler",
176 | "realName": "Kurt Wagner"
177 | },
178 | {
179 | "name": "Gambit",
180 | "realName": "Remy Etienne LeBeau"
181 | },
182 | {
183 | "name": "Spider-Woman",
184 | "realName": "Jessica Drew"
185 | },
186 | {
187 | "name": "Doctor Doom",
188 | "realName": "Victor Von Doom"
189 | },
190 | {
191 | "name": "Nightwing",
192 | "realName": "Dick Grayson"
193 | },
194 | {
195 | "name": "Supergirl",
196 | "realName": "Kara Danvers"
197 | },
198 | {
199 | "name": "Scarecrow",
200 | "realName": "Jonathan Crane"
201 | },
202 | {
203 | "name": "The Penguin",
204 | "realName": "Oswald Cobblepot"
205 | },
206 | {
207 | "name": "Mister Miracle",
208 | "realName": "Scott Free"
209 | },
210 | {
211 | "name": "Hush",
212 | "realName": "Tommy Elliot"
213 | },
214 | {
215 | "name": "Huntress",
216 | "realName": "Helena Bertinelli"
217 | },
218 | {
219 | "name": "Hawkman",
220 | "realName": "Carter Hall"
221 | },
222 | {
223 | "name": "Hawkgirl",
224 | "realName": "Shiera Hall"
225 | },
226 | {
227 | "name": "Venom",
228 | "realName": "Eddi Brock"
229 | },
230 | {
231 | "name": "Rogue",
232 | "realName": "Anna Marie"
233 | },
234 | {
235 | "name": "Black Cat",
236 | "realName": "Felicia Hardy"
237 | },
238 | {
239 | "name": "White Queen",
240 | "realName": "Emma Frost"
241 | },
242 | {
243 | "name": "Captain Britain",
244 | "realName": "Brian Braddock"
245 | },
246 | {
247 | "name": "Doctor Strange",
248 | "realName": "Stephen Vincent Strange"
249 | },
250 | {
251 | "name": "Cable",
252 | "realName": "Nathan Summers"
253 | },
254 | {
255 | "name": "Dazzler",
256 | "realName": "Alison Blaire"
257 | },
258 | {
259 | "name": "Electro",
260 | "realName": "Maxwell Dillon"
261 | },
262 | {
263 | "name": "Falcon",
264 | "realName": "Sam Wilson"
265 | },
266 | {
267 | "name": "War Machine",
268 | "realName": "James Rhodes"
269 | },
270 | {
271 | "name": "Havok",
272 | "realName": "Alex Summers"
273 | },
274 | {
275 | "name": "Iron Fist",
276 | "realName": "Danny Rand"
277 | },
278 | {
279 | "name": "Batgirl",
280 | "realName": "Barbara Gordon"
281 | },
282 | {
283 | "name": "Scarlet Witch",
284 | "realName": "Wanda Maximoff"
285 | },
286 | {
287 | "name": "Quicksilver",
288 | "realName": "Pietro Maximoff"
289 | },
290 | {
291 | "name": "Sabretooth",
292 | "realName": "Victor Creed"
293 | },
294 | {
295 | "name": "She-Hulk",
296 | "realName": "Jennifer Walters"
297 | },
298 | {
299 | "name": "Sunfire",
300 | "realName": "Shiro Yoshida"
301 | },
302 | {
303 | "name": "Killer Frost",
304 | "realName": "Caitlin Snow"
305 | },
306 | {
307 | "name": "Captain Boomerang",
308 | "realName": "George Harkness"
309 | },
310 | {
311 | "name": "Cyborg",
312 | "realName": "Victor Stone"
313 | }, {
314 | "name": "Enchantress",
315 | "realName": "June Moon"
316 | },
317 | {
318 | "name": "Doctor Strange",
319 | "realName": "Stephen Vincent Strange"
320 | }
321 | ]
322 | }
323 |
--------------------------------------------------------------------------------
/Ch 13/quiz/styles.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css?family=Baloo+Da|Roboto');
2 |
3 | body{
4 | background: #5F1C1C;
5 | font-family: 'Roboto', sans-serif;
6 | }
7 | .dojo{
8 | background: url(https://gistcdn.githack.com/alexmwalker/6acbe9040d9fe6e5e9fd758a25e1b2a5/raw/635810bd1a925c06b5c0bc0c861d62fe53597078/dojo.svg) no-repeat;
9 | width: 100%;
10 | height: 800px;
11 | background-size: 100% auto;
12 | padding-top: 10px;
13 | }
14 | .quiz-body{
15 | background: rgba(255,255,255,1);
16 | margin: 150px 33%;
17 | padding: 10px 20px 50px 20px;
18 | -webkit-box-shadow: 4px 4px 11px 3px rgba(0,0,0,0.3);
19 | -moz-box-shadow: 4px 4px 11px 3px rgba(0,0,0,0.3);
20 | box-shadow: 4px 4px 11px 3px rgba(0,0,0,0.3);
21 | }
22 | h1{
23 | color: #611BBD;
24 | font-family: 'Baloo Da', cursive;
25 | font-weight: 900;
26 | text-align: center;
27 | font-size: 48px;
28 | margin: 0;
29 | }
30 | button {
31 | color: #ffffff;
32 | background-color: #611BBD;
33 | border-color: #130269;
34 | border-radius: 4px;
35 | margin: 0.2em 0;
36 | display: block;
37 | width: 100%;
38 | font-size: 24px;
39 | }
40 | #question {
41 | font-size: 24px;
42 | }
43 |
44 | #result{
45 | color: #fff;
46 | margin: 0.2em 0;
47 | width: 100%;
48 | text-align: center;
49 | }
50 | .correct {
51 | background-color: #0c0;
52 | }
53 | .wrong {
54 | color: #fff;
55 | background-color: #c00;
56 | }
57 |
--------------------------------------------------------------------------------
/Ch 13/todo/main.js:
--------------------------------------------------------------------------------
1 | const form = document.forms['todo'];
2 | form.addEventListener('submit', addTask, false);
3 |
4 | function addTask(event) {
5 | event.preventDefault();
6 | const number = form.task.value;
7 | const task = {
8 | userId: 1,
9 | title: form.task.value,
10 | completed: false
11 | }
12 | const data = JSON.stringify(task);
13 |
14 | const headers = new Headers({
15 | 'Accept': 'application/json',
16 | 'Content-Type': 'application/json'
17 | });
18 | const request = new Request(form.action,
19 | {
20 | method: form.method,
21 | header: headers,
22 | body: data
23 | }
24 | )
25 |
26 | fetch(request)
27 | .then( response => response.json() )
28 | .then( task => console.log(`Task saved with an id of ${task.id}`) )
29 | .catch( error => console.log('There was an error:', error))
30 |
31 | }
32 |
--------------------------------------------------------------------------------
/Ch 13/todo/todo.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | To Do List
6 |
7 |
8 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/Ch 14/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/spbooks/jsninja2/99190428cc21281912042f69ae2306c958bdc268/Ch 14/.DS_Store
--------------------------------------------------------------------------------
/Ch 14/canvas/canvas.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Canvas Example
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/Ch 14/canvas/main.js:
--------------------------------------------------------------------------------
1 | const canvasElement = document.getElementById('canvas');
2 | const context = canvasElement.getContext('2d');
3 | context.fillStyle = "#0000cc"; // a blue fill color
4 | context.strokeStyle = "#ccc"; // a gray stroke color
5 | context.lineWidth = 4;
6 | context.fillRect(10,10,100,50);
7 | context.strokeRect(10,100,100,50);
8 |
9 | context.beginPath();
10 | context.moveTo(130, 50);
11 | context.lineTo(180, 50);
12 | context.moveTo(155, 50);
13 | context.lineTo(155, 90);
14 | context.strokeStyle = '#c00';
15 | context.lineWidth = 15;
16 | context.stroke();
17 |
18 | context.beginPath();
19 | context.arc(200, 200, 30, 0, Math.PI * 2, false);
20 | context.strokeStyle = '#ff0';
21 | context.lineWidth = 4;
22 | context.stroke();
23 |
24 | context.fillStyle = '#0c0'; // a blue fill color
25 | context.font = 'bold 26px sans-serif';
26 | context.fillText('Hello', 20, 200);
27 |
--------------------------------------------------------------------------------
/Ch 14/quiz/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Quiz Ninja
7 |
8 |
9 |
10 |
11 |
12 |
13 | Time: 20
14 | Score: 0
15 | High Score:
16 | Quiz Ninja!
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/Ch 14/quiz/main.js:
--------------------------------------------------------------------------------
1 | const url = 'https://spbooks.github.io/jsninja2/questions.json';
2 |
3 | fetch(url)
4 | .then(res => res.json())
5 | .then(quiz => {
6 | view.start.addEventListener('click', () => game.start(quiz.questions), false);
7 | view.response.addEventListener('click', (event) => game.check(event), false);
8 | });
9 |
10 | // Utility functions
11 | function random(a,b=1) {
12 | // if only 1 argument is provided, we need to swap the values of a and b
13 | if (b === 1) {
14 | [a,b] = [b,a];
15 | }
16 | return Math.floor((b-a+1) * Math.random()) + a;
17 | }
18 |
19 | function shuffle(array) {
20 | for (let i = array.length; i; i--) {
21 | let j = random(i)-1;
22 | [array[i - 1], array[j]] = [array[j], array[i - 1]];
23 | }
24 | }
25 |
26 | // View Object
27 | const view = {
28 | score: document.querySelector('#score strong'),
29 | question: document.querySelector('#question'),
30 | result: document.querySelector('#result'),
31 | info: document.querySelector('#info'),
32 | start: document.querySelector('#start'),
33 | response: document.querySelector('#response'),
34 | timer: document.querySelector('#timer strong'),
35 | hiScore: document.querySelector('#hiScore strong'),
36 | render(target,content,attributes) {
37 | for(const key in attributes) {
38 | target.setAttribute(key, attributes[key]);
39 | }
40 | target.innerHTML = content;
41 | },
42 | show(element){
43 | element.style.display = 'block';
44 | },
45 | hide(element){
46 | element.style.display = 'none';
47 | },
48 | setup(){
49 | this.show(this.question);
50 | this.show(this.response);
51 | this.show(this.result);
52 | this.hide(this.start);
53 | this.render(this.score,game.score);
54 | this.render(this.result,'');
55 | this.render(this.info,'');
56 | this.render(this.hiScore, game.hiScore());
57 | },
58 | teardown(){
59 | this.hide(this.question);
60 | this.hide(this.response);
61 | this.show(this.start);
62 | this.render(this.hiScore, game.hiScore());
63 | },
64 | buttons(array){
65 | return array.map(value => ``).join('');
66 | }
67 | };
68 |
69 | const game = {
70 | start(quiz){
71 | console.log('start() invoked');
72 | this.score = 0;
73 | this.questions = [...quiz];
74 | view.setup();
75 | this.secondsRemaining = 20;
76 | this.timer = setInterval( this.countdown , 1000 );
77 | this.ask();
78 | },
79 | countdown() {
80 | game.secondsRemaining--;
81 | view.render(view.timer,game.secondsRemaining);
82 | if(game.secondsRemaining <= 0) {
83 | game.gameOver();
84 | }
85 | },
86 | ask(name){
87 | console.log('ask() invoked');
88 | if(this.questions.length > 2) {
89 | shuffle(this.questions);
90 | this.question = this.questions.pop();
91 | const options = [this.questions[0].realName, this.questions[1].realName, this.question.realName];
92 | shuffle(options);
93 | const question = `What is ${this.question.name}'s real name?`;
94 | view.render(view.question,question);
95 | view.render(view.response,view.buttons(options));
96 | }
97 | else {
98 | this.gameOver();
99 | }
100 | },
101 | check(event){
102 | console.log('check(event) invoked');
103 | const response = event.target.textContent;
104 | const answer = this.question.realName;
105 | if(response === answer){
106 | console.log('correct');
107 | view.render(view.result,'Correct!',{'class':'correct'});
108 | this.score++;
109 | view.render(view.score,this.score);
110 | } else {
111 | console.log('wrong');
112 | view.render(view.result,`Wrong! The correct answer was ${answer}`,{'class':'wrong'});
113 | }
114 | this.ask();
115 | },
116 | gameOver(){
117 | console.log('gameOver() invoked');
118 | view.render(view.info,`Game Over, you scored ${this.score} point${this.score !== 1 ? 's' : ''}`);
119 | view.teardown();
120 | clearInterval(this.timer);
121 | },
122 | hiScore(){
123 | const hi = localStorage.getItem('highScore') || 0;
124 | if(this.score > hi || hi === 0) {
125 | localStorage.setItem('highScore',this.score);
126 | view.render(view.info,'** NEW HIGH SCORE! **');
127 | }
128 | return localStorage.getItem('highScore');
129 | }
130 | }
131 |
--------------------------------------------------------------------------------
/Ch 14/quiz/styles.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css?family=Baloo+Da|Roboto');
2 |
3 | body{
4 | background: #5F1C1C;
5 | font-family: 'Roboto', sans-serif;
6 | }
7 | .dojo{
8 | background: url(https://gistcdn.githack.com/alexmwalker/6acbe9040d9fe6e5e9fd758a25e1b2a5/raw/635810bd1a925c06b5c0bc0c861d62fe53597078/dojo.svg) no-repeat;
9 | width: 100%;
10 | height: 800px;
11 | background-size: 100% auto;
12 | padding-top: 10px;
13 | }
14 | .quiz-body{
15 | background: rgba(255,255,255,1);
16 | margin: 150px 33%;
17 | padding: 10px 20px 50px 20px;
18 | -webkit-box-shadow: 4px 4px 11px 3px rgba(0,0,0,0.3);
19 | -moz-box-shadow: 4px 4px 11px 3px rgba(0,0,0,0.3);
20 | box-shadow: 4px 4px 11px 3px rgba(0,0,0,0.3);
21 | }
22 | h1{
23 | color: #611BBD;
24 | font-family: 'Baloo Da', cursive;
25 | font-weight: 900;
26 | text-align: center;
27 | font-size: 48px;
28 | margin: 0;
29 | }
30 | button {
31 | color: #ffffff;
32 | background-color: #611BBD;
33 | border-color: #130269;
34 | border-radius: 4px;
35 | margin: 0.2em 0;
36 | display: block;
37 | width: 100%;
38 | font-size: 24px;
39 | }
40 | #question {
41 | font-size: 24px;
42 | }
43 |
44 | #result{
45 | color: #fff;
46 | margin: 0.2em 0;
47 | width: 100%;
48 | text-align: center;
49 | }
50 | .correct {
51 | background-color: #0c0;
52 | }
53 | .wrong {
54 | color: #fff;
55 | background-color: #c00;
56 | }
57 |
--------------------------------------------------------------------------------
/Ch 14/websocket/main.js:
--------------------------------------------------------------------------------
1 | const URL = 'wss://echo.websocket.org/';
2 | const outputDiv = document.getElementById('output');
3 | const form = document.forms[0];
4 | const connection = new WebSocket(URL);
5 |
6 | connection.addEventListener('open', (event) => {
7 | output('CONNECTED');
8 | }, false);
9 |
10 | function output(message)
11 | {
12 | const para = document.createElement('p');
13 | para.innerHTML = message;
14 | outputDiv.appendChild(para);
15 | }
16 |
17 | form.addEventListener('submit', message, false);
18 |
19 | function message(event) {
20 | event.preventDefault();
21 | const text = form.message.value;
22 | output(`SENT: ${text}`)
23 | connection.send(text);
24 | }
25 |
26 | connection.addEventListener('message', (event) => {
27 | output(`RESPONSE: ${event.data}`);
28 | }, false);
29 |
30 | connection.addEventListener('close', (event) => {
31 | output('DISCONNECTED');
32 | }, false);
33 |
34 | connection.addEventListener('error', (event) => {
35 | output(`ERROR: ${event.data}`);
36 | }, false);
37 |
--------------------------------------------------------------------------------
/Ch 14/websocket/websocket.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Websocket Example
6 |
7 |
8 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/Ch 14/worker/factors.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Factorizor
6 |
7 |
8 |
9 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/Ch 14/worker/factors.js:
--------------------------------------------------------------------------------
1 | function factorsOf(n) {
2 | if(Number.isNaN(Number(n))) {
3 | throw new RangeError('Argument Error: Value must be an integer');
4 | }
5 | if(n < 0) {
6 | throw new RangeError('Argument Error: Number must be positive');
7 | }
8 | if(!Number.isInteger(n)) {
9 | throw new RangeError('Argument Error: Number must be an integer');
10 | }
11 | const factors = [];
12 | for (let i=1 , max = Math.sqrt(n); i <= max ; i++) {
13 | if (n%i === 0){
14 | factors.push(i,n/i);
15 | }
16 | }
17 | return factors.sort((a,b) => a - b);
18 | }
19 |
20 | self.addEventListener('message', (event) => {
21 |
22 | const factors = String(factorsOf(Number(event.data)));
23 | self.postMessage(factors);
24 | self.close();
25 |
26 | }, false);
27 |
--------------------------------------------------------------------------------
/Ch 14/worker/main.js:
--------------------------------------------------------------------------------
1 | const button = document.getElementById('rainbow');
2 |
3 | const colors = [ 'red', 'orange', 'yellow', 'green', 'blue', 'indigo', 'violet' ];
4 |
5 | function change() {
6 | document.body.style.background = colors[Math.floor(7*
7 | Math.random())];
8 | }
9 | button.addEventListener('click', change);
10 |
11 | const form = document.forms[0];
12 | form.addEventListener('submit', factorize, false);
13 |
14 |
15 | function factorize(event) {
16 | // prevent the form from being submitted
17 | event.preventDefault();
18 | document.getElementById('output').innerHTML = 'This coud take a while ...
';
19 | const number = Number(form.number.value);
20 | if(window.Worker) {
21 | const worker = new Worker('factors.js');
22 | worker.postMessage(number);
23 | worker.addEventListener('message', (event) => {
24 | document.getElementById('output').innerHTML = event.data;
25 | }, false);
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Ch 15/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/spbooks/jsninja2/99190428cc21281912042f69ae2306c958bdc268/Ch 15/.DS_Store
--------------------------------------------------------------------------------
/Ch 15/MVC/list.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | MVC List
6 |
7 |
8 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/Ch 15/MVC/main.js:
--------------------------------------------------------------------------------
1 | 'use strict'
2 |
3 | const form = document.forms[0];
4 |
5 | class Item {
6 | constructor(name) {
7 | this.name = name;
8 | }
9 | }
10 |
11 | const controller = {
12 | watch(form) {
13 | form.addEventListener('submit', (event) => {
14 | event.preventDefault(); // prevent the form from being submitted
15 | this.add(form.name.value);
16 | }, false);
17 | },
18 |
19 | add(name) {
20 | const item = new Item(name);
21 | view.render(item);
22 | }
23 | }
24 |
25 | const view = {
26 | render(item) {
27 | const list = document.getElementById('list');
28 | const li = document.createElement('li');
29 | li.innerHTML = item.name;
30 | list.appendChild(li);
31 | // reset the input field
32 | form.name.value = '';
33 | }
34 | }
35 |
36 | controller.watch(form);
37 |
--------------------------------------------------------------------------------
/Ch 15/quiz/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/spbooks/jsninja2/99190428cc21281912042f69ae2306c958bdc268/Ch 15/quiz/.DS_Store
--------------------------------------------------------------------------------
/Ch 15/quiz/dist/bundle.min.js:
--------------------------------------------------------------------------------
1 | (function(a){function b(d){if(c[d])return c[d].exports;var e=c[d]={i:d,l:!1,exports:{}};return a[d].call(e.exports,e,e.exports,b),e.l=!0,e.exports}var c={};return b.m=a,b.c=c,b.d=function(a,c,d){b.o(a,c)||Object.defineProperty(a,c,{configurable:!1,enumerable:!0,get:d})},b.n=function(a){var c=a&&a.__esModule?function(){return a['default']}:function(){return a};return b.d(c,'a',c),c},b.o=function(a,b){return Object.prototype.hasOwnProperty.call(a,b)},b.p='',b(b.s=0)})([function(a,b,c){'use strict';var d=c(1);fetch('https://s3-us-west-2.amazonaws.com/s.cdpn.io/123941/questions.json').then(function(b){return b.json()}).then(function(b){console.log('questions loaded!'),d.view.start.addEventListener('click',function(){return d.game.start(b.questions)},!1),d.view.response.addEventListener('click',function(b){return d.game.check(b)},!1)})},function(a,b,c){'use strict';function d(d){if(Array.isArray(d)){for(var a=0,b=Array(d.length);a'+b+''}).join('')}},g={start:function(b){console.log('start() invoked'),this.score=0,this.questions=[].concat(d(b)),f.setup(),this.secondsRemaining=20,this.timer=setInterval(this.countdown,1e3),this.ask()},countdown:function(){g.secondsRemaining--,f.render(f.timer,g.secondsRemaining),0>=g.secondsRemaining&&g.gameOver()},ask:function(){if(console.log('ask() invoked'),2b||0===b)&&localStorage.setItem('highScore',this.score),localStorage.getItem('highScore')}};b.view=f,b.game=g},function(a,b){'use strict';function e(d){var c=1
2 |
3 |
4 |
5 |
6 | Quiz Ninja
7 |
8 |
9 |
10 |
11 |
12 |
13 | Time: 20
14 | Score: 0
15 | High Score:
16 | Quiz Ninja!
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/Ch 15/quiz/dist/styles.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css?family=Baloo+Da|Roboto');
2 |
3 | body{
4 | background: #5F1C1C;
5 | font-family: 'Roboto', sans-serif;
6 | }
7 | .dojo{
8 | background: url(https://gistcdn.githack.com/alexmwalker/6acbe9040d9fe6e5e9fd758a25e1b2a5/raw/635810bd1a925c06b5c0bc0c861d62fe53597078/dojo.svg) no-repeat;
9 | width: 100%;
10 | height: 800px;
11 | background-size: 100% auto;
12 | padding-top: 10px;
13 | }
14 | .quiz-body{
15 | background: rgba(255,255,255,1);
16 | margin: 150px 33%;
17 | padding: 10px 20px 50px 20px;
18 | -webkit-box-shadow: 4px 4px 11px 3px rgba(0,0,0,0.3);
19 | -moz-box-shadow: 4px 4px 11px 3px rgba(0,0,0,0.3);
20 | box-shadow: 4px 4px 11px 3px rgba(0,0,0,0.3);
21 | }
22 | h1{
23 | color: #611BBD;
24 | font-family: 'Baloo Da', cursive;
25 | font-weight: 900;
26 | text-align: center;
27 | font-size: 48px;
28 | margin: 0;
29 | }
30 | button {
31 | color: #ffffff;
32 | background-color: #611BBD;
33 | border-color: #130269;
34 | border-radius: 4px;
35 | margin: 0.2em 0;
36 | display: block;
37 | width: 100%;
38 | font-size: 24px;
39 | }
40 | #question {
41 | font-size: 24px;
42 | }
43 |
44 | #result{
45 | color: #fff;
46 | margin: 0.2em 0;
47 | width: 100%;
48 | text-align: center;
49 | }
50 | .correct {
51 | background-color: #0c0;
52 | }
53 | .wrong {
54 | color: #fff;
55 | background-color: #c00;
56 | }
57 |
--------------------------------------------------------------------------------
/Ch 15/quiz/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "quiz-ninja",
3 | "version": "1.0.0",
4 | "description": "A JavaScript quiz.",
5 | "main": "main.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "build": "webpack --progress --colors --profile"
9 | },
10 | "keywords": [
11 | "quiz",
12 | "ninja",
13 | "javascript"
14 | ],
15 | "author": "DAZ",
16 | "license": "MIT",
17 | "devDependencies": {
18 | "babel-core": "^6.25.0",
19 | "babel-loader": "^7.1.1",
20 | "babel-preset-env": "^1.6.0",
21 | "babili-webpack-plugin": "^0.1.2",
22 | "webpack": "^3.0.0"
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Ch 15/quiz/src/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/spbooks/jsninja2/99190428cc21281912042f69ae2306c958bdc268/Ch 15/quiz/src/.DS_Store
--------------------------------------------------------------------------------
/Ch 15/quiz/src/game.js:
--------------------------------------------------------------------------------
1 | export default {
2 | start(quiz){
3 | console.log('start() invoked');
4 | this.score = 0;
5 | this.questions = [...quiz];
6 | view.setup();
7 | this.secondsRemaining = 20;
8 | this.timer = setInterval( this.countdown , 1000 );
9 | this.ask();
10 | },
11 | countdown() {
12 | game.secondsRemaining--;
13 | view.render(view.timer,game.secondsRemaining);
14 | if(game.secondsRemaining <= 0) {
15 | game.gameOver();
16 | }
17 | },
18 | ask(name){
19 | console.log('ask() invoked');
20 | if(this.questions.length > 2) {
21 | shuffle(this.questions);
22 | this.question = this.questions.pop();
23 | const options = [this.questions[0].answer, this.questions[1].answer, this.question.answer];
24 | shuffle(options);
25 | const question = `What is ${this.question.question}'s real name?`;
26 | view.render(view.question,question);
27 | view.render(view.response,view.buttons(options));
28 | }
29 | else {
30 | this.gameOver();
31 | }
32 | },
33 | check(event){
34 | console.log('check(event) invoked')
35 | const response = event.target.textContent;
36 | const answer = this.question.answer;
37 | if(response === answer){
38 | console.log('correct');
39 | view.render(view.result,'Correct!',{'class':'correct'});
40 | this.score++;
41 | view.render(view.score,this.score);
42 | } else {
43 | console.log('wrong');
44 | view.render(view.result,`Wrong! The correct answer was ${answer}`,{'class':'wrong'});
45 | }
46 | this.ask();
47 | },
48 | gameOver(){
49 | console.log('gameOver() invoked')
50 | view.render(view.info,`Game Over, you scored ${this.score} point${this.score !== 1 ? 's' : ''}`);
51 | view.teardown();
52 | clearInterval(this.timer);
53 | },
54 | hiScore(){
55 | const hi = localStorage.getItem('highScore') || 0;
56 | if(this.score > hi || hi === 0) localStorage.setItem('highScore',this.score);
57 | return localStorage.getItem('highScore');
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/Ch 15/quiz/src/main.js:
--------------------------------------------------------------------------------
1 | import { view, game } from './quiz.js';
2 |
3 | const url = 'https://spbooks.github.io/jsninja2/questions.json';
4 |
5 | fetch(url)
6 | .then(res => res.json())
7 | .then(quiz => {
8 | console.log('questions loaded!');
9 | view.start.addEventListener('click', () => game.start(quiz.questions), false);
10 | view.response.addEventListener('click', (event) => game.check(event), false);
11 | });
12 |
--------------------------------------------------------------------------------
/Ch 15/quiz/src/quiz.js:
--------------------------------------------------------------------------------
1 | import { random, shuffle } from './utilities.js';
2 |
3 | const view = {
4 | score: document.querySelector('#score strong'),
5 | question: document.querySelector('#question'),
6 | result: document.querySelector('#result'),
7 | info: document.querySelector('#info'),
8 | start: document.querySelector('#start'),
9 | response: document.querySelector('#response'),
10 | timer: document.querySelector('#timer strong'),
11 | hiScore: document.querySelector('#hiScore strong'),
12 | render(target,content,attributes) {
13 | for(const key in attributes) {
14 | target.setAttribute(key, attributes[key]);
15 | }
16 | target.innerHTML = content;
17 | },
18 | show(element){
19 | element.style.display = 'block';
20 | },
21 | hide(element){
22 | element.style.display = 'none';
23 | },
24 | setup(){
25 | this.show(this.question);
26 | this.show(this.response);
27 | this.show(this.result);
28 | this.hide(this.start);
29 | this.render(this.score,game.score);
30 | this.render(this.result,'');
31 | this.render(this.info,'');
32 | this.render(this.hiScore, game.hiScore());
33 | },
34 | teardown(){
35 | this.hide(this.question);
36 | this.hide(this.response);
37 | this.show(this.start);
38 | this.render(this.hiScore, game.hiScore());
39 | },
40 | buttons(array){
41 | return array.map(value => ``).join('');
42 | }
43 | };
44 |
45 | const game = {
46 | start(quiz){
47 | console.log('start() invoked');
48 | this.score = 0;
49 | this.questions = [...quiz];
50 | view.setup();
51 | this.secondsRemaining = 20;
52 | this.timer = setInterval( this.countdown , 1000 );
53 | this.ask();
54 | },
55 | countdown() {
56 | game.secondsRemaining--;
57 | view.render(view.timer,game.secondsRemaining);
58 | if(game.secondsRemaining <= 0) {
59 | game.gameOver();
60 | }
61 | },
62 | ask(name){
63 | console.log('ask() invoked');
64 | if(this.questions.length > 2) {
65 | shuffle(this.questions);
66 | this.question = this.questions.pop();
67 | const options = [this.questions[0].realName, this.questions[1].realName, this.question.realName];
68 | shuffle(options);
69 | const question = `What is ${this.question.name}'s real name?`;
70 | view.render(view.question,question);
71 | view.render(view.response,view.buttons(options));
72 | }
73 | else {
74 | this.gameOver();
75 | }
76 | },
77 | check(event){
78 | console.log('check(event) invoked')
79 | const response = event.target.textContent;
80 | const answer = this.question.realName;
81 | if(response === answer){
82 | console.log('correct');
83 | view.render(view.result,'Correct!',{'class':'correct'});
84 | this.score++;
85 | view.render(view.score,this.score);
86 | } else {
87 | console.log('wrong');
88 | view.render(view.result,`Wrong! The correct answer was ${answer}`,{'class':'wrong'});
89 | }
90 | this.ask();
91 | },
92 | gameOver(){
93 | console.log('gameOver() invoked')
94 | view.render(view.info,`Game Over, you scored ${this.score} point${this.score !== 1 ? 's' : ''}`);
95 | view.teardown();
96 | clearInterval(this.timer);
97 | },
98 | hiScore(){
99 | const hi = localStorage.getItem('highScore') || 0;
100 | if(this.score > hi || hi === 0) localStorage.setItem('highScore',this.score);
101 | return localStorage.getItem('highScore');
102 | }
103 | };
104 |
105 | export {
106 | view,
107 | game
108 | }
109 |
--------------------------------------------------------------------------------
/Ch 15/quiz/src/utilities.js:
--------------------------------------------------------------------------------
1 | function random(a,b=1) {
2 | // if only 1 argument is provided, we need to swap the values of a and b
3 | if (b === 1) {
4 | [a,b] = [b,a];
5 | }
6 | return Math.floor((b-a+1) * Math.random()) + a;
7 | }
8 |
9 | function shuffle(array) {
10 | for (let i = array.length; i; i--) {
11 | let j = random(i)-1;
12 | [array[i - 1], array[j]] = [array[j], array[i - 1]];
13 | }
14 | }
15 |
16 | export {
17 | random,
18 | shuffle
19 | }
20 |
--------------------------------------------------------------------------------
/Ch 15/quiz/src/view.js:
--------------------------------------------------------------------------------
1 | export default {
2 | score: document.querySelector('#score strong'),
3 | question: document.querySelector('#question'),
4 | result: document.querySelector('#result'),
5 | info: document.querySelector('#info'),
6 | start: document.querySelector('#start'),
7 | response: document.querySelector('#response'),
8 | timer: document.querySelector('#timer strong'),
9 | hiScore: document.querySelector('#hiScore strong'),
10 | render(target,content,attributes) {
11 | for(const key in attributes) {
12 | target.setAttribute(key, attributes[key]);
13 | }
14 | target.innerHTML = content;
15 | },
16 | show(element){
17 | element.style.display = 'block';
18 | },
19 | hide(element){
20 | element.style.display = 'none';
21 | },
22 | setup(){
23 | this.show(this.question);
24 | this.show(this.response);
25 | this.show(this.result);
26 | this.hide(this.start);
27 | this.render(this.score,game.score);
28 | this.render(this.result,'');
29 | this.render(this.info,'');
30 | this.render(this.hiScore, game.hiScore());
31 | },
32 | teardown(){
33 | this.hide(this.question);
34 | this.hide(this.response);
35 | this.show(this.start);
36 | this.render(this.hiScore, game.hiScore());
37 | },
38 | buttons(array){
39 | return array.map(value => ``).join('');
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/Ch 15/quiz/webpack.config.js:
--------------------------------------------------------------------------------
1 | const webpack = require('webpack');
2 | const BabiliPlugin = require("babili-webpack-plugin");
3 |
4 | module.exports = {
5 | context: __dirname + '/src',
6 | entry: './main.js',
7 | output: {
8 | path: __dirname + '/dist',
9 | filename: 'bundle.min.js'
10 | },
11 |
12 | module: {
13 | rules: [
14 | {
15 | test: /\.js$/,
16 | exclude: /node_modules/,
17 | use: {
18 | loader: 'babel-loader',
19 | options: {
20 | presets: ['env','babili']
21 | }
22 | }
23 | }
24 | ]
25 | },
26 | plugins: [
27 | new BabiliPlugin(),
28 | new webpack.DefinePlugin({
29 | 'process.env': {
30 | 'NODE_ENV': JSON.stringify('production')
31 | }
32 | })
33 | ]
34 | };
35 |
--------------------------------------------------------------------------------
/Ch 15/webpack-example/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/spbooks/jsninja2/99190428cc21281912042f69ae2306c958bdc268/Ch 15/webpack-example/.DS_Store
--------------------------------------------------------------------------------
/Ch 15/webpack-example/main.js:
--------------------------------------------------------------------------------
1 | import _ from 'lodash';
2 | console.log(_.now());
3 |
--------------------------------------------------------------------------------
/Ch 15/webpack-example/package-lock.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "webpack-example",
3 | "version": "1.0.0",
4 | "lockfileVersion": 1,
5 | "dependencies": {
6 | "acorn": {
7 | "version": "5.1.0",
8 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-5.1.0.tgz",
9 | "integrity": "sha512-WXZ0VTJT8EE25BmZjc+wr0qIwG7QaEna9csPKHS6WQp8gDo4V376wUWi222LXRiuAF6CAS4Ejv736DdRwuPK9g==",
10 | "dev": true
11 | },
12 | "acorn-dynamic-import": {
13 | "version": "2.0.2",
14 | "resolved": "https://registry.npmjs.org/acorn-dynamic-import/-/acorn-dynamic-import-2.0.2.tgz",
15 | "integrity": "sha1-x1K9IQvvZ5UBtsbLf8hPj0cVjMQ=",
16 | "dev": true,
17 | "dependencies": {
18 | "acorn": {
19 | "version": "4.0.13",
20 | "resolved": "https://registry.npmjs.org/acorn/-/acorn-4.0.13.tgz",
21 | "integrity": "sha1-EFSVrlNh1pe9GVyCUZLhrX8lN4c=",
22 | "dev": true
23 | }
24 | }
25 | },
26 | "ajv": {
27 | "version": "5.2.0",
28 | "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.2.0.tgz",
29 | "integrity": "sha1-wXNQJMXaLvdcwZBxMHPUTwmL9IY=",
30 | "dev": true
31 | },
32 | "ajv-keywords": {
33 | "version": "2.1.0",
34 | "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-2.1.0.tgz",
35 | "integrity": "sha1-opbhf3v658HOT34N5T0pyzIWLfA=",
36 | "dev": true
37 | },
38 | "align-text": {
39 | "version": "0.1.4",
40 | "resolved": "https://registry.npmjs.org/align-text/-/align-text-0.1.4.tgz",
41 | "integrity": "sha1-DNkKVhCT810KmSVsIrcGlDP60Rc=",
42 | "dev": true
43 | },
44 | "ansi-regex": {
45 | "version": "2.1.1",
46 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
47 | "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=",
48 | "dev": true
49 | },
50 | "anymatch": {
51 | "version": "1.3.0",
52 | "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.0.tgz",
53 | "integrity": "sha1-o+Uvo5FoyCX/V7AkgSbOWo/5VQc=",
54 | "dev": true
55 | },
56 | "arr-diff": {
57 | "version": "2.0.0",
58 | "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz",
59 | "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=",
60 | "dev": true
61 | },
62 | "arr-flatten": {
63 | "version": "1.1.0",
64 | "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
65 | "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==",
66 | "dev": true
67 | },
68 | "array-unique": {
69 | "version": "0.2.1",
70 | "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz",
71 | "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM=",
72 | "dev": true
73 | },
74 | "arrify": {
75 | "version": "1.0.1",
76 | "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz",
77 | "integrity": "sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0=",
78 | "dev": true
79 | },
80 | "asn1.js": {
81 | "version": "4.9.1",
82 | "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.9.1.tgz",
83 | "integrity": "sha1-SLokC0WpKA6UdImQull9IWYX/UA=",
84 | "dev": true
85 | },
86 | "assert": {
87 | "version": "1.4.1",
88 | "resolved": "https://registry.npmjs.org/assert/-/assert-1.4.1.tgz",
89 | "integrity": "sha1-mZEtWRg2tab1s0XA8H7vwI/GXZE=",
90 | "dev": true
91 | },
92 | "async": {
93 | "version": "2.5.0",
94 | "resolved": "https://registry.npmjs.org/async/-/async-2.5.0.tgz",
95 | "integrity": "sha512-e+lJAJeNWuPCNyxZKOBdaJGyLGHugXVQtrAwtuAe2vhxTYxFTKE73p8JuTmdH0qdQZtDvI4dhJwjZc5zsfIsYw==",
96 | "dev": true
97 | },
98 | "async-each": {
99 | "version": "1.0.1",
100 | "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz",
101 | "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=",
102 | "dev": true
103 | },
104 | "balanced-match": {
105 | "version": "1.0.0",
106 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
107 | "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
108 | "dev": true
109 | },
110 | "base64-js": {
111 | "version": "1.2.1",
112 | "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.2.1.tgz",
113 | "integrity": "sha512-dwVUVIXsBZXwTuwnXI9RK8sBmgq09NDHzyR9SAph9eqk76gKK2JSQmZARC2zRC81JC2QTtxD0ARU5qTS25gIGw==",
114 | "dev": true
115 | },
116 | "big.js": {
117 | "version": "3.1.3",
118 | "resolved": "https://registry.npmjs.org/big.js/-/big.js-3.1.3.tgz",
119 | "integrity": "sha1-TK2iGTZS6zyp7I5VyQFWacmAaXg=",
120 | "dev": true
121 | },
122 | "binary-extensions": {
123 | "version": "1.8.0",
124 | "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.8.0.tgz",
125 | "integrity": "sha1-SOyNFt9Dd+rl+liEaCSAr02Vx3Q=",
126 | "dev": true
127 | },
128 | "bn.js": {
129 | "version": "4.11.7",
130 | "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.7.tgz",
131 | "integrity": "sha512-LxFiV5mefv0ley0SzqkOPR1bC4EbpPx8LkOz5vMe/Yi15t5hzwgO/G+tc7wOtL4PZTYjwHu8JnEiSLumuSjSfA==",
132 | "dev": true
133 | },
134 | "brace-expansion": {
135 | "version": "1.1.8",
136 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz",
137 | "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=",
138 | "dev": true
139 | },
140 | "braces": {
141 | "version": "1.8.5",
142 | "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz",
143 | "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=",
144 | "dev": true
145 | },
146 | "brorand": {
147 | "version": "1.1.0",
148 | "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz",
149 | "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=",
150 | "dev": true
151 | },
152 | "browserify-aes": {
153 | "version": "1.0.6",
154 | "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.0.6.tgz",
155 | "integrity": "sha1-Xncl297x/Vkw1OurSFZ85FHEigo=",
156 | "dev": true
157 | },
158 | "browserify-cipher": {
159 | "version": "1.0.0",
160 | "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.0.tgz",
161 | "integrity": "sha1-mYgkSHS/XtTijalWZtzWasj8Njo=",
162 | "dev": true
163 | },
164 | "browserify-des": {
165 | "version": "1.0.0",
166 | "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.0.tgz",
167 | "integrity": "sha1-2qJ3cXRwki7S/hhZQRihdUOXId0=",
168 | "dev": true
169 | },
170 | "browserify-rsa": {
171 | "version": "4.0.1",
172 | "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz",
173 | "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=",
174 | "dev": true
175 | },
176 | "browserify-sign": {
177 | "version": "4.0.4",
178 | "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz",
179 | "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=",
180 | "dev": true
181 | },
182 | "browserify-zlib": {
183 | "version": "0.1.4",
184 | "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.1.4.tgz",
185 | "integrity": "sha1-uzX4pRn2AOD6a4SFJByXnQFB+y0=",
186 | "dev": true
187 | },
188 | "buffer": {
189 | "version": "4.9.1",
190 | "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz",
191 | "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=",
192 | "dev": true
193 | },
194 | "buffer-xor": {
195 | "version": "1.0.3",
196 | "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz",
197 | "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=",
198 | "dev": true
199 | },
200 | "builtin-modules": {
201 | "version": "1.1.1",
202 | "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz",
203 | "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=",
204 | "dev": true
205 | },
206 | "builtin-status-codes": {
207 | "version": "3.0.0",
208 | "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz",
209 | "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=",
210 | "dev": true
211 | },
212 | "camelcase": {
213 | "version": "1.2.1",
214 | "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz",
215 | "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk=",
216 | "dev": true
217 | },
218 | "center-align": {
219 | "version": "0.1.3",
220 | "resolved": "https://registry.npmjs.org/center-align/-/center-align-0.1.3.tgz",
221 | "integrity": "sha1-qg0yYptu6XIgBBHL1EYckHvCt60=",
222 | "dev": true
223 | },
224 | "chokidar": {
225 | "version": "1.7.0",
226 | "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz",
227 | "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=",
228 | "dev": true
229 | },
230 | "cipher-base": {
231 | "version": "1.0.3",
232 | "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.3.tgz",
233 | "integrity": "sha1-7qvxlEGc6QDaMBjCB9IS8qbfCgc=",
234 | "dev": true
235 | },
236 | "cliui": {
237 | "version": "2.1.0",
238 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-2.1.0.tgz",
239 | "integrity": "sha1-S0dXYP+AJkx2LDoXGQMukcf+oNE=",
240 | "dev": true
241 | },
242 | "co": {
243 | "version": "4.6.0",
244 | "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
245 | "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ=",
246 | "dev": true
247 | },
248 | "code-point-at": {
249 | "version": "1.1.0",
250 | "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
251 | "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
252 | "dev": true
253 | },
254 | "concat-map": {
255 | "version": "0.0.1",
256 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
257 | "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
258 | "dev": true
259 | },
260 | "console-browserify": {
261 | "version": "1.1.0",
262 | "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz",
263 | "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=",
264 | "dev": true
265 | },
266 | "constants-browserify": {
267 | "version": "1.0.0",
268 | "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz",
269 | "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=",
270 | "dev": true
271 | },
272 | "core-util-is": {
273 | "version": "1.0.2",
274 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
275 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=",
276 | "dev": true
277 | },
278 | "create-ecdh": {
279 | "version": "4.0.0",
280 | "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.0.tgz",
281 | "integrity": "sha1-iIxyNZbN92EvZJgjPuvXo1MBc30=",
282 | "dev": true
283 | },
284 | "create-hash": {
285 | "version": "1.1.3",
286 | "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.1.3.tgz",
287 | "integrity": "sha1-YGBCrIuSYnUPSDyt2rD1gZFy2P0=",
288 | "dev": true
289 | },
290 | "create-hmac": {
291 | "version": "1.1.6",
292 | "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.6.tgz",
293 | "integrity": "sha1-rLniIaThe9sHbpBlfEK5PjcmzwY=",
294 | "dev": true
295 | },
296 | "crypto-browserify": {
297 | "version": "3.11.0",
298 | "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.11.0.tgz",
299 | "integrity": "sha1-NlKgkGq5sqfgw85mpAjpV6JIVSI=",
300 | "dev": true
301 | },
302 | "d": {
303 | "version": "1.0.0",
304 | "resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz",
305 | "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=",
306 | "dev": true
307 | },
308 | "date-now": {
309 | "version": "0.1.4",
310 | "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz",
311 | "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=",
312 | "dev": true
313 | },
314 | "decamelize": {
315 | "version": "1.2.0",
316 | "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
317 | "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
318 | "dev": true
319 | },
320 | "des.js": {
321 | "version": "1.0.0",
322 | "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz",
323 | "integrity": "sha1-wHTS4qpqipoH29YfmhXCzYPsjsw=",
324 | "dev": true
325 | },
326 | "diffie-hellman": {
327 | "version": "5.0.2",
328 | "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.2.tgz",
329 | "integrity": "sha1-tYNXOScM/ias9jIJn97SoH8gnl4=",
330 | "dev": true
331 | },
332 | "domain-browser": {
333 | "version": "1.1.7",
334 | "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.1.7.tgz",
335 | "integrity": "sha1-hnqksJP6oF8d4IwG9NeyH9+GmLw=",
336 | "dev": true
337 | },
338 | "elliptic": {
339 | "version": "6.4.0",
340 | "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.4.0.tgz",
341 | "integrity": "sha1-ysmvh2LIWDYYcAPI3+GT5eLq5d8=",
342 | "dev": true
343 | },
344 | "emojis-list": {
345 | "version": "2.1.0",
346 | "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz",
347 | "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=",
348 | "dev": true
349 | },
350 | "enhanced-resolve": {
351 | "version": "3.3.0",
352 | "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-3.3.0.tgz",
353 | "integrity": "sha512-2qbxE7ek3YxPJ1ML6V+satHkzHpJQKWkRHmRx6mfAoW59yP8YH8BFplbegSP+u2hBd6B6KCOpvJQ3dZAP+hkpg==",
354 | "dev": true
355 | },
356 | "errno": {
357 | "version": "0.1.4",
358 | "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.4.tgz",
359 | "integrity": "sha1-uJbiOp5ei6M4cfyZar02NfyaHH0=",
360 | "dev": true
361 | },
362 | "error-ex": {
363 | "version": "1.3.1",
364 | "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz",
365 | "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=",
366 | "dev": true
367 | },
368 | "es5-ext": {
369 | "version": "0.10.23",
370 | "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.23.tgz",
371 | "integrity": "sha1-dXi1G+l0IHpUh4IbVlOMIk5Oezg=",
372 | "dev": true
373 | },
374 | "es6-iterator": {
375 | "version": "2.0.1",
376 | "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.1.tgz",
377 | "integrity": "sha1-jjGcnwRTv1ddN0lAplWSDlnKVRI=",
378 | "dev": true
379 | },
380 | "es6-map": {
381 | "version": "0.1.5",
382 | "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz",
383 | "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=",
384 | "dev": true
385 | },
386 | "es6-set": {
387 | "version": "0.1.5",
388 | "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz",
389 | "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=",
390 | "dev": true
391 | },
392 | "es6-symbol": {
393 | "version": "3.1.1",
394 | "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz",
395 | "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=",
396 | "dev": true
397 | },
398 | "es6-weak-map": {
399 | "version": "2.0.2",
400 | "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.2.tgz",
401 | "integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=",
402 | "dev": true
403 | },
404 | "escope": {
405 | "version": "3.6.0",
406 | "resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz",
407 | "integrity": "sha1-4Bl16BJ4GhY6ba392AOY3GTIicM=",
408 | "dev": true
409 | },
410 | "esrecurse": {
411 | "version": "4.2.0",
412 | "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.0.tgz",
413 | "integrity": "sha1-+pVo2Y04I/mkHZHpAtyrnqblsWM=",
414 | "dev": true
415 | },
416 | "estraverse": {
417 | "version": "4.2.0",
418 | "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz",
419 | "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=",
420 | "dev": true
421 | },
422 | "event-emitter": {
423 | "version": "0.3.5",
424 | "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz",
425 | "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=",
426 | "dev": true
427 | },
428 | "events": {
429 | "version": "1.1.1",
430 | "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz",
431 | "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=",
432 | "dev": true
433 | },
434 | "evp_bytestokey": {
435 | "version": "1.0.0",
436 | "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.0.tgz",
437 | "integrity": "sha1-SXtmrZ/vZc18CKYYCCS6FHa2blM=",
438 | "dev": true
439 | },
440 | "expand-brackets": {
441 | "version": "0.1.5",
442 | "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz",
443 | "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=",
444 | "dev": true
445 | },
446 | "expand-range": {
447 | "version": "1.8.2",
448 | "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz",
449 | "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=",
450 | "dev": true
451 | },
452 | "extglob": {
453 | "version": "0.3.2",
454 | "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz",
455 | "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=",
456 | "dev": true
457 | },
458 | "fast-deep-equal": {
459 | "version": "0.1.0",
460 | "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-0.1.0.tgz",
461 | "integrity": "sha1-XG9FmaumszPuM0Li7ZeGcvEAH40=",
462 | "dev": true
463 | },
464 | "filename-regex": {
465 | "version": "2.0.1",
466 | "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz",
467 | "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY=",
468 | "dev": true
469 | },
470 | "fill-range": {
471 | "version": "2.2.3",
472 | "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz",
473 | "integrity": "sha1-ULd9/X5Gm8dJJHCWNpn+eoSFpyM=",
474 | "dev": true
475 | },
476 | "find-up": {
477 | "version": "1.1.2",
478 | "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz",
479 | "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=",
480 | "dev": true
481 | },
482 | "for-in": {
483 | "version": "1.0.2",
484 | "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
485 | "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=",
486 | "dev": true
487 | },
488 | "for-own": {
489 | "version": "0.1.5",
490 | "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz",
491 | "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=",
492 | "dev": true
493 | },
494 | "fsevents": {
495 | "version": "1.1.2",
496 | "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.1.2.tgz",
497 | "integrity": "sha512-Sn44E5wQW4bTHXvQmvSHwqbuiXtduD6Rrjm2ZtUEGbyrig+nUH3t/QD4M4/ZXViY556TBpRgZkHLDx3JxPwxiw==",
498 | "dev": true,
499 | "optional": true,
500 | "dependencies": {
501 | "abbrev": {
502 | "version": "1.1.0",
503 | "bundled": true,
504 | "dev": true,
505 | "optional": true
506 | },
507 | "ajv": {
508 | "version": "4.11.8",
509 | "bundled": true,
510 | "dev": true,
511 | "optional": true
512 | },
513 | "ansi-regex": {
514 | "version": "2.1.1",
515 | "bundled": true,
516 | "dev": true
517 | },
518 | "aproba": {
519 | "version": "1.1.1",
520 | "bundled": true,
521 | "dev": true,
522 | "optional": true
523 | },
524 | "are-we-there-yet": {
525 | "version": "1.1.4",
526 | "bundled": true,
527 | "dev": true,
528 | "optional": true
529 | },
530 | "asn1": {
531 | "version": "0.2.3",
532 | "bundled": true,
533 | "dev": true,
534 | "optional": true
535 | },
536 | "assert-plus": {
537 | "version": "0.2.0",
538 | "bundled": true,
539 | "dev": true,
540 | "optional": true
541 | },
542 | "asynckit": {
543 | "version": "0.4.0",
544 | "bundled": true,
545 | "dev": true,
546 | "optional": true
547 | },
548 | "aws-sign2": {
549 | "version": "0.6.0",
550 | "bundled": true,
551 | "dev": true,
552 | "optional": true
553 | },
554 | "aws4": {
555 | "version": "1.6.0",
556 | "bundled": true,
557 | "dev": true,
558 | "optional": true
559 | },
560 | "balanced-match": {
561 | "version": "0.4.2",
562 | "bundled": true,
563 | "dev": true
564 | },
565 | "bcrypt-pbkdf": {
566 | "version": "1.0.1",
567 | "bundled": true,
568 | "dev": true,
569 | "optional": true
570 | },
571 | "block-stream": {
572 | "version": "0.0.9",
573 | "bundled": true,
574 | "dev": true
575 | },
576 | "boom": {
577 | "version": "2.10.1",
578 | "bundled": true,
579 | "dev": true
580 | },
581 | "brace-expansion": {
582 | "version": "1.1.7",
583 | "bundled": true,
584 | "dev": true
585 | },
586 | "buffer-shims": {
587 | "version": "1.0.0",
588 | "bundled": true,
589 | "dev": true
590 | },
591 | "caseless": {
592 | "version": "0.12.0",
593 | "bundled": true,
594 | "dev": true,
595 | "optional": true
596 | },
597 | "co": {
598 | "version": "4.6.0",
599 | "bundled": true,
600 | "dev": true,
601 | "optional": true
602 | },
603 | "code-point-at": {
604 | "version": "1.1.0",
605 | "bundled": true,
606 | "dev": true
607 | },
608 | "combined-stream": {
609 | "version": "1.0.5",
610 | "bundled": true,
611 | "dev": true
612 | },
613 | "concat-map": {
614 | "version": "0.0.1",
615 | "bundled": true,
616 | "dev": true
617 | },
618 | "console-control-strings": {
619 | "version": "1.1.0",
620 | "bundled": true,
621 | "dev": true
622 | },
623 | "core-util-is": {
624 | "version": "1.0.2",
625 | "bundled": true,
626 | "dev": true
627 | },
628 | "cryptiles": {
629 | "version": "2.0.5",
630 | "bundled": true,
631 | "dev": true,
632 | "optional": true
633 | },
634 | "dashdash": {
635 | "version": "1.14.1",
636 | "bundled": true,
637 | "dev": true,
638 | "optional": true,
639 | "dependencies": {
640 | "assert-plus": {
641 | "version": "1.0.0",
642 | "bundled": true,
643 | "dev": true,
644 | "optional": true
645 | }
646 | }
647 | },
648 | "debug": {
649 | "version": "2.6.8",
650 | "bundled": true,
651 | "dev": true,
652 | "optional": true
653 | },
654 | "deep-extend": {
655 | "version": "0.4.2",
656 | "bundled": true,
657 | "dev": true,
658 | "optional": true
659 | },
660 | "delayed-stream": {
661 | "version": "1.0.0",
662 | "bundled": true,
663 | "dev": true
664 | },
665 | "delegates": {
666 | "version": "1.0.0",
667 | "bundled": true,
668 | "dev": true,
669 | "optional": true
670 | },
671 | "ecc-jsbn": {
672 | "version": "0.1.1",
673 | "bundled": true,
674 | "dev": true,
675 | "optional": true
676 | },
677 | "extend": {
678 | "version": "3.0.1",
679 | "bundled": true,
680 | "dev": true,
681 | "optional": true
682 | },
683 | "extsprintf": {
684 | "version": "1.0.2",
685 | "bundled": true,
686 | "dev": true
687 | },
688 | "forever-agent": {
689 | "version": "0.6.1",
690 | "bundled": true,
691 | "dev": true,
692 | "optional": true
693 | },
694 | "form-data": {
695 | "version": "2.1.4",
696 | "bundled": true,
697 | "dev": true,
698 | "optional": true
699 | },
700 | "fs.realpath": {
701 | "version": "1.0.0",
702 | "bundled": true,
703 | "dev": true
704 | },
705 | "fstream": {
706 | "version": "1.0.11",
707 | "bundled": true,
708 | "dev": true
709 | },
710 | "fstream-ignore": {
711 | "version": "1.0.5",
712 | "bundled": true,
713 | "dev": true,
714 | "optional": true
715 | },
716 | "gauge": {
717 | "version": "2.7.4",
718 | "bundled": true,
719 | "dev": true,
720 | "optional": true
721 | },
722 | "getpass": {
723 | "version": "0.1.7",
724 | "bundled": true,
725 | "dev": true,
726 | "optional": true,
727 | "dependencies": {
728 | "assert-plus": {
729 | "version": "1.0.0",
730 | "bundled": true,
731 | "dev": true,
732 | "optional": true
733 | }
734 | }
735 | },
736 | "glob": {
737 | "version": "7.1.2",
738 | "bundled": true,
739 | "dev": true
740 | },
741 | "graceful-fs": {
742 | "version": "4.1.11",
743 | "bundled": true,
744 | "dev": true
745 | },
746 | "har-schema": {
747 | "version": "1.0.5",
748 | "bundled": true,
749 | "dev": true,
750 | "optional": true
751 | },
752 | "har-validator": {
753 | "version": "4.2.1",
754 | "bundled": true,
755 | "dev": true,
756 | "optional": true
757 | },
758 | "has-unicode": {
759 | "version": "2.0.1",
760 | "bundled": true,
761 | "dev": true,
762 | "optional": true
763 | },
764 | "hawk": {
765 | "version": "3.1.3",
766 | "bundled": true,
767 | "dev": true,
768 | "optional": true
769 | },
770 | "hoek": {
771 | "version": "2.16.3",
772 | "bundled": true,
773 | "dev": true
774 | },
775 | "http-signature": {
776 | "version": "1.1.1",
777 | "bundled": true,
778 | "dev": true,
779 | "optional": true
780 | },
781 | "inflight": {
782 | "version": "1.0.6",
783 | "bundled": true,
784 | "dev": true
785 | },
786 | "inherits": {
787 | "version": "2.0.3",
788 | "bundled": true,
789 | "dev": true
790 | },
791 | "ini": {
792 | "version": "1.3.4",
793 | "bundled": true,
794 | "dev": true,
795 | "optional": true
796 | },
797 | "is-fullwidth-code-point": {
798 | "version": "1.0.0",
799 | "bundled": true,
800 | "dev": true
801 | },
802 | "is-typedarray": {
803 | "version": "1.0.0",
804 | "bundled": true,
805 | "dev": true,
806 | "optional": true
807 | },
808 | "isarray": {
809 | "version": "1.0.0",
810 | "bundled": true,
811 | "dev": true
812 | },
813 | "isstream": {
814 | "version": "0.1.2",
815 | "bundled": true,
816 | "dev": true,
817 | "optional": true
818 | },
819 | "jodid25519": {
820 | "version": "1.0.2",
821 | "bundled": true,
822 | "dev": true,
823 | "optional": true
824 | },
825 | "jsbn": {
826 | "version": "0.1.1",
827 | "bundled": true,
828 | "dev": true,
829 | "optional": true
830 | },
831 | "json-schema": {
832 | "version": "0.2.3",
833 | "bundled": true,
834 | "dev": true,
835 | "optional": true
836 | },
837 | "json-stable-stringify": {
838 | "version": "1.0.1",
839 | "bundled": true,
840 | "dev": true,
841 | "optional": true
842 | },
843 | "json-stringify-safe": {
844 | "version": "5.0.1",
845 | "bundled": true,
846 | "dev": true,
847 | "optional": true
848 | },
849 | "jsonify": {
850 | "version": "0.0.0",
851 | "bundled": true,
852 | "dev": true,
853 | "optional": true
854 | },
855 | "jsprim": {
856 | "version": "1.4.0",
857 | "bundled": true,
858 | "dev": true,
859 | "optional": true,
860 | "dependencies": {
861 | "assert-plus": {
862 | "version": "1.0.0",
863 | "bundled": true,
864 | "dev": true,
865 | "optional": true
866 | }
867 | }
868 | },
869 | "mime-db": {
870 | "version": "1.27.0",
871 | "bundled": true,
872 | "dev": true
873 | },
874 | "mime-types": {
875 | "version": "2.1.15",
876 | "bundled": true,
877 | "dev": true
878 | },
879 | "minimatch": {
880 | "version": "3.0.4",
881 | "bundled": true,
882 | "dev": true
883 | },
884 | "minimist": {
885 | "version": "0.0.8",
886 | "bundled": true,
887 | "dev": true
888 | },
889 | "mkdirp": {
890 | "version": "0.5.1",
891 | "bundled": true,
892 | "dev": true
893 | },
894 | "ms": {
895 | "version": "2.0.0",
896 | "bundled": true,
897 | "dev": true,
898 | "optional": true
899 | },
900 | "node-pre-gyp": {
901 | "version": "0.6.36",
902 | "bundled": true,
903 | "dev": true,
904 | "optional": true
905 | },
906 | "nopt": {
907 | "version": "4.0.1",
908 | "bundled": true,
909 | "dev": true,
910 | "optional": true
911 | },
912 | "npmlog": {
913 | "version": "4.1.0",
914 | "bundled": true,
915 | "dev": true,
916 | "optional": true
917 | },
918 | "number-is-nan": {
919 | "version": "1.0.1",
920 | "bundled": true,
921 | "dev": true
922 | },
923 | "oauth-sign": {
924 | "version": "0.8.2",
925 | "bundled": true,
926 | "dev": true,
927 | "optional": true
928 | },
929 | "object-assign": {
930 | "version": "4.1.1",
931 | "bundled": true,
932 | "dev": true,
933 | "optional": true
934 | },
935 | "once": {
936 | "version": "1.4.0",
937 | "bundled": true,
938 | "dev": true
939 | },
940 | "os-homedir": {
941 | "version": "1.0.2",
942 | "bundled": true,
943 | "dev": true,
944 | "optional": true
945 | },
946 | "os-tmpdir": {
947 | "version": "1.0.2",
948 | "bundled": true,
949 | "dev": true,
950 | "optional": true
951 | },
952 | "osenv": {
953 | "version": "0.1.4",
954 | "bundled": true,
955 | "dev": true,
956 | "optional": true
957 | },
958 | "path-is-absolute": {
959 | "version": "1.0.1",
960 | "bundled": true,
961 | "dev": true
962 | },
963 | "performance-now": {
964 | "version": "0.2.0",
965 | "bundled": true,
966 | "dev": true,
967 | "optional": true
968 | },
969 | "process-nextick-args": {
970 | "version": "1.0.7",
971 | "bundled": true,
972 | "dev": true
973 | },
974 | "punycode": {
975 | "version": "1.4.1",
976 | "bundled": true,
977 | "dev": true,
978 | "optional": true
979 | },
980 | "qs": {
981 | "version": "6.4.0",
982 | "bundled": true,
983 | "dev": true,
984 | "optional": true
985 | },
986 | "rc": {
987 | "version": "1.2.1",
988 | "bundled": true,
989 | "dev": true,
990 | "optional": true,
991 | "dependencies": {
992 | "minimist": {
993 | "version": "1.2.0",
994 | "bundled": true,
995 | "dev": true,
996 | "optional": true
997 | }
998 | }
999 | },
1000 | "readable-stream": {
1001 | "version": "2.2.9",
1002 | "bundled": true,
1003 | "dev": true
1004 | },
1005 | "request": {
1006 | "version": "2.81.0",
1007 | "bundled": true,
1008 | "dev": true,
1009 | "optional": true
1010 | },
1011 | "rimraf": {
1012 | "version": "2.6.1",
1013 | "bundled": true,
1014 | "dev": true
1015 | },
1016 | "safe-buffer": {
1017 | "version": "5.0.1",
1018 | "bundled": true,
1019 | "dev": true
1020 | },
1021 | "semver": {
1022 | "version": "5.3.0",
1023 | "bundled": true,
1024 | "dev": true,
1025 | "optional": true
1026 | },
1027 | "set-blocking": {
1028 | "version": "2.0.0",
1029 | "bundled": true,
1030 | "dev": true,
1031 | "optional": true
1032 | },
1033 | "signal-exit": {
1034 | "version": "3.0.2",
1035 | "bundled": true,
1036 | "dev": true,
1037 | "optional": true
1038 | },
1039 | "sntp": {
1040 | "version": "1.0.9",
1041 | "bundled": true,
1042 | "dev": true,
1043 | "optional": true
1044 | },
1045 | "sshpk": {
1046 | "version": "1.13.0",
1047 | "bundled": true,
1048 | "dev": true,
1049 | "optional": true,
1050 | "dependencies": {
1051 | "assert-plus": {
1052 | "version": "1.0.0",
1053 | "bundled": true,
1054 | "dev": true,
1055 | "optional": true
1056 | }
1057 | }
1058 | },
1059 | "string_decoder": {
1060 | "version": "1.0.1",
1061 | "bundled": true,
1062 | "dev": true
1063 | },
1064 | "string-width": {
1065 | "version": "1.0.2",
1066 | "bundled": true,
1067 | "dev": true
1068 | },
1069 | "stringstream": {
1070 | "version": "0.0.5",
1071 | "bundled": true,
1072 | "dev": true,
1073 | "optional": true
1074 | },
1075 | "strip-ansi": {
1076 | "version": "3.0.1",
1077 | "bundled": true,
1078 | "dev": true
1079 | },
1080 | "strip-json-comments": {
1081 | "version": "2.0.1",
1082 | "bundled": true,
1083 | "dev": true,
1084 | "optional": true
1085 | },
1086 | "tar": {
1087 | "version": "2.2.1",
1088 | "bundled": true,
1089 | "dev": true
1090 | },
1091 | "tar-pack": {
1092 | "version": "3.4.0",
1093 | "bundled": true,
1094 | "dev": true,
1095 | "optional": true
1096 | },
1097 | "tough-cookie": {
1098 | "version": "2.3.2",
1099 | "bundled": true,
1100 | "dev": true,
1101 | "optional": true
1102 | },
1103 | "tunnel-agent": {
1104 | "version": "0.6.0",
1105 | "bundled": true,
1106 | "dev": true,
1107 | "optional": true
1108 | },
1109 | "tweetnacl": {
1110 | "version": "0.14.5",
1111 | "bundled": true,
1112 | "dev": true,
1113 | "optional": true
1114 | },
1115 | "uid-number": {
1116 | "version": "0.0.6",
1117 | "bundled": true,
1118 | "dev": true,
1119 | "optional": true
1120 | },
1121 | "util-deprecate": {
1122 | "version": "1.0.2",
1123 | "bundled": true,
1124 | "dev": true
1125 | },
1126 | "uuid": {
1127 | "version": "3.0.1",
1128 | "bundled": true,
1129 | "dev": true,
1130 | "optional": true
1131 | },
1132 | "verror": {
1133 | "version": "1.3.6",
1134 | "bundled": true,
1135 | "dev": true,
1136 | "optional": true
1137 | },
1138 | "wide-align": {
1139 | "version": "1.1.2",
1140 | "bundled": true,
1141 | "dev": true,
1142 | "optional": true
1143 | },
1144 | "wrappy": {
1145 | "version": "1.0.2",
1146 | "bundled": true,
1147 | "dev": true
1148 | }
1149 | }
1150 | },
1151 | "get-caller-file": {
1152 | "version": "1.0.2",
1153 | "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.2.tgz",
1154 | "integrity": "sha1-9wLmMSfn4jHBYKgMFVSstw1QR+U=",
1155 | "dev": true
1156 | },
1157 | "glob-base": {
1158 | "version": "0.3.0",
1159 | "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz",
1160 | "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=",
1161 | "dev": true
1162 | },
1163 | "glob-parent": {
1164 | "version": "2.0.0",
1165 | "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz",
1166 | "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=",
1167 | "dev": true
1168 | },
1169 | "graceful-fs": {
1170 | "version": "4.1.11",
1171 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
1172 | "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg=",
1173 | "dev": true
1174 | },
1175 | "has-flag": {
1176 | "version": "1.0.0",
1177 | "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz",
1178 | "integrity": "sha1-nZ55MWXOAXoA8AQYxD+UKnsdEfo=",
1179 | "dev": true
1180 | },
1181 | "hash-base": {
1182 | "version": "2.0.2",
1183 | "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-2.0.2.tgz",
1184 | "integrity": "sha1-ZuodhW206KVHDK32/OI65SRO8uE=",
1185 | "dev": true
1186 | },
1187 | "hash.js": {
1188 | "version": "1.1.3",
1189 | "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.3.tgz",
1190 | "integrity": "sha512-/UETyP0W22QILqS+6HowevwhEFJ3MBJnwTf75Qob9Wz9t0DPuisL8kW8YZMK62dHAKE1c1p+gY1TtOLY+USEHA==",
1191 | "dev": true
1192 | },
1193 | "hmac-drbg": {
1194 | "version": "1.0.1",
1195 | "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
1196 | "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=",
1197 | "dev": true
1198 | },
1199 | "hosted-git-info": {
1200 | "version": "2.5.0",
1201 | "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz",
1202 | "integrity": "sha512-pNgbURSuab90KbTqvRPsseaTxOJCZBD0a7t+haSN33piP9cCM4l0CqdzAif2hUqm716UovKB2ROmiabGAKVXyg==",
1203 | "dev": true
1204 | },
1205 | "https-browserify": {
1206 | "version": "0.0.1",
1207 | "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-0.0.1.tgz",
1208 | "integrity": "sha1-P5E2XKvmC3ftDruiS0VOPgnZWoI=",
1209 | "dev": true
1210 | },
1211 | "ieee754": {
1212 | "version": "1.1.8",
1213 | "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.8.tgz",
1214 | "integrity": "sha1-vjPUCsEO8ZJnAfbwii2G+/0a0+Q=",
1215 | "dev": true
1216 | },
1217 | "indexof": {
1218 | "version": "0.0.1",
1219 | "resolved": "https://registry.npmjs.org/indexof/-/indexof-0.0.1.tgz",
1220 | "integrity": "sha1-gtwzbSMrkGIXnQWrMpOmYFn9Q10=",
1221 | "dev": true
1222 | },
1223 | "inherits": {
1224 | "version": "2.0.3",
1225 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
1226 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=",
1227 | "dev": true
1228 | },
1229 | "interpret": {
1230 | "version": "1.0.3",
1231 | "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.0.3.tgz",
1232 | "integrity": "sha1-y8NcYu7uc/Gat7EKgBURQBr8D5A=",
1233 | "dev": true
1234 | },
1235 | "invert-kv": {
1236 | "version": "1.0.0",
1237 | "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz",
1238 | "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=",
1239 | "dev": true
1240 | },
1241 | "is-arrayish": {
1242 | "version": "0.2.1",
1243 | "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
1244 | "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=",
1245 | "dev": true
1246 | },
1247 | "is-binary-path": {
1248 | "version": "1.0.1",
1249 | "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz",
1250 | "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=",
1251 | "dev": true
1252 | },
1253 | "is-buffer": {
1254 | "version": "1.1.5",
1255 | "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.5.tgz",
1256 | "integrity": "sha1-Hzsm72E7IUuIy8ojzGwB2Hlh7sw=",
1257 | "dev": true
1258 | },
1259 | "is-builtin-module": {
1260 | "version": "1.0.0",
1261 | "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz",
1262 | "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=",
1263 | "dev": true
1264 | },
1265 | "is-dotfile": {
1266 | "version": "1.0.3",
1267 | "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz",
1268 | "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE=",
1269 | "dev": true
1270 | },
1271 | "is-equal-shallow": {
1272 | "version": "0.1.3",
1273 | "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz",
1274 | "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=",
1275 | "dev": true
1276 | },
1277 | "is-extendable": {
1278 | "version": "0.1.1",
1279 | "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
1280 | "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=",
1281 | "dev": true
1282 | },
1283 | "is-extglob": {
1284 | "version": "1.0.0",
1285 | "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
1286 | "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA=",
1287 | "dev": true
1288 | },
1289 | "is-fullwidth-code-point": {
1290 | "version": "1.0.0",
1291 | "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
1292 | "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
1293 | "dev": true
1294 | },
1295 | "is-glob": {
1296 | "version": "2.0.1",
1297 | "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
1298 | "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
1299 | "dev": true
1300 | },
1301 | "is-number": {
1302 | "version": "2.1.0",
1303 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz",
1304 | "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=",
1305 | "dev": true
1306 | },
1307 | "is-posix-bracket": {
1308 | "version": "0.1.1",
1309 | "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz",
1310 | "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q=",
1311 | "dev": true
1312 | },
1313 | "is-primitive": {
1314 | "version": "2.0.0",
1315 | "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz",
1316 | "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU=",
1317 | "dev": true
1318 | },
1319 | "is-utf8": {
1320 | "version": "0.2.1",
1321 | "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
1322 | "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=",
1323 | "dev": true
1324 | },
1325 | "isarray": {
1326 | "version": "1.0.0",
1327 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
1328 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
1329 | "dev": true
1330 | },
1331 | "isobject": {
1332 | "version": "2.1.0",
1333 | "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
1334 | "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
1335 | "dev": true
1336 | },
1337 | "json-loader": {
1338 | "version": "0.5.4",
1339 | "resolved": "https://registry.npmjs.org/json-loader/-/json-loader-0.5.4.tgz",
1340 | "integrity": "sha1-i6oTZaYy9Yo8RtIBdfxgAsluN94=",
1341 | "dev": true
1342 | },
1343 | "json-schema-traverse": {
1344 | "version": "0.3.1",
1345 | "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz",
1346 | "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A=",
1347 | "dev": true
1348 | },
1349 | "json-stable-stringify": {
1350 | "version": "1.0.1",
1351 | "resolved": "https://registry.npmjs.org/json-stable-stringify/-/json-stable-stringify-1.0.1.tgz",
1352 | "integrity": "sha1-mnWdOcXy/1A/1TAGRu1EX4jE+a8=",
1353 | "dev": true
1354 | },
1355 | "json5": {
1356 | "version": "0.5.1",
1357 | "resolved": "https://registry.npmjs.org/json5/-/json5-0.5.1.tgz",
1358 | "integrity": "sha1-Hq3nrMASA0rYTiOWdn6tn6VJWCE=",
1359 | "dev": true
1360 | },
1361 | "jsonify": {
1362 | "version": "0.0.0",
1363 | "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz",
1364 | "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=",
1365 | "dev": true
1366 | },
1367 | "kind-of": {
1368 | "version": "3.2.2",
1369 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
1370 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
1371 | "dev": true
1372 | },
1373 | "lazy-cache": {
1374 | "version": "1.0.4",
1375 | "resolved": "https://registry.npmjs.org/lazy-cache/-/lazy-cache-1.0.4.tgz",
1376 | "integrity": "sha1-odePw6UEdMuAhF07O24dpJpEbo4=",
1377 | "dev": true
1378 | },
1379 | "lcid": {
1380 | "version": "1.0.0",
1381 | "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz",
1382 | "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=",
1383 | "dev": true
1384 | },
1385 | "load-json-file": {
1386 | "version": "1.1.0",
1387 | "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
1388 | "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
1389 | "dev": true
1390 | },
1391 | "loader-runner": {
1392 | "version": "2.3.0",
1393 | "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.3.0.tgz",
1394 | "integrity": "sha1-9IKuqC1UPgeSFwDVpG7yb9rGuKI=",
1395 | "dev": true
1396 | },
1397 | "loader-utils": {
1398 | "version": "1.1.0",
1399 | "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.1.0.tgz",
1400 | "integrity": "sha1-yYrvSIvM7aL/teLeZG1qdUQp9c0=",
1401 | "dev": true
1402 | },
1403 | "lodash": {
1404 | "version": "4.17.4",
1405 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz",
1406 | "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4="
1407 | },
1408 | "longest": {
1409 | "version": "1.0.1",
1410 | "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz",
1411 | "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=",
1412 | "dev": true
1413 | },
1414 | "memory-fs": {
1415 | "version": "0.4.1",
1416 | "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz",
1417 | "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=",
1418 | "dev": true
1419 | },
1420 | "micromatch": {
1421 | "version": "2.3.11",
1422 | "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz",
1423 | "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=",
1424 | "dev": true
1425 | },
1426 | "miller-rabin": {
1427 | "version": "4.0.0",
1428 | "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.0.tgz",
1429 | "integrity": "sha1-SmL7HUKTPAVYOYL0xxb2+55sbT0=",
1430 | "dev": true
1431 | },
1432 | "minimalistic-assert": {
1433 | "version": "1.0.0",
1434 | "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.0.tgz",
1435 | "integrity": "sha1-cCvi3aazf0g2vLP121ZkG2Sh09M=",
1436 | "dev": true
1437 | },
1438 | "minimalistic-crypto-utils": {
1439 | "version": "1.0.1",
1440 | "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz",
1441 | "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=",
1442 | "dev": true
1443 | },
1444 | "minimatch": {
1445 | "version": "3.0.4",
1446 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
1447 | "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
1448 | "dev": true
1449 | },
1450 | "minimist": {
1451 | "version": "0.0.8",
1452 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
1453 | "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=",
1454 | "dev": true
1455 | },
1456 | "mkdirp": {
1457 | "version": "0.5.1",
1458 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
1459 | "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
1460 | "dev": true
1461 | },
1462 | "nan": {
1463 | "version": "2.6.2",
1464 | "resolved": "https://registry.npmjs.org/nan/-/nan-2.6.2.tgz",
1465 | "integrity": "sha1-5P805slf37WuzAjeZZb0NgWn20U=",
1466 | "dev": true,
1467 | "optional": true
1468 | },
1469 | "node-libs-browser": {
1470 | "version": "2.0.0",
1471 | "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.0.0.tgz",
1472 | "integrity": "sha1-o6WeyXAkmFtG6Vg3lkb5bEthZkY=",
1473 | "dev": true,
1474 | "dependencies": {
1475 | "string_decoder": {
1476 | "version": "0.10.31",
1477 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
1478 | "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=",
1479 | "dev": true
1480 | }
1481 | }
1482 | },
1483 | "normalize-package-data": {
1484 | "version": "2.4.0",
1485 | "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz",
1486 | "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==",
1487 | "dev": true
1488 | },
1489 | "normalize-path": {
1490 | "version": "2.1.1",
1491 | "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
1492 | "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
1493 | "dev": true
1494 | },
1495 | "number-is-nan": {
1496 | "version": "1.0.1",
1497 | "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
1498 | "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=",
1499 | "dev": true
1500 | },
1501 | "object-assign": {
1502 | "version": "4.1.1",
1503 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
1504 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
1505 | "dev": true
1506 | },
1507 | "object.omit": {
1508 | "version": "2.0.1",
1509 | "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz",
1510 | "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=",
1511 | "dev": true
1512 | },
1513 | "os-browserify": {
1514 | "version": "0.2.1",
1515 | "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.2.1.tgz",
1516 | "integrity": "sha1-Y/xMzuXS13Y9Jrv4YBB45sLgBE8=",
1517 | "dev": true
1518 | },
1519 | "os-locale": {
1520 | "version": "1.4.0",
1521 | "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
1522 | "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=",
1523 | "dev": true
1524 | },
1525 | "pako": {
1526 | "version": "0.2.9",
1527 | "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz",
1528 | "integrity": "sha1-8/dSL073gjSNqBYbrZ7P1Rv4OnU=",
1529 | "dev": true
1530 | },
1531 | "parse-asn1": {
1532 | "version": "5.1.0",
1533 | "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.0.tgz",
1534 | "integrity": "sha1-N8T5t+06tlx0gXtfJICTf7+XxxI=",
1535 | "dev": true
1536 | },
1537 | "parse-glob": {
1538 | "version": "3.0.4",
1539 | "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz",
1540 | "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=",
1541 | "dev": true
1542 | },
1543 | "parse-json": {
1544 | "version": "2.2.0",
1545 | "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
1546 | "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=",
1547 | "dev": true
1548 | },
1549 | "path-browserify": {
1550 | "version": "0.0.0",
1551 | "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.0.tgz",
1552 | "integrity": "sha1-oLhwcpquIUAFt9UDLsLLuw+0RRo=",
1553 | "dev": true
1554 | },
1555 | "path-exists": {
1556 | "version": "2.1.0",
1557 | "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz",
1558 | "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=",
1559 | "dev": true
1560 | },
1561 | "path-is-absolute": {
1562 | "version": "1.0.1",
1563 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
1564 | "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
1565 | "dev": true
1566 | },
1567 | "path-type": {
1568 | "version": "1.1.0",
1569 | "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz",
1570 | "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=",
1571 | "dev": true
1572 | },
1573 | "pbkdf2": {
1574 | "version": "3.0.12",
1575 | "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.12.tgz",
1576 | "integrity": "sha1-vjZ4XFBn6kjYBv+SMojF91C2uKI=",
1577 | "dev": true
1578 | },
1579 | "pify": {
1580 | "version": "2.3.0",
1581 | "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
1582 | "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=",
1583 | "dev": true
1584 | },
1585 | "pinkie": {
1586 | "version": "2.0.4",
1587 | "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
1588 | "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=",
1589 | "dev": true
1590 | },
1591 | "pinkie-promise": {
1592 | "version": "2.0.1",
1593 | "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
1594 | "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
1595 | "dev": true
1596 | },
1597 | "preserve": {
1598 | "version": "0.2.0",
1599 | "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz",
1600 | "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks=",
1601 | "dev": true
1602 | },
1603 | "process": {
1604 | "version": "0.11.10",
1605 | "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
1606 | "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=",
1607 | "dev": true
1608 | },
1609 | "process-nextick-args": {
1610 | "version": "1.0.7",
1611 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz",
1612 | "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=",
1613 | "dev": true
1614 | },
1615 | "prr": {
1616 | "version": "0.0.0",
1617 | "resolved": "https://registry.npmjs.org/prr/-/prr-0.0.0.tgz",
1618 | "integrity": "sha1-GoS4WQgyVQFBGFPQCB7j+obikmo=",
1619 | "dev": true
1620 | },
1621 | "public-encrypt": {
1622 | "version": "4.0.0",
1623 | "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.0.tgz",
1624 | "integrity": "sha1-OfaZ86RlYN1eusvKaTyvfGXBjMY=",
1625 | "dev": true
1626 | },
1627 | "punycode": {
1628 | "version": "1.4.1",
1629 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
1630 | "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=",
1631 | "dev": true
1632 | },
1633 | "querystring": {
1634 | "version": "0.2.0",
1635 | "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz",
1636 | "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=",
1637 | "dev": true
1638 | },
1639 | "querystring-es3": {
1640 | "version": "0.2.1",
1641 | "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz",
1642 | "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=",
1643 | "dev": true
1644 | },
1645 | "randomatic": {
1646 | "version": "1.1.7",
1647 | "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz",
1648 | "integrity": "sha512-D5JUjPyJbaJDkuAazpVnSfVkLlpeO3wDlPROTMLGKG1zMFNFRgrciKo1ltz/AzNTkqE0HzDx655QOL51N06how==",
1649 | "dev": true,
1650 | "dependencies": {
1651 | "is-number": {
1652 | "version": "3.0.0",
1653 | "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
1654 | "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
1655 | "dev": true,
1656 | "dependencies": {
1657 | "kind-of": {
1658 | "version": "3.2.2",
1659 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
1660 | "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
1661 | "dev": true
1662 | }
1663 | }
1664 | },
1665 | "kind-of": {
1666 | "version": "4.0.0",
1667 | "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz",
1668 | "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=",
1669 | "dev": true
1670 | }
1671 | }
1672 | },
1673 | "randombytes": {
1674 | "version": "2.0.5",
1675 | "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.0.5.tgz",
1676 | "integrity": "sha512-8T7Zn1AhMsQ/HI1SjcCfT/t4ii3eAqco3yOcSzS4mozsOz69lHLsoMXmF9nZgnFanYscnSlUSgs8uZyKzpE6kg==",
1677 | "dev": true
1678 | },
1679 | "read-pkg": {
1680 | "version": "1.1.0",
1681 | "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
1682 | "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=",
1683 | "dev": true
1684 | },
1685 | "read-pkg-up": {
1686 | "version": "1.0.1",
1687 | "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz",
1688 | "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=",
1689 | "dev": true
1690 | },
1691 | "readable-stream": {
1692 | "version": "2.3.3",
1693 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz",
1694 | "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==",
1695 | "dev": true
1696 | },
1697 | "readdirp": {
1698 | "version": "2.1.0",
1699 | "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.1.0.tgz",
1700 | "integrity": "sha1-TtCtBg3zBzMAxIRANz9y0cxkLXg=",
1701 | "dev": true
1702 | },
1703 | "regex-cache": {
1704 | "version": "0.4.3",
1705 | "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.3.tgz",
1706 | "integrity": "sha1-mxpsNdTQ3871cRrmUejp09cRQUU=",
1707 | "dev": true
1708 | },
1709 | "remove-trailing-separator": {
1710 | "version": "1.0.2",
1711 | "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.0.2.tgz",
1712 | "integrity": "sha1-abBi2XhyetFNxrVrpKt3L9jXBRE=",
1713 | "dev": true
1714 | },
1715 | "repeat-element": {
1716 | "version": "1.1.2",
1717 | "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz",
1718 | "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo=",
1719 | "dev": true
1720 | },
1721 | "repeat-string": {
1722 | "version": "1.6.1",
1723 | "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
1724 | "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=",
1725 | "dev": true
1726 | },
1727 | "require-directory": {
1728 | "version": "2.1.1",
1729 | "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
1730 | "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=",
1731 | "dev": true
1732 | },
1733 | "require-main-filename": {
1734 | "version": "1.0.1",
1735 | "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz",
1736 | "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=",
1737 | "dev": true
1738 | },
1739 | "right-align": {
1740 | "version": "0.1.3",
1741 | "resolved": "https://registry.npmjs.org/right-align/-/right-align-0.1.3.tgz",
1742 | "integrity": "sha1-YTObci/mo1FWiSENJOFMlhSGE+8=",
1743 | "dev": true
1744 | },
1745 | "ripemd160": {
1746 | "version": "2.0.1",
1747 | "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.1.tgz",
1748 | "integrity": "sha1-D0WEKVxTo2KK9+bXmsohzlfRxuc=",
1749 | "dev": true
1750 | },
1751 | "safe-buffer": {
1752 | "version": "5.1.1",
1753 | "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
1754 | "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg==",
1755 | "dev": true
1756 | },
1757 | "semver": {
1758 | "version": "5.3.0",
1759 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz",
1760 | "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=",
1761 | "dev": true
1762 | },
1763 | "set-blocking": {
1764 | "version": "2.0.0",
1765 | "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
1766 | "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
1767 | "dev": true
1768 | },
1769 | "set-immediate-shim": {
1770 | "version": "1.0.1",
1771 | "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz",
1772 | "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E=",
1773 | "dev": true
1774 | },
1775 | "setimmediate": {
1776 | "version": "1.0.5",
1777 | "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz",
1778 | "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=",
1779 | "dev": true
1780 | },
1781 | "sha.js": {
1782 | "version": "2.4.8",
1783 | "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.8.tgz",
1784 | "integrity": "sha1-NwaMLEdra69ALRSknGf1l5IfY08=",
1785 | "dev": true
1786 | },
1787 | "source-list-map": {
1788 | "version": "2.0.0",
1789 | "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.0.tgz",
1790 | "integrity": "sha512-I2UmuJSRr/T8jisiROLU3A3ltr+swpniSmNPI4Ml3ZCX6tVnDsuZzK7F2hl5jTqbZBWCEKlj5HRQiPExXLgE8A==",
1791 | "dev": true
1792 | },
1793 | "source-map": {
1794 | "version": "0.5.6",
1795 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.6.tgz",
1796 | "integrity": "sha1-dc449SvwczxafwwRjYEzSiu19BI=",
1797 | "dev": true
1798 | },
1799 | "spdx-correct": {
1800 | "version": "1.0.2",
1801 | "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz",
1802 | "integrity": "sha1-SzBz2TP/UfORLwOsVRlJikFQ20A=",
1803 | "dev": true
1804 | },
1805 | "spdx-expression-parse": {
1806 | "version": "1.0.4",
1807 | "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz",
1808 | "integrity": "sha1-m98vIOH0DtRH++JzJmGR/O1RYmw=",
1809 | "dev": true
1810 | },
1811 | "spdx-license-ids": {
1812 | "version": "1.2.2",
1813 | "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz",
1814 | "integrity": "sha1-yd96NCRZSt5r0RkA1ZZpbcBrrFc=",
1815 | "dev": true
1816 | },
1817 | "stream-browserify": {
1818 | "version": "2.0.1",
1819 | "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.1.tgz",
1820 | "integrity": "sha1-ZiZu5fm9uZQKTkUUyvtDu3Hlyds=",
1821 | "dev": true
1822 | },
1823 | "stream-http": {
1824 | "version": "2.7.2",
1825 | "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.7.2.tgz",
1826 | "integrity": "sha512-c0yTD2rbQzXtSsFSVhtpvY/vS6u066PcXOX9kBB3mSO76RiUQzL340uJkGBWnlBg4/HZzqiUXtaVA7wcRcJgEw==",
1827 | "dev": true
1828 | },
1829 | "string_decoder": {
1830 | "version": "1.0.3",
1831 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
1832 | "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
1833 | "dev": true
1834 | },
1835 | "string-width": {
1836 | "version": "1.0.2",
1837 | "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
1838 | "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
1839 | "dev": true
1840 | },
1841 | "strip-ansi": {
1842 | "version": "3.0.1",
1843 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
1844 | "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
1845 | "dev": true
1846 | },
1847 | "strip-bom": {
1848 | "version": "2.0.0",
1849 | "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
1850 | "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=",
1851 | "dev": true
1852 | },
1853 | "supports-color": {
1854 | "version": "3.2.3",
1855 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz",
1856 | "integrity": "sha1-ZawFBLOVQXHYpklGsq48u4pfVPY=",
1857 | "dev": true
1858 | },
1859 | "tapable": {
1860 | "version": "0.2.6",
1861 | "resolved": "https://registry.npmjs.org/tapable/-/tapable-0.2.6.tgz",
1862 | "integrity": "sha1-IGvo4YiGC1FEJTdebxrom/sB/Y0=",
1863 | "dev": true
1864 | },
1865 | "timers-browserify": {
1866 | "version": "2.0.2",
1867 | "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.2.tgz",
1868 | "integrity": "sha1-q0iDz1l9zVCvIRNJoA+8pWrIa4Y=",
1869 | "dev": true
1870 | },
1871 | "to-arraybuffer": {
1872 | "version": "1.0.1",
1873 | "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz",
1874 | "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=",
1875 | "dev": true
1876 | },
1877 | "tty-browserify": {
1878 | "version": "0.0.0",
1879 | "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz",
1880 | "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=",
1881 | "dev": true
1882 | },
1883 | "uglify-js": {
1884 | "version": "2.8.29",
1885 | "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.8.29.tgz",
1886 | "integrity": "sha1-KcVzMUgFe7Th913zW3qcty5qWd0=",
1887 | "dev": true,
1888 | "dependencies": {
1889 | "yargs": {
1890 | "version": "3.10.0",
1891 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.10.0.tgz",
1892 | "integrity": "sha1-9+572FfdfB0tOMDnTvvWgdFDH9E=",
1893 | "dev": true
1894 | }
1895 | }
1896 | },
1897 | "uglify-to-browserify": {
1898 | "version": "1.0.2",
1899 | "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz",
1900 | "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc=",
1901 | "dev": true,
1902 | "optional": true
1903 | },
1904 | "uglifyjs-webpack-plugin": {
1905 | "version": "0.4.6",
1906 | "resolved": "https://registry.npmjs.org/uglifyjs-webpack-plugin/-/uglifyjs-webpack-plugin-0.4.6.tgz",
1907 | "integrity": "sha1-uVH0q7a9YX5m9j64kUmOORdj4wk=",
1908 | "dev": true
1909 | },
1910 | "url": {
1911 | "version": "0.11.0",
1912 | "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz",
1913 | "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=",
1914 | "dev": true,
1915 | "dependencies": {
1916 | "punycode": {
1917 | "version": "1.3.2",
1918 | "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz",
1919 | "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=",
1920 | "dev": true
1921 | }
1922 | }
1923 | },
1924 | "util": {
1925 | "version": "0.10.3",
1926 | "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz",
1927 | "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=",
1928 | "dev": true,
1929 | "dependencies": {
1930 | "inherits": {
1931 | "version": "2.0.1",
1932 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz",
1933 | "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=",
1934 | "dev": true
1935 | }
1936 | }
1937 | },
1938 | "util-deprecate": {
1939 | "version": "1.0.2",
1940 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
1941 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
1942 | "dev": true
1943 | },
1944 | "validate-npm-package-license": {
1945 | "version": "3.0.1",
1946 | "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz",
1947 | "integrity": "sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=",
1948 | "dev": true
1949 | },
1950 | "vm-browserify": {
1951 | "version": "0.0.4",
1952 | "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-0.0.4.tgz",
1953 | "integrity": "sha1-XX6kW7755Kb/ZflUOOCofDV9WnM=",
1954 | "dev": true
1955 | },
1956 | "watchpack": {
1957 | "version": "1.3.1",
1958 | "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.3.1.tgz",
1959 | "integrity": "sha1-fYaTkHsozmAT5/NhCqKhrPB9rYc=",
1960 | "dev": true
1961 | },
1962 | "webpack": {
1963 | "version": "3.0.0",
1964 | "resolved": "https://registry.npmjs.org/webpack/-/webpack-3.0.0.tgz",
1965 | "integrity": "sha1-7pvOvyEkf3FTy0EBaMq0XjpZ1Nc=",
1966 | "dev": true
1967 | },
1968 | "webpack-sources": {
1969 | "version": "1.0.1",
1970 | "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.0.1.tgz",
1971 | "integrity": "sha512-05tMxipUCwHqYaVS8xc7sYPTly8PzXayRCB4dTxLhWTqlKUiwH6ezmEe0OSreL1c30LAuA3Zqmc+uEBUGFJDjw==",
1972 | "dev": true
1973 | },
1974 | "which-module": {
1975 | "version": "1.0.0",
1976 | "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz",
1977 | "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=",
1978 | "dev": true
1979 | },
1980 | "window-size": {
1981 | "version": "0.1.0",
1982 | "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz",
1983 | "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0=",
1984 | "dev": true
1985 | },
1986 | "wordwrap": {
1987 | "version": "0.0.2",
1988 | "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz",
1989 | "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8=",
1990 | "dev": true
1991 | },
1992 | "wrap-ansi": {
1993 | "version": "2.1.0",
1994 | "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
1995 | "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
1996 | "dev": true
1997 | },
1998 | "xtend": {
1999 | "version": "4.0.1",
2000 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz",
2001 | "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=",
2002 | "dev": true
2003 | },
2004 | "y18n": {
2005 | "version": "3.2.1",
2006 | "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz",
2007 | "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=",
2008 | "dev": true
2009 | },
2010 | "yargs": {
2011 | "version": "6.6.0",
2012 | "resolved": "https://registry.npmjs.org/yargs/-/yargs-6.6.0.tgz",
2013 | "integrity": "sha1-eC7CHvQDNF+DCoCMo9UTr1YGUgg=",
2014 | "dev": true,
2015 | "dependencies": {
2016 | "camelcase": {
2017 | "version": "3.0.0",
2018 | "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz",
2019 | "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=",
2020 | "dev": true
2021 | },
2022 | "cliui": {
2023 | "version": "3.2.0",
2024 | "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz",
2025 | "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=",
2026 | "dev": true
2027 | }
2028 | }
2029 | },
2030 | "yargs-parser": {
2031 | "version": "4.2.1",
2032 | "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-4.2.1.tgz",
2033 | "integrity": "sha1-KczqwNxPA8bIe0qfIX3RjJ90hxw=",
2034 | "dev": true,
2035 | "dependencies": {
2036 | "camelcase": {
2037 | "version": "3.0.0",
2038 | "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz",
2039 | "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=",
2040 | "dev": true
2041 | }
2042 | }
2043 | }
2044 | }
2045 | }
2046 |
--------------------------------------------------------------------------------
/Ch 15/webpack-example/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "webpack-example",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "main.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1",
8 | "build": "webpack"
9 | },
10 | "keywords": [],
11 | "author": "",
12 | "license": "ISC",
13 | "devDependencies": {
14 | "webpack": "^3.0.0"
15 | },
16 | "dependencies": {
17 | "lodash": "^4.17.4"
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Ch 15/webpack-example/webpack.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | entry: './main.js',
3 | output: {
4 | filename: 'bundle.js',
5 | path: __dirname
6 | }
7 | };
8 |
--------------------------------------------------------------------------------
/Ch 15/webpack-example/webpack.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Webpack Example
6 |
7 |
8 |
9 |
10 |
11 |
--------------------------------------------------------------------------------
/Ch 8/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/spbooks/jsninja2/99190428cc21281912042f69ae2306c958bdc268/Ch 8/.DS_Store
--------------------------------------------------------------------------------
/Ch 8/hero/hero.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Hero Form
6 |
13 |
14 |
15 |
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/Ch 8/hero/main.js:
--------------------------------------------------------------------------------
1 | const form = document.forms['hero'];
2 |
3 | form.heroName.addEventListener('keyup',validateInline,false);
4 | form.heroName.addEventListener('keyup',disableSubmit,false);
5 |
6 | function disableSubmit(event) {
7 | if(event.target.value === ''){
8 | document.getElementById('submit').disabled = true;
9 | } else {
10 | document.getElementById('submit').disabled = false;
11 | }
12 | }
13 |
14 | const label = form.querySelector('label');
15 | const error = document.createElement('div');
16 | error.classList.add('error');
17 | error.textContent = '! Your name is not allowed to start with X.';
18 | label.append(error);
19 |
20 | function validateInline() {
21 | const heroName = this.value.toUpperCase();
22 | if(heroName.startsWith('X')){
23 | error.style.display = 'block';
24 | } else {
25 | error.style.display = 'none';
26 | }
27 | }
28 |
29 | form.addEventListener('submit',validate,false);
30 |
31 | function validate(event) {
32 | const firstLetter = form.heroName.value[0];
33 | if (firstLetter.toUpperCase() === 'X') {
34 | event.preventDefault();
35 | alert('Your name is not allowed to start with X!');
36 |
37 | }
38 | }
39 | form.addEventListener('submit', makeHero, false);
40 |
41 | function makeHero(event) {
42 |
43 | event.preventDefault(); // prevent the form from being submitted
44 |
45 | const hero = {}; // create an empty object
46 |
47 | hero.name = form.heroName.value; // create a name property based on the input field's value
48 | hero.realName = form.realName.value;
49 | hero.powers = [...form.powers].filter(box => box.checked).map(box => box.value);
50 | hero.category = form.category.value;
51 | hero.age = form.age.value;
52 | hero.city = form.city.value;
53 | hero.origin = form.origin.value;
54 | alert(JSON.stringify(hero)); // convert object to JSON string and display in alert dialog
55 | }
56 |
--------------------------------------------------------------------------------
/Ch 8/quiz/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Quiz Ninja
7 |
8 |
9 |
10 |
11 |
12 |
13 | Score: 0
14 | Quiz Ninja!
15 |
16 |
17 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/Ch 8/quiz/main.js:
--------------------------------------------------------------------------------
1 | const quiz = [
2 | { name: "Superman",realName: "Clark Kent" },
3 | { name: "Wonderwoman",realName: "Dianna Prince" },
4 | { name: "Batman",realName: "Bruce Wayne" },
5 | ];
6 | // View Object
7 | const view = {
8 | score: document.querySelector('#score strong'),
9 | question: document.getElementById('question'),
10 | result: document.getElementById('result'),
11 | info: document.getElementById('info'),
12 | start: document.getElementById('start'),
13 | response: document.querySelector('#response'),
14 | render(target,content,attributes) {
15 | for(const key in attributes) {
16 | target.setAttribute(key, attributes[key]);
17 | }
18 | target.innerHTML = content;
19 | },
20 | show(element){
21 | element.style.display = 'block';
22 | },
23 | hide(element){
24 | element.style.display = 'none';
25 | },
26 | resetForm(){
27 | this.response.answer.value = '';
28 | this.response.answer.focus();
29 | },
30 | setup(){
31 | this.show(this.question);
32 | this.show(this.response);
33 | this.show(this.result);
34 | this.hide(this.start);
35 | this.render(this.score,game.score);
36 | this.render(this.result,'');
37 | this.render(this.info,'');
38 | this.resetForm();
39 | },
40 | teardown(){
41 | this.hide(this.question);
42 | this.hide(this.response);
43 | this.show(this.start);
44 | }
45 | };
46 |
47 | const game = {
48 | start(quiz){
49 | this.score = 0;
50 | this.questions = [...quiz];
51 | view.setup();
52 | this.ask();
53 | },
54 | ask(name){
55 | if(this.questions.length > 0) {
56 | this.question = this.questions.pop();
57 | const question = `What is ${this.question.name}'s real name?`;
58 | view.render(view.question,question);
59 | }
60 | else {
61 | this.gameOver();
62 | }
63 | },
64 | check(event){
65 | event.preventDefault();
66 | const response = view.response.answer.value;
67 | const answer = this.question.realName;
68 | if(response === answer){
69 | view.render(view.result,'Correct!',{'class':'correct'});
70 | this.score++;
71 | view.render(view.score,this.score);
72 | } else {
73 | view.render(view.result,`Wrong! The correct answer was ${answer}`,{'class':'wrong'});
74 | }
75 | view.resetForm();
76 | this.ask();
77 | },
78 | gameOver(){
79 | view.render(view.info,`Game Over, you scored ${this.score} point${this.score !== 1 ? 's' : ''}`);
80 | view.teardown();
81 | }
82 | }
83 |
84 | view.start.addEventListener('click', () => game.start(quiz), false);
85 | view.response.addEventListener('submit', (event) => game.check(event), false);
86 | view.hide(view.response);
87 |
--------------------------------------------------------------------------------
/Ch 8/quiz/styles.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css?family=Baloo+Da|Roboto');
2 |
3 | body{
4 | background: #5F1C1C;
5 | font-family: 'Roboto', sans-serif;
6 | }
7 | .dojo{
8 | background: url(https://gistcdn.githack.com/alexmwalker/6acbe9040d9fe6e5e9fd758a25e1b2a5/raw/635810bd1a925c06b5c0bc0c861d62fe53597078/dojo.svg) no-repeat;
9 | width: 100%;
10 | height: 800px;
11 | background-size: 100% auto;
12 | padding-top: 10px;
13 | }
14 | .quiz-body{
15 | background: rgba(255,255,255,1);
16 | margin: 150px 33%;
17 | padding: 10px 20px 50px 20px;
18 | -webkit-box-shadow: 4px 4px 11px 3px rgba(0,0,0,0.3);
19 | -moz-box-shadow: 4px 4px 11px 3px rgba(0,0,0,0.3);
20 | box-shadow: 4px 4px 11px 3px rgba(0,0,0,0.3);
21 | }
22 | h1{
23 | color: #611BBD;
24 | font-family: 'Baloo Da', cursive;
25 | font-weight: 900;
26 | text-align: center;
27 | font-size: 48px;
28 | margin: 0;
29 | }
30 | button {
31 | color: #ffffff;
32 | background-color: #611BBD;
33 | border-color: #130269;
34 | border-radius: 4px;
35 | margin: 0.2em 0;
36 | display: block;
37 | width: 100%;
38 | font-size: 24px;
39 | }
40 | #question {
41 | font-size: 24px;
42 | }
43 |
44 | #result{
45 | color: #fff;
46 | margin: 0.2em 0;
47 | width: 100%;
48 | text-align: center;
49 | }
50 | .correct {
51 | background-color: #0c0;
52 | }
53 | .wrong {
54 | color: #fff;
55 | background-color: #c00;
56 | }
57 |
--------------------------------------------------------------------------------
/Ch 8/search/main.js:
--------------------------------------------------------------------------------
1 | const form = document.forms['search'];
2 | const input = form.elements.searchInput;
3 |
4 | input.addEventListener('focus', () => console.log('focused'), false);
5 | input.addEventListener('blur', () => console.log('blurred'), false);
6 | input.addEventListener('change', () => console.log('changed'), false);
7 |
8 | form.addEventListener('submit', search, false);
9 |
10 | input.value = 'Search Here';
11 |
12 | input.addEventListener('focus', function(){
13 | if (input.value==='Search Here') {
14 | input.value = ''
15 | }
16 | }, false);
17 |
18 | input.addEventListener('blur', function(){
19 | if(input.value == '') {
20 | input.value = 'Search Here';
21 | } }, false);
22 |
23 | function search(event) {
24 | alert(`You Searched for: ${input.value}`);
25 | event.preventDefault();
26 | }
27 |
--------------------------------------------------------------------------------
/Ch 8/search/search.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Search
6 |
7 |
8 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/Ch 9/animation/animation.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Animation Example
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
--------------------------------------------------------------------------------
/Ch 9/animation/main.js:
--------------------------------------------------------------------------------
1 | const squareA = document.getElementById('A');
2 | const squareB = document.getElementById('B');
3 |
4 | let angleA = 0;
5 |
6 | setInterval( () => {
7 | angleA = (angleA + 2) % 360;
8 | squareA.style.transform = `rotate(${angleA}deg)`
9 | }, 1000/60);
10 |
11 | let angleB = 0;
12 |
13 | function rotateB() {
14 | angleB = (angleB + 2)%360
15 | squareB.style.transform = `rotate(${angleB}deg)`
16 | window.requestAnimationFrame(rotateB);
17 | }
18 |
19 | const id = requestAnimationFrame(rotateB);
20 |
--------------------------------------------------------------------------------
/Ch 9/animation/styles.css:
--------------------------------------------------------------------------------
1 | .square {
2 | margin: 100px;
3 | width: 100px;
4 | height: 100px;
5 | background: #d16;
6 | }
7 |
--------------------------------------------------------------------------------
/Ch 9/quiz/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Quiz Ninja
7 |
8 |
9 |
10 |
11 |
12 |
13 | Score: 0
14 | Quiz Ninja!
15 |
16 |
17 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/Ch 9/quiz/main.js:
--------------------------------------------------------------------------------
1 | const quiz = [
2 | { name: "Superman",realName: "Clark Kent" },
3 | { name: "Wonderwoman",realName: "Dianna Prince" },
4 | { name: "Batman",realName: "Bruce Wayne" },
5 | ];
6 | // View Object
7 | const view = {
8 | score: document.querySelector('#score strong'),
9 | question: document.querySelector('#question'),
10 | result: document.querySelector('#result'),
11 | info: document.querySelector('#info'),
12 | start: document.querySelector('#start'),
13 | response: document.querySelector('#response'),
14 | timer: document.querySelector('#timer strong'),
15 | render(target,content,attributes) {
16 | for(const key in attributes) {
17 | target.setAttribute(key, attributes[key]);
18 | }
19 | target.innerHTML = content;
20 | },
21 | show(element){
22 | element.style.display = 'block';
23 | },
24 | hide(element){
25 | element.style.display = 'none';
26 | },
27 | resetForm(){
28 | this.response.answer.value = '';
29 | this.response.answer.focus();
30 | },
31 | setup(){
32 | this.show(this.question);
33 | this.show(this.response);
34 | this.show(this.result);
35 | this.hide(this.start);
36 | this.render(this.score,game.score);
37 | this.render(this.result,'');
38 | this.render(this.info,'');
39 | this.resetForm();
40 | },
41 | teardown(){
42 | this.hide(this.question);
43 | this.hide(this.response);
44 | this.show(this.start);
45 | }
46 | };
47 |
48 | const game = {
49 | start(quiz){
50 | this.score = 0;
51 | this.questions = [...quiz];
52 | view.setup();
53 | this.secondsRemaining = 20;
54 | this.timer = setInterval( this.countdown , 1000 );
55 | this.ask();
56 | },
57 | countdown() {
58 | game.secondsRemaining--;
59 | view.render(view.timer,game.secondsRemaining);
60 | if(game.secondsRemaining < 0) {
61 | game.gameOver();
62 | }
63 | },
64 | ask(name){
65 | if(this.questions.length > 0) {
66 | this.question = this.questions.pop();
67 | const question = `What is ${this.question.name}'s real name?`;
68 | view.render(view.question,question);
69 | }
70 | else {
71 | this.gameOver();
72 | }
73 | },
74 | check(event){
75 | event.preventDefault();
76 | const response = view.response.answer.value;
77 | const answer = this.question.realName;
78 | if(response === answer){
79 | view.render(view.result,'Correct!',{'class':'correct'});
80 | this.score++;
81 | view.render(view.score,this.score);
82 | } else {
83 | view.render(view.result,`Wrong! The correct answer was ${answer}`,{'class':'wrong'});
84 | }
85 | view.resetForm();
86 | this.ask();
87 | },
88 | gameOver(){
89 | view.render(view.info,`Game Over, you scored ${this.score} point${this.score !== 1 ? 's' : ''}`);
90 | view.teardown();
91 | clearInterval(this.timer);
92 | }
93 | }
94 |
95 | view.start.addEventListener('click', () => game.start(quiz), false);
96 | view.response.addEventListener('submit', (event) => game.check(event), false);
97 | view.hide(view.response);
98 |
--------------------------------------------------------------------------------
/Ch 9/quiz/styles.css:
--------------------------------------------------------------------------------
1 | @import url('https://fonts.googleapis.com/css?family=Baloo+Da|Roboto');
2 |
3 | body{
4 | background: #5F1C1C;
5 | font-family: 'Roboto', sans-serif;
6 | }
7 | .dojo{
8 | background: url(https://gistcdn.githack.com/alexmwalker/6acbe9040d9fe6e5e9fd758a25e1b2a5/raw/635810bd1a925c06b5c0bc0c861d62fe53597078/dojo.svg) no-repeat;
9 | width: 100%;
10 | height: 800px;
11 | background-size: 100% auto;
12 | padding-top: 10px;
13 | }
14 | .quiz-body{
15 | background: rgba(255,255,255,1);
16 | margin: 150px 33%;
17 | padding: 10px 20px 50px 20px;
18 | -webkit-box-shadow: 4px 4px 11px 3px rgba(0,0,0,0.3);
19 | -moz-box-shadow: 4px 4px 11px 3px rgba(0,0,0,0.3);
20 | box-shadow: 4px 4px 11px 3px rgba(0,0,0,0.3);
21 | }
22 | h1{
23 | color: #611BBD;
24 | font-family: 'Baloo Da', cursive;
25 | font-weight: 900;
26 | text-align: center;
27 | font-size: 48px;
28 | margin: 0;
29 | }
30 | button {
31 | color: #ffffff;
32 | background-color: #611BBD;
33 | border-color: #130269;
34 | border-radius: 4px;
35 | margin: 0.2em 0;
36 | display: block;
37 | width: 100%;
38 | font-size: 24px;
39 | }
40 | #question {
41 | font-size: 24px;
42 | }
43 |
44 | #result{
45 | color: #fff;
46 | margin: 0.2em 0;
47 | width: 100%;
48 | text-align: center;
49 | }
50 | .correct {
51 | background-color: #0c0;
52 | }
53 | .wrong {
54 | color: #fff;
55 | background-color: #c00;
56 | }
57 |
--------------------------------------------------------------------------------
/dojo.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
77 |
--------------------------------------------------------------------------------
/questions.json:
--------------------------------------------------------------------------------
1 | {
2 | "questions": [{
3 | "name": "Superman",
4 | "realName": "Clarke Kent"
5 | },
6 | {
7 | "name": "Batman",
8 | "realName": "Bruce Wayne"
9 | },
10 | {
11 | "name": "Wonder Woman",
12 | "realName": "Dianna Prince"
13 | },
14 | {
15 | "name": "Spider-Man",
16 | "realName": "Peter Parker"
17 | },
18 | {
19 | "name": "Green Lantern",
20 | "realName": "Hal Jordan"
21 | },
22 | {
23 | "name": "Green Arrow",
24 | "realName": "Oliver Queen"
25 | },
26 | {
27 | "name": "The Flash",
28 | "realName": "Barry Allen"
29 | },
30 | {
31 | "name": "The Hulk",
32 | "realName": "Bruce Banner"
33 | },
34 | {
35 | "name": "Iron Man",
36 | "realName": "Tony Stark"
37 | },
38 | {
39 | "name": "The Punisher",
40 | "realName": "Frank Castle"
41 | },
42 | {
43 | "name": "Daredevil",
44 | "realName": "Matt Murdoch"
45 | },
46 | {
47 | "name": "Cyclops",
48 | "realName": "Scott Summers"
49 | },
50 | {
51 | "name": "Ghost Rider",
52 | "realName": "Johnny Blaze"
53 | },
54 | {
55 | "name": "Hawkeye",
56 | "realName": "Clint Barton"
57 | },
58 | {
59 | "name": "Aquaman",
60 | "realName": "Arthur Curry"
61 | },
62 | {
63 | "name": "Catwoman",
64 | "realName": "Selina Kyle"
65 | },
66 | {
67 | "name": "Beast",
68 | "realName": "Hank McCoy"
69 | },
70 | {
71 | "name": "Professor X",
72 | "realName": "Charles Xavier"
73 | },
74 | {
75 | "name": "Captain America",
76 | "realName": "Steve Rogers"
77 | },
78 | {
79 | "name": "Collossus",
80 | "realName": "Piotr Rasputin"
81 | },
82 | {
83 | "name": "Mr Fantastic",
84 | "realName": "Reed Richards"
85 | },
86 | {
87 | "name": "Invisible Girl",
88 | "realName": "Sue Storm"
89 | },
90 | {
91 | "name": "Iceman",
92 | "realName": "Bobby Drake"
93 | },
94 | {
95 | "name": "Martian Manhunter",
96 | "realName": "J'onn J'onzz "
97 | },
98 | {
99 | "name": "Two Face",
100 | "realName": "Harvey Dent"
101 | },
102 | {
103 | "name": "The Riddler",
104 | "realName": "Edward Nigma"
105 | },
106 | {
107 | "name": "Black Canary",
108 | "realName": "Dinah Lance"
109 | },
110 | {
111 | "name": "Killer Croc",
112 | "realName": "Waylon Jones"
113 | },
114 | {
115 | "name": "The Atom",
116 | "realName": "Ray Palmer"
117 | },
118 | {
119 | "name": "Animal Man",
120 | "realName": "Buddy Baker"
121 | },
122 | {
123 | "name": "Blue Beetle",
124 | "realName": "Jaime Reyes"
125 | },
126 | {
127 | "name": "Booster Gold",
128 | "realName": "Michael Carter"
129 | },
130 | {
131 | "name": "Captain Atom",
132 | "realName": "Nate Adam"
133 | },
134 | {
135 | "name": "Captain Marvel",
136 | "realName": "Carol Danvers"
137 | },
138 | {
139 | "name": "The Creeper",
140 | "realName": "Jack Ryder"
141 | },
142 | {
143 | "name": "Deathstroke",
144 | "realName": "Slade Wilson"
145 | },
146 | {
147 | "name": "Storm",
148 | "realName": "Ororo Munroe"
149 | },
150 | {
151 | "name": "Magneto",
152 | "realName": "Max Eisenhardt"
153 | },
154 | {
155 | "name": "The Human Torch",
156 | "realName": "Johnny Storm"
157 | },
158 | {
159 | "name": "Deadpool",
160 | "realName": "Wade Wilson"
161 | },
162 | {
163 | "name": "Black Panther",
164 | "realName": "T'Challa"
165 | },
166 | {
167 | "name": "The Thing",
168 | "realName": "Ben Grimm"
169 | },
170 | {
171 | "name": "Wolverine",
172 | "realName": "James Howlett"
173 | },
174 | {
175 | "name": "Nightcrawler",
176 | "realName": "Kurt Wagner"
177 | },
178 | {
179 | "name": "Gambit",
180 | "realName": "Remy Etienne LeBeau"
181 | },
182 | {
183 | "name": "Spider-Woman",
184 | "realName": "Jessica Drew"
185 | },
186 | {
187 | "name": "Doctor Doom",
188 | "realName": "Victor Von Doom"
189 | },
190 | {
191 | "name": "Nightwing",
192 | "realName": "Dick Grayson"
193 | },
194 | {
195 | "name": "Supergirl",
196 | "realName": "Kara Danvers"
197 | },
198 | {
199 | "name": "Scarecrow",
200 | "realName": "Jonathan Crane"
201 | },
202 | {
203 | "name": "The Penguin",
204 | "realName": "Oswald Cobblepot"
205 | },
206 | {
207 | "name": "Mister Miracle",
208 | "realName": "Scott Free"
209 | },
210 | {
211 | "name": "Hush",
212 | "realName": "Tommy Elliot"
213 | },
214 | {
215 | "name": "Huntress",
216 | "realName": "Helena Bertinelli"
217 | },
218 | {
219 | "name": "Hawkman",
220 | "realName": "Carter Hall"
221 | },
222 | {
223 | "name": "Hawkgirl",
224 | "realName": "Shiera Hall"
225 | },
226 | {
227 | "name": "Venom",
228 | "realName": "Eddi Brock"
229 | },
230 | {
231 | "name": "Rogue",
232 | "realName": "Anna Marie"
233 | },
234 | {
235 | "name": "Black Cat",
236 | "realName": "Felicia Hardy"
237 | },
238 | {
239 | "name": "White Queen",
240 | "realName": "Emma Frost"
241 | },
242 | {
243 | "name": "Captain Britain",
244 | "realName": "Brian Braddock"
245 | },
246 | {
247 | "name": "Doctor Strange",
248 | "realName": "Stephen Vincent Strange"
249 | },
250 | {
251 | "name": "Cable",
252 | "realName": "Nathan Summers"
253 | },
254 | {
255 | "name": "Dazzler",
256 | "realName": "Alison Blaire"
257 | },
258 | {
259 | "name": "Electro",
260 | "realName": "Maxwell Dillon"
261 | },
262 | {
263 | "name": "Falcon",
264 | "realName": "Sam Wilson"
265 | },
266 | {
267 | "name": "War Machine",
268 | "realName": "James Rhodes"
269 | },
270 | {
271 | "name": "Havok",
272 | "realName": "Alex Summers"
273 | },
274 | {
275 | "name": "Iron Fist",
276 | "realName": "Danny Rand"
277 | },
278 | {
279 | "name": "Batgirl",
280 | "realName": "Barbara Gordon"
281 | },
282 | {
283 | "name": "Scarlet Witch",
284 | "realName": "Wanda Maximoff"
285 | },
286 | {
287 | "name": "Quicksilver",
288 | "realName": "Pietro Maximoff"
289 | },
290 | {
291 | "name": "Sabretooth",
292 | "realName": "Victor Creed"
293 | },
294 | {
295 | "name": "She-Hulk",
296 | "realName": "Jennifer Walters"
297 | },
298 | {
299 | "name": "Sunfire",
300 | "realName": "Shiro Yoshida"
301 | },
302 | {
303 | "name": "Killer Frost",
304 | "realName": "Caitlin Snow"
305 | },
306 | {
307 | "name": "Captain Boomerang",
308 | "realName": "George Harkness"
309 | },
310 | {
311 | "name": "Cyborg",
312 | "realName": "Victor Stone"
313 | }, {
314 | "name": "Enchantress",
315 | "realName": "June Moon"
316 | },
317 | {
318 | "name": "Doctor Strange",
319 | "realName": "Stephen Vincent Strange"
320 | }
321 | ]
322 | }
323 |
--------------------------------------------------------------------------------