├── .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 |
11 |
12 |
13 |

Quiz Ninja!

14 |
15 |
16 |
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 |
11 |
12 |
13 |

Quiz Ninja!

14 |
15 |
16 |
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 |
11 |
12 |
13 |

Quiz Ninja!

14 |
15 |
16 |
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 |
11 |
12 |
13 |

Quiz Ninja!

14 |
15 |
16 |
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 |
11 |
12 |
13 |

Quiz Ninja!

14 |
15 |
16 |
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 |
9 |

Justice League

10 |
11 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /Ch 06/quiz/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Quiz Ninja 7 | 8 | 9 | 10 |
11 |
12 |
13 |

Quiz Ninja!

14 |
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 |
18 | 19 | 20 |
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 |
18 | 19 | 20 |
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 |
9 | 10 | 11 |
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 | Sorry, but your browswer does not support the canvas element 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 |
9 | 10 | 11 | 12 |
13 |
14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /Ch 14/worker/factors.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Factorizor 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 |
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 |
9 | 10 | 11 |
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 |
16 | 19 | 22 |

Super Powers:

23 | 26 | 29 | 32 | 35 | 38 |

What type of hero are you?

39 | 42 | 45 | 48 | 51 | 61 | 64 | 65 |
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 |
18 | 19 | 20 |
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 |
9 | 10 | 11 |
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 |
18 | 19 | 20 |
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 | 4 | 5 | 26 | 27 | 28 | DOJO 2 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 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 | --------------------------------------------------------------------------------