├── .node-version ├── public ├── stage5 │ ├── style.css │ ├── .csslintrc │ ├── .eslintrc │ ├── index.html │ └── tests.js ├── stage6 │ ├── sample │ │ ├── script.js │ │ ├── style.css │ │ └── index.html │ ├── .csslintrc │ ├── style.css │ ├── .eslintrc │ ├── tests.js │ └── index.html ├── stage7 │ ├── .csslintrc │ ├── style.css │ ├── .eslintrc │ ├── index.html │ └── tests.js ├── stage4 │ ├── .csslintrc │ ├── style.css │ ├── index.html │ └── tests.js ├── stage1 │ ├── .csslintrc │ ├── analytics.js │ ├── style.css │ ├── index.html │ └── tests.js ├── stage2 │ ├── .csslintrc │ ├── style.css │ ├── index.html │ └── tests.js ├── stage3 │ ├── .csslintrc │ ├── style.css │ ├── index.html │ └── tests.js ├── .eslintrc ├── common │ └── mocha-patch.css ├── bower.json └── index.html ├── .bowerrc ├── .gitignore ├── reveal.json ├── .travis.yml ├── .eslintrc ├── server.js ├── gulpfile.js ├── gulp └── serve.js ├── package.json ├── LICENSE ├── server └── response │ └── friendsmap.json ├── README.md └── npm-shrinkwrap.json /.node-version: -------------------------------------------------------------------------------- 1 | v4.1.0 2 | -------------------------------------------------------------------------------- /public/stage5/style.css: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "cwd": "public/" 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | bower_components 3 | -------------------------------------------------------------------------------- /public/stage6/sample/script.js: -------------------------------------------------------------------------------- 1 | // ボタンはサービスです。 2 | // 自由に使ってください。 3 | -------------------------------------------------------------------------------- /reveal.json: -------------------------------------------------------------------------------- 1 | { 2 | "transition": "slide", 3 | "transitionSpeed": "fast" 4 | } 5 | -------------------------------------------------------------------------------- /public/stage5/.csslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "//": "さすがにいまどき IE7 はやめてほしい", 3 | "box-sizing": false 4 | } 5 | -------------------------------------------------------------------------------- /public/stage6/.csslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "//": "さすがにいまどき IE7 はやめてほしい", 3 | "box-sizing": false 4 | } 5 | -------------------------------------------------------------------------------- /public/stage7/.csslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "//": "さすがにいまどき IE7 はやめてほしい", 3 | "box-sizing": false 4 | } 5 | -------------------------------------------------------------------------------- /public/stage5/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "globals": { 3 | "fetch": false, 4 | "Promise": false 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /public/stage6/style.css: -------------------------------------------------------------------------------- 1 | .js-training-sample-link { 2 | display: block; 3 | margin: 10px auto; 4 | text-align: center; 5 | } 6 | -------------------------------------------------------------------------------- /public/stage7/style.css: -------------------------------------------------------------------------------- 1 | .js-training-sample-link { 2 | display: block; 3 | margin: 10px auto; 4 | text-align: center; 5 | } 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "latest" 4 | - "iojs" 5 | 6 | sudo: false 7 | 8 | notifications: 9 | email: false 10 | -------------------------------------------------------------------------------- /public/stage4/.csslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "//": "querySelector の練習のために、あえて ID セレクタでしかひけない要素を入れている", 3 | "ids": false, 4 | 5 | "//": "さすがにいまどき IE7 はやめてほしい", 6 | "box-sizing": false 7 | } 8 | -------------------------------------------------------------------------------- /public/stage1/.csslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "//": "querySelector の練習のために、あえて ID セレクタでしかひけない要素を入れている", 3 | "ids": false, 4 | 5 | "//": "querySelector の練習のために、あえて属性セレクタでしかひけない要素を入れている", 6 | "unqualified-attributes": false 7 | } 8 | -------------------------------------------------------------------------------- /public/stage2/.csslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "//": "querySelector の練習のために、あえて ID セレクタでしかひけない要素を入れている", 3 | "ids": false, 4 | 5 | "//": "querySelector の練習のために、あえて属性セレクタでしかひけない要素を入れている", 6 | "unqualified-attributes": false 7 | } 8 | -------------------------------------------------------------------------------- /public/stage3/.csslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "//": "querySelector の練習のために、あえて ID セレクタでしかひけない要素を入れている", 3 | "ids": false, 4 | 5 | "//": "querySelector の練習のために、あえて属性セレクタでしかひけない要素を入れている", 6 | "unqualified-attributes": false 7 | } 8 | -------------------------------------------------------------------------------- /public/stage6/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | // シャレオツコードの意図が undefined 代入だとわかりやすいので許可 4 | "no-undef-init": 0 5 | }, 6 | "globals": { 7 | "fetch": false, 8 | "Promise": false 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /public/stage6/sample/style.css: -------------------------------------------------------------------------------- 1 | .js-training-playground { 2 | box-sizing: border-box; 3 | padding: 80px 0; 4 | height: 250px; 5 | } 6 | 7 | .js-training-button { 8 | display: block; 9 | margin: 0 auto; 10 | } 11 | -------------------------------------------------------------------------------- /public/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "mocha": true, 4 | "browser": true, 5 | "jquery": true 6 | }, 7 | "globals": { 8 | "expect": false 9 | }, 10 | "rules": { 11 | // chai の expect 構文が誤警告になるため無視 12 | "no-unused-expressions": 0 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /public/stage6/tests.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('ステージ6(意図通りにモジュールを書ける)', function() { 4 | it('あなたの満足のいく Web アプリケーションがここにある', function() { 5 | // ボタンはサービスです。 6 | // 自由に使ってください。 7 | 8 | var qualityOfYourAppliation = undefined; 9 | 10 | expect(qualityOfYourAppliation).to.be.ok; 11 | }); 12 | }); 13 | -------------------------------------------------------------------------------- /public/stage7/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "rules": { 3 | // undefined 上書き問題のため、明示的な undefined 代入を許可 4 | "no-undef-init": 0, 5 | 6 | // == 演算子の振る舞いの問題の警告は誤警告 7 | "yoda": 0, 8 | 9 | // truthy, falsey を判定する問題のため、定数式を許可 10 | "no-constant-condition": 0 11 | }, 12 | "globals": { 13 | "fetch": false, 14 | "Promise": false 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "node": true 4 | }, 5 | "rules": { 6 | // single quote に統一 7 | "quotes": [2, "single", "avoid-escape"], 8 | 9 | // 関数宣言文以外は hoisting 避けのため禁止 10 | "no-use-before-define": [2, "nofunc"], 11 | 12 | // この形式のキャストはくっついていないと読みづらい 13 | "space-infix-ops": [2, { "int32Hint": false }], 14 | 15 | // ガード節の読みやすさを重視して、一行の場合のみ許可する 16 | "curly": [2, "multi-line"] 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /public/common/mocha-patch.css: -------------------------------------------------------------------------------- 1 | @charset "utf-8"; 2 | 3 | #mocha { 4 | position: relative; 5 | } 6 | 7 | #mocha-stats { 8 | position: absolute !important; 9 | top: -45px !important; 10 | } 11 | 12 | #mocha .suite { 13 | margin-bottom: 0.8em; 14 | } 15 | 16 | #mocha .suite h1 { 17 | margin-bottom: 0.5em; 18 | } 19 | 20 | #mocha .suite .suite h1 { 21 | margin-bottom: 0.5em; 22 | } 23 | 24 | #mocha .test { 25 | margin-bottom: 0.5em; 26 | } 27 | -------------------------------------------------------------------------------- /public/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mixi-js-training-client", 3 | "version": "0.0.0", 4 | "homepage": "https://github.com/mixi-inc/JavaScriptTraining", 5 | "authors": [ 6 | "Kuniwak " 7 | ], 8 | "description": "Training course repositry for JavaScript by mixi", 9 | "keywords": [ 10 | "training" 11 | ], 12 | "license": "MIT", 13 | "private": true, 14 | "ignore": [ 15 | "**/.*", 16 | "node_modules", 17 | "bower_components", 18 | "test", 19 | "tests" 20 | ], 21 | "dependencies": { 22 | "chai": "~2.1.2", 23 | "chai-as-promised": "~4.3.0", 24 | "mocha": "~2.2.1", 25 | "bootstrap": "~3.3.4", 26 | "chai-jquery": "~2.0.0", 27 | "jquery": "~2.1.3", 28 | "fetch": "~0.7.0", 29 | "github-fork-ribbon-css": "~0.1.1" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /public/stage6/sample/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | mixi JS Training 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 |
14 | 15 |
16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var util = require('util'); 4 | var path = require('path'); 5 | var express = require('express'); 6 | var bodyParser = require('body-parser'); 7 | 8 | var app = express(); 9 | app.use(bodyParser.json({limit: '50mb'})); 10 | app.use(bodyParser.urlencoded({extended: true, limit: '50mb' })); 11 | 12 | var PUBLIC_DIR = path.join(__dirname, 'public'); 13 | app.use(express.static(PUBLIC_DIR)); 14 | 15 | 16 | app.get('/api/heavy', function(req, res) { 17 | setTimeout(function() { 18 | res.send('// do nothing'); 19 | }, 1000); 20 | }); 21 | 22 | var friendMap = require('./server/response/friendsmap.json'); 23 | 24 | app.get('/api/friends/:username([\\w.-]+)', function(req, res) { 25 | var username = req.params.username; 26 | res.json(friendMap[username]); 27 | }); 28 | 29 | 30 | 31 | var PORT = process.env.PORT; 32 | var HOSTNAME = 'localhost'; 33 | 34 | var server = require('http').createServer(app); 35 | server.listen(PORT, HOSTNAME, function () { 36 | console.log('SERVER_READY'); 37 | console.log(util.format('http://%s:%d にブラウザでアクセスしてください'), HOSTNAME, PORT); 38 | }); 39 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var path = require('path'); 4 | var gulp = require('gulp-help')(require('gulp')); 5 | 6 | var serve = require('./gulp/serve.js'); 7 | 8 | var tasks = [ 9 | { 10 | id: 'stage-1', 11 | help: '意図した DOM を取得できているかテストします' 12 | }, { 13 | id: 'stage-2', 14 | help: '意図通りに DOM のスタイルが変更できているかテストします' 15 | }, { 16 | id: 'stage-3', 17 | help: '意図通りに DOM の構造が変更できているかテストします' 18 | }, { 19 | id: 'stage-4', 20 | help: '意図通りにイベントを利用できているかテストします' 21 | }, { 22 | id: 'stage-5', 23 | help: '意図通りに非同期処理ができているかテストします' 24 | }, { 25 | id: 'stage-6', 26 | help: '意図通りにモジュールを実装できているかテストします' 27 | }, { 28 | id: 'stage-7', 29 | help: 'よくあるイディオムを読み書きできているかテストします' 30 | } 31 | ]; 32 | 33 | 34 | tasks.forEach(function(task) { 35 | var stage = path.join('public', task.id); 36 | var js = path.join(stage, '**/*.js'); 37 | var css = path.join(stage, '**/*.css'); 38 | 39 | gulp.task('lint-' + task.id, 'ミスのおこりやすいコード・可読性の低いコードがないか検査します', function() { 40 | var eslint = require('gulp-eslint'); 41 | 42 | return gulp.src(js) 43 | .pipe(eslint()) 44 | .pipe(eslint.format()) 45 | }); 46 | }); 47 | 48 | 49 | 50 | gulp.task('serve', 'サーバーを起動し、ブラウザでテストを確認できるようにします', function(){ 51 | return serve(); 52 | }); 53 | -------------------------------------------------------------------------------- /public/stage1/analytics.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | 'use strict'; 3 | // PhantomJS s not supporting web components yet. 4 | // And some polyfills (as webcomponents/webcomponents.js) are not worked well. 5 | if (!('registerElement' in document)) { return; } 6 | 7 | var XFlyingSushiMonsterProto = Object.create(HTMLDivElement.prototype); 8 | XFlyingSushiMonsterProto.createdCallback = function() { 9 | this.textContent = '\uD83C\uDF63'; 10 | var style = this.style; 11 | 12 | style.position = 'absolute'; 13 | style.fontSize = '100px'; 14 | style.animationName = 'moveHorizontal'; 15 | style.animationDuration = '1s'; 16 | style.animationIterationCount = 'infinite'; 17 | style.animationDirection = 'alternate-reverse'; 18 | style.animationFillMode = 'forwards'; 19 | }; 20 | 21 | var XFlyingSushiMonster = document.registerElement('x-flying-sushi-monster', { 22 | prototype: XFlyingSushiMonsterProto 23 | }); 24 | 25 | var target = document.createElement('div'); 26 | target.style.position = 'relative'; 27 | target.style.height = '100px'; 28 | target.appendChild(new XFlyingSushiMonster()); 29 | 30 | var targetContainer = document.createElement('div'); 31 | targetContainer.appendChild(target); 32 | document.body.appendChild(targetContainer); 33 | })(); 34 | -------------------------------------------------------------------------------- /public/stage7/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | mixi JS Training 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 24 | 25 | 26 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | mixi JS Training 7 | 8 | 9 | 14 | 15 | 16 |
17 |
18 | Fork me on GitHub 19 |
20 |
21 |
22 |
23 |
24 |

mixi JavaScript Training

25 |
26 |
27 |
    28 |
  1. DOM 要素を取得するトレーニング
  2. 29 |
  3. DOM 要素の属性・テキストを変更するトレーニング
  4. 30 |
  5. DOM の構造を変更するトレーニング
  6. 31 |
  7. DOM イベントを利用するトレーニング
  8. 32 |
  9. 非同期処理を書くトレーニング
  10. 33 |
  11. モジュールを実装するトレーニング
  12. 34 |
  13. よくあるイディオムを読むトレーニング
  14. 35 |
36 |
37 | 38 | 39 | -------------------------------------------------------------------------------- /gulp/serve.js: -------------------------------------------------------------------------------- 1 | /* eslint no-underscore-dangle:0 */ 2 | 'use strict'; 3 | 4 | var path = require('path'); 5 | var stream = require('stream'); 6 | var gutil = require('gulp-util'); 7 | 8 | var SERVER_SCRIPT = path.join(__dirname, '../server.js'); 9 | 10 | 11 | var serve = function() { 12 | var nodemon = require('gulp-nodemon'); 13 | var readable = new stream.Readable({ objectMode: true }); 14 | 15 | readable._read = function() { 16 | var self = this; 17 | 18 | nodemon({ 19 | script: SERVER_SCRIPT, 20 | watch: [SERVER_SCRIPT], 21 | env: { PORT: serve.PORT }, 22 | stdout: false 23 | }) 24 | .on('readable', function() { 25 | this.stdout.on('data', function(buf) { 26 | gutil.log(String(buf)); 27 | if (!String(buf).match(/SERVER_READY/)) { return; } 28 | 29 | // server is ready. 30 | self.emit('end'); 31 | }); 32 | 33 | this.stderr.on('data', function(buf) { 34 | var stderr = String(buf); 35 | var isAddressAlreadyInUse = Boolean(stderr.match(/EADDRINUSE/)); 36 | 37 | var msg = 'サーバーを起動できませんでした。\n' + (isAddressAlreadyInUse ? 38 | '既にサーバーが立ち上がっているか、8000 番ポートが既に使用されています。' : stderr); 39 | 40 | gutil.log(gutil.colors.red(msg)); 41 | }); 42 | }); 43 | }; 44 | 45 | return readable; 46 | }; 47 | 48 | 49 | serve.PORT = process.env.PORT || 8000; 50 | 51 | module.exports = serve; 52 | -------------------------------------------------------------------------------- /public/stage5/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | mixi JS Training 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 16 | 17 | 18 | 19 | 20 | 21 | 26 | 27 | 28 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mixi-js-training", 3 | "version": "0.0.0", 4 | "description": "Training course repository for JavaScript by mixi", 5 | "main": "index.js", 6 | "scripts": { 7 | "postinstall": "bower install", 8 | "help": "gulp help", 9 | "start": "gulp serve", 10 | "presentation": "reveal-md README.md --theme solarized --separator '^\\n\\n\\n' --verticalSeparator '^\\n\\n'", 11 | "lint-stage-1": "gulp lint-stage-1", 12 | "lint-stage-2": "gulp lint-stage-2", 13 | "lint-stage-3": "gulp lint-stage-3", 14 | "lint-stage-4": "gulp lint-stage-4", 15 | "lint-stage-5": "gulp lint-stage-5", 16 | "lint-stage-6": "gulp lint-stage-6", 17 | "lint-stage-7": "gulp lint-stage-7" 18 | }, 19 | "repository": { 20 | "type": "git", 21 | "url": "https://github.com/mixi-inc/JavaScriptTraining.git" 22 | }, 23 | "keywords": [ 24 | "training" 25 | ], 26 | "author": "Kuniwak", 27 | "license": "MIT", 28 | "bugs": { 29 | "url": "https://github.com/mixi-inc/JavaScriptTraining/issues" 30 | }, 31 | "engines": { 32 | "node": "~4.1.0" 33 | }, 34 | "homepage": "https://github.com/mixi-inc/JavaScriptTraining", 35 | "devDependencies": { 36 | "body-parser": "1.14.0", 37 | "express": "4.13.3", 38 | "gulp": "3.9.0", 39 | "gulp-eslint": "1.0.0", 40 | "gulp-help": "1.6.1", 41 | "gulp-nodemon": "2.0.4", 42 | "gulp-util": "3.0.6" 43 | }, 44 | "dependencies": { 45 | "bower": "1.5.2", 46 | "reveal-md": "0.0.20" 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /public/stage6/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | mixi JS Training 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | サンプルパッケージ 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 | 27 | 28 | 29 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2015, mixi, inc. 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | 7 | 1. Redistributions of source code must retain the above copyright notice, 8 | this list of conditions and the following disclaimer. 9 | 2. Redistributions in binary form must reproduce the above copyright notice, 10 | this list of conditions and the following disclaimer in the documentation 11 | and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 14 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 15 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 16 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 17 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 18 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 19 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 20 | ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 21 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 22 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | The views and conclusions contained in the software and documentation are those 25 | of the authors and should not be interpreted as representing official policies, 26 | either expressed or implied, of the FreeBSD Project. 27 | -------------------------------------------------------------------------------- /public/stage4/style.css: -------------------------------------------------------------------------------- 1 | .js-training-container { 2 | position: relative; 3 | } 4 | 5 | .js-training { 6 | position: relative; 7 | z-index:10; 8 | display: -webkit-flex; 9 | display: flex; 10 | list-style: none; 11 | margin: 10px; 12 | padding: 0; 13 | font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif; 14 | } 15 | 16 | .js-training li { 17 | -webkit-flex: 1; 18 | flex: 1; 19 | margin: 0; 20 | padding: 0; 21 | height: 40px; 22 | line-height: 40px; 23 | 24 | text-align: center; 25 | color: white; 26 | font-weight: bold; 27 | font-size: 130%; 28 | text-shadow: 0 1px 0 hsla(0, 0%, 0%, 0.3); 29 | } 30 | 31 | .js-training #firebrick { 32 | background-color: firebrick; 33 | font-weight: normal; 34 | } 35 | 36 | .js-training #chocolate { 37 | background-color: chocolate; 38 | font-weight: normal; 39 | } 40 | 41 | .js-training .mediumseagreen { 42 | background-color: mediumseagreen; 43 | font-weight: normal; 44 | } 45 | 46 | .js-training .turquoise { 47 | background-color: turquoise; 48 | font-weight: normal; 49 | text-align: right; 50 | } 51 | 52 | .js-training .turquoise input { 53 | background-color: turquoise; 54 | background-color: hsla(0, 0%, 0%, 0.1); 55 | box-sizing: border-box; 56 | width: 60px; 57 | height: 40px; 58 | border: none; 59 | margin-left: 30%; 60 | padding: 0 0 0 12px; 61 | 62 | font-size: 50%; 63 | color: inherit; 64 | text-shadow: inherit; 65 | text-align: center; 66 | vertical-align: top; 67 | } 68 | 69 | .js-training .steelblue { 70 | background-color: steelblue; 71 | margin: 0; 72 | height: 40px; 73 | font-size: 1; 74 | font-weight: normal; 75 | } 76 | -------------------------------------------------------------------------------- /public/stage4/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | mixi JS Training 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 21 |
22 |
23 | 24 | 25 | 26 | 27 | 32 | 33 | 34 | 38 | 39 |
40 | 43 |
44 | 45 | 46 | -------------------------------------------------------------------------------- /public/stage2/style.css: -------------------------------------------------------------------------------- 1 | .js-training-container { 2 | position: relative; 3 | } 4 | 5 | .js-training { 6 | position: relative; 7 | z-index:10; 8 | display: -webkit-flex; 9 | display: flex; 10 | list-style: none; 11 | margin: 10px; 12 | padding: 0; 13 | font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif; 14 | } 15 | 16 | .js-training li { 17 | -webkit-flex: 1; 18 | flex: 1; 19 | margin: 0; 20 | padding: 0; 21 | height: 40px; 22 | line-height: 40px; 23 | text-align: center; 24 | color: white; 25 | font-weight: bold; 26 | font-size: 130%; 27 | text-shadow: 0 1px 0 hsla(0, 0%, 0%, 0.3); 28 | } 29 | 30 | .js-training #firebrick { 31 | background-color: firebrick; 32 | font-weight: normal; 33 | } 34 | 35 | .js-training #chocolate { 36 | background-color: chocolate; 37 | font-weight: normal; 38 | } 39 | 40 | .js-training .mediumseagreen { 41 | background-color: mediumseagreen; 42 | } 43 | 44 | .js-training .turquoise { 45 | background-color: turquoise; 46 | } 47 | 48 | .js-training blockquote { 49 | background-color: steelblue; 50 | margin: 0; 51 | height: 40px; 52 | font-weight: bold; 53 | font-size: 1; 54 | } 55 | 56 | .js-training [data-js-training="blueviolet"] { 57 | background-color: blueviolet; 58 | } 59 | 60 | .js-training #brown { 61 | background-color: brown; 62 | font-weight: normal; 63 | } 64 | 65 | .js-training #darkorange { 66 | background-color: darkorange; 67 | font-weight: normal; 68 | } 69 | 70 | .js-training .limegreen { 71 | background-color: limegreen; 72 | } 73 | 74 | .js-training .mediumturquoise { 75 | background-color: mediumturquoise; 76 | } 77 | 78 | .js-training p { 79 | margin: 0; 80 | padding: 0; 81 | background-color: cornflowerblue; 82 | } 83 | 84 | .js-training [data-js-training="darkorchid"] { 85 | background-color: darkorchid; 86 | } 87 | 88 | .js-training-trick { 89 | z-index: 1; 90 | position: absolute; 91 | top: 0; 92 | height: 40px; 93 | line-height: 40px; 94 | text-indent: 60%; 95 | } 96 | -------------------------------------------------------------------------------- /public/stage1/style.css: -------------------------------------------------------------------------------- 1 | .js-training { 2 | display: -webkit-flex; 3 | display: flex; 4 | list-style: none; 5 | margin: 10px; 6 | padding: 0; 7 | } 8 | 9 | .js-training li { 10 | -webkit-flex: 1; 11 | flex: 1; 12 | margin: 0; 13 | padding: 0; 14 | height: 40px; 15 | line-height: 40px; 16 | text-align: center; 17 | color: white; 18 | font-weight: bold; 19 | font-size: 130%; 20 | text-shadow: 0 1px 0 hsla(0, 0%, 0%, 0.3); 21 | } 22 | 23 | .js-training #firebrick { 24 | background-color: firebrick; 25 | } 26 | 27 | .js-training #chocolate { 28 | background-color: chocolate; 29 | } 30 | 31 | .js-training .mediumseagreen { 32 | background-color: mediumseagreen; 33 | } 34 | 35 | .js-training .turquoise { 36 | -webkit-flex: 0.5; 37 | flex: 0.5; 38 | background-color: turquoise; 39 | } 40 | 41 | .js-training blockquote { 42 | background-color: steelblue; 43 | margin: 0; 44 | height: 40px; 45 | font-weight: bold; 46 | font-size: 1; 47 | } 48 | 49 | .js-training [data-js-training="blueviolet"] { 50 | background-color: blueviolet; 51 | } 52 | 53 | .js-training #brown { 54 | background-color: brown; 55 | } 56 | 57 | .js-training #darkorange { 58 | background-color: darkorange; 59 | } 60 | 61 | .js-training .limegreen { 62 | background-color: limegreen; 63 | } 64 | 65 | .js-training .mediumturquoise { 66 | -webkit-flex: 0.5; 67 | flex: 0.5; 68 | background-color: mediumturquoise; 69 | } 70 | 71 | .js-training p { 72 | margin: 0; 73 | padding: 0; 74 | background-color: cornflowerblue; 75 | } 76 | 77 | .js-training [data-js-training="darkorchid"] { 78 | background-color: darkorchid; 79 | } 80 | 81 | @-webkit-keyframes moveHorizontal { 82 | from { 83 | left: -20%; 84 | } 85 | 86 | to { 87 | left: 110%; 88 | } 89 | } 90 | 91 | 92 | @-moz-keyframes moveHorizontal { 93 | from { 94 | left: -20%; 95 | } 96 | 97 | to { 98 | left: 110%; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /public/stage2/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | mixi JS Training 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 23 |
🐠🐠
24 |
25 |
26 | 34 |
🐠🐠
35 |
36 |
37 | 38 | 39 | 40 | 41 | 46 | 47 | 48 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /public/stage1/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | mixi JS Training 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 23 | 32 |
33 | 34 | 35 | 36 | 37 | 42 | 43 | 44 | 45 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /public/stage3/style.css: -------------------------------------------------------------------------------- 1 | .js-training-container { 2 | position: relative; 3 | } 4 | 5 | .js-training { 6 | position: relative; 7 | z-index:10; 8 | display: -webkit-flex; 9 | display: flex; 10 | list-style: none; 11 | margin: 10px; 12 | padding: 0; 13 | font-family: 'Open Sans', 'Helvetica Neue', Helvetica, Arial, sans-serif; 14 | } 15 | 16 | .js-training li { 17 | -webkit-flex: 1; 18 | flex: 1; 19 | margin: 0; 20 | padding: 0; 21 | height: 40px; 22 | line-height: 40px; 23 | text-align: center; 24 | color: white; 25 | font-weight: bold; 26 | font-size: 130%; 27 | text-shadow: 0 1px 0 hsla(0, 0%, 0%, 0.3); 28 | } 29 | 30 | .js-training #firebrick { 31 | background-color: firebrick; 32 | font-weight: normal; 33 | } 34 | 35 | .js-training #chocolate { 36 | background-color: chocolate; 37 | font-weight: normal; 38 | } 39 | 40 | .js-training .mediumseagreen { 41 | background-color: mediumseagreen; 42 | font-weight: normal; 43 | } 44 | 45 | .js-training .turquoise { 46 | background-color: turquoise; 47 | font-weight: normal; 48 | } 49 | 50 | .js-training blockquote { 51 | background-color: steelblue; 52 | margin: 0; 53 | height: 40px; 54 | font-size: 1; 55 | font-weight: normal; 56 | } 57 | 58 | .js-training [data-js-training="blueviolet"] { 59 | background-color: blueviolet; 60 | } 61 | 62 | .js-training #brown { 63 | background-color: brown; 64 | font-weight: normal; 65 | } 66 | 67 | .js-training #darkorange { 68 | background-color: darkorange; 69 | font-weight: normal; 70 | } 71 | 72 | .js-training .limegreen { 73 | background-color: limegreen; 74 | font-weight: normal; 75 | } 76 | 77 | .js-training .mediumturquoise { 78 | background-color: mediumturquoise; 79 | font-weight: normal; 80 | } 81 | 82 | .js-training p { 83 | margin: 0; 84 | padding: 0; 85 | background-color: cornflowerblue; 86 | font-weight: normal; 87 | } 88 | 89 | .js-training [data-js-training="darkorchid"] { 90 | background-color: darkorchid; 91 | } 92 | 93 | .js-training-trick { 94 | z-index: 1; 95 | position: absolute; 96 | top: 0; 97 | height: 40px; 98 | line-height: 40px; 99 | text-indent: 60%; 100 | } 101 | -------------------------------------------------------------------------------- /public/stage3/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | mixi JS Training 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 | 22 |
🐠🐠
23 |
24 |
25 | 32 |
🐠🐠
33 |
34 |
35 | 36 | 37 | 38 | 39 | 44 | 45 | 46 | 50 | 51 | 52 | -------------------------------------------------------------------------------- /public/stage3/tests.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('ステージ3(意図した通りに DOM 要素の構造を変更できるようになる)', function() { 4 | describe('DOMインターフェース編', function() { 5 | it('1 番の要素から幽霊要素を除去する', function() { 6 | 7 | // チュートリアル 8 | // 9 | // ここに以下のコードを記述してください。 10 | // 11 | // var element = document.querySelector('#firebrick'); 12 | // var ghost = document.querySelector('.firebrick-ghost'); 13 | // element.removeChild(ghost); 14 | 15 | 16 | var firebrick = document.getElementById('firebrick'); 17 | expect(firebrick.childNodes.length).to.equal(1); 18 | expect(firebrick).to.have.property('textContent', '1'); 19 | }); 20 | 21 | 22 | it('2 番の要素からインベーダー要素を除去する', function() { 23 | 24 | // ここにコードを記述してください。 25 | 26 | 27 | var darkorange = document.getElementById('chocolate'); 28 | expect(darkorange.childNodes.length).to.equal(1); 29 | expect(darkorange).to.have.property('textContent', '2'); 30 | }); 31 | 32 | 33 | it('3 番の要素の左右の幽霊要素をすべて除去する', function() { 34 | 35 | // ここにコードを記述してください。 36 | 37 | 38 | var darkorange = document.querySelector('.mediumseagreen'); 39 | expect(darkorange).to.have.property('textContent', '3\uD83C\uDF3F'); 40 | }); 41 | 42 | 43 | it('4 番の水色の要素の最後に要素を追加する', function() { 44 | var elementToAdd = document.createElement('span'); 45 | elementToAdd.textContent = '\uD83D\uDC2C'; 46 | 47 | // 上の elementToAdd を追加するコードをここに記述してください。 48 | 49 | 50 | var turquoise = document.querySelector('.turquoise'); 51 | expect(turquoise.childNodes.length).to.equal(2); 52 | expect(turquoise).to.have.deep.property('childNodes[0].textContent', '4'); 53 | expect(turquoise).to.have.deep.property('childNodes[1]').equal(elementToAdd); 54 | }); 55 | 56 | 57 | it('5 番の青色の要素の最初に要素を追加する', function() { 58 | var elementToAdd = document.createElement('span'); 59 | elementToAdd.textContent = '\uD83D\uDC1F'; 60 | 61 | // 上の elementToAdd を、5 番の青色の要素の最初に追加するコードを 62 | // ここに記述してください。 63 | 64 | 65 | var blockquote = document.querySelector('blockquote'); 66 | expect(blockquote.childNodes.length).to.equal(2); 67 | expect(blockquote).to.have.deep.property('childNodes[0]').equal(elementToAdd); 68 | expect(blockquote).to.have.deep.property('childNodes[1].textContent', '5'); 69 | }); 70 | }); 71 | 72 | 73 | describe('jQuery 編', function() { 74 | it('6 番の要素から幽霊要素を除去する', function() { 75 | 76 | // チュートリアル 77 | // 78 | // jQuery でも同じことをおこなってみましょう。 79 | // ここに以下のコードを記述してください。 80 | // 81 | // $('.brown-ghost').remove(); 82 | 83 | 84 | var $brown = $('#brown'); 85 | expect($brown.children()).to.have.length(0); 86 | expect($brown).to.have.text('6'); 87 | }); 88 | 89 | 90 | it('7 番の要素からインベーダー要素を除去する', function() { 91 | 92 | // ここにコードを記述してください。 93 | 94 | 95 | var $darkorange = $('#darkorange'); 96 | expect($darkorange.children()).to.have.length(0); 97 | expect($darkorange).to.have.text('7'); 98 | 99 | // 参考情報 100 | // http://api.jquery.com/category/manipulation/ 101 | }); 102 | 103 | 104 | it('8 番の要素の左右の幽霊要素をすべて除去する', function() { 105 | 106 | // ここにコードを記述してください。 107 | 108 | 109 | var $limegreen = $('.limegreen'); 110 | expect($limegreen).to.have.text('8\uD83C\uDF3F'); 111 | }); 112 | 113 | 114 | it('9 番の水色の要素の最後に要素を追加する', function() { 115 | var $elementToAdd = $('\uD83D\uDC2C'); 116 | 117 | // 上の $elementToAdd を追加するコードをここに記述してください。 118 | 119 | 120 | var $mediumturquoise = $('.mediumturquoise'); 121 | expect($mediumturquoise.children()).to.have.length(1); 122 | expect($mediumturquoise).to.have.text('9\uD83D\uDC2C'); 123 | }); 124 | 125 | 126 | it('10 番の青色の要素の最初に要素を追加する', function() { 127 | var $elementToAdd = $('\uD83D\uDC1F'); 128 | 129 | // 上の $elementToAdd を追加するコードをここに記述してください。 130 | 131 | 132 | var $p = $('p'); 133 | expect($p.children()).to.have.length(1); 134 | expect($p).to.have.text('\uD83D\uDC1F10'); 135 | }); 136 | }); 137 | }); 138 | -------------------------------------------------------------------------------- /public/stage4/tests.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('ステージ4(意図通りにイベントを利用できる)', function() { 4 | describe('イベント編', function() { 5 | it('1 番の要素の click イベントで要素内の数字を 1 ずつ大きくできる', function() { 6 | 7 | // チュートリアル 8 | // 9 | // 2 通りの代表的な書き方があります。 10 | // 11 | // jQuery じゃない版: 12 | // 13 | // var element = document.getElementById('firebrick'); 14 | // element.addEventListener('click', function() { 15 | // element.textContent = Number(element.textContent) + 1; 16 | // }); 17 | // 18 | // jQuery 版: 19 | // 20 | // $('#firebrick').on('click', function(event) { 21 | // var $target = $(event.target); 22 | // $target.text(Number($target.text()) + 1); 23 | // }); 24 | // 25 | // ここに上記のどちらかのコードを記述してください。 26 | 27 | 28 | var firebrick = document.getElementById('firebrick'); 29 | firebrick.dispatchEvent(createClickEvent()); 30 | expect(firebrick).to.have.property('textContent', '2'); 31 | 32 | firebrick.dispatchEvent(createClickEvent()); 33 | expect(firebrick).to.have.property('textContent', '3'); 34 | }); 35 | 36 | 37 | it('2 番の要素の click イベントで要素内の数字を 1 ずつ小さくできる', function() { 38 | 39 | // ここにコードを記述してください。 40 | 41 | 42 | var chocolate = document.getElementById('chocolate'); 43 | chocolate.dispatchEvent(createClickEvent()); 44 | expect(chocolate).to.have.property('textContent', '1'); 45 | 46 | chocolate.dispatchEvent(createClickEvent()); 47 | expect(chocolate).to.have.property('textContent', '0'); 48 | }); 49 | 50 | 51 | it('3 番の要素の click イベントで要素を 10 度ずつ回転できる', function() { 52 | 53 | // ここにコードを記述してください。 54 | 55 | 56 | var mediumseagreen = document.querySelector('.mediumseagreen'); 57 | mediumseagreen.dispatchEvent(createClickEvent()); 58 | expect(mediumseagreen).to.have.deep.property( 59 | secret('fglyr.genafsbez'), secret('ebgngr(10qrt)')); 60 | 61 | mediumseagreen.dispatchEvent(createClickEvent()); 62 | expect(mediumseagreen).to.have.deep.property( 63 | secret('fglyr.genafsbez'), secret('ebgngr(20qrt)')); 64 | }); 65 | 66 | 67 | it('4 番の要素を入力された角度に回転できる', function() { 68 | 69 | // ここにコードを記述してください。 70 | 71 | 72 | var turquoise = document.querySelector('.turquoise'); 73 | var turquoiseInput = turquoise.querySelector('input'); 74 | 75 | simulateChangeEvent(turquoiseInput, 10); 76 | expect(turquoise).to.have.deep.property( 77 | secret('fglyr.genafsbez'), secret('ebgngr(10qrt)')); 78 | 79 | simulateChangeEvent(turquoiseInput, 20); 80 | expect(turquoise).to.have.deep.property( 81 | secret('fglyr.genafsbez'), secret('ebgngr(20qrt)')); 82 | }); 83 | 84 | 85 | it('5 番の要素の内容を取得できる', function(done) { 86 | 87 | // このテストは、画面下部の .steelblue 要素の内容が "5 (クジラの絵文字)" で 88 | // あることを確認する意図があります。画面上は 5 とクジラの絵文字が正しく 89 | // 表示されています。しかし、テストは失敗しているようです。 90 | // 91 | // このテストが意図通り成功するようにテストコードを修正してください。 92 | // 93 | // なお、expect(steelblue).to.be.null は上記のテストの要件を満たして 94 | // いないので、正解ではありません。 95 | 96 | var steelblue = document.querySelector('.steelblue'); 97 | expect(steelblue).to.have.property('textContent', '5 \uD83D\uDC33'); 98 | done(); 99 | }); 100 | }); 101 | }); 102 | 103 | 104 | function createClickEvent() { 105 | var event = document.createEvent('MouseEvents'); 106 | event.initEvent('click', false, true); 107 | return event; 108 | } 109 | 110 | 111 | function simulateChangeEvent(inputElement, newValue) { 112 | inputElement.value = newValue; 113 | inputElement.dispatchEvent(createChangeEvent()); 114 | } 115 | 116 | 117 | function createChangeEvent() { 118 | var event = document.createEvent('HTMLEvents'); 119 | event.initEvent('change', true, true); 120 | 121 | return event; 122 | } 123 | 124 | 125 | function secret(str) { 126 | // Copyright (c) 2012 K.Adam White 127 | // Released under the MIT license 128 | // https://github.com/kadamwhite/jquery.rot13/blob/master/LICENSE-MIT 129 | return Array.prototype.map.call(str, function(char) { 130 | if (!char.match(/[A-Za-z]/)) { return char; } 131 | 132 | var charCode = char.charCodeAt(0); 133 | if(charCode < 97) { 134 | charCode = (charCode - 52) % 26 + 65; 135 | } else { 136 | charCode = (charCode - 84) % 26 + 97; 137 | } 138 | return String.fromCharCode(charCode); 139 | }).join(''); 140 | } 141 | -------------------------------------------------------------------------------- /public/stage5/tests.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('ステージ5(意図通りに非同期処理を利用できる)', function() { 4 | describe('Promise 編', function() { 5 | it('resolve ハンドラーを書ける', function(testDone){ 6 | var promise = Promise.resolve('resolved!'); 7 | 8 | // チュートリアル 9 | // 10 | // ここに下記のコードを記述してください。 11 | // 12 | // promise.then(function(msg) { 13 | // expect(msg).to.equal('resolved!'); 14 | // testDone(); 15 | // }); 16 | }); 17 | 18 | 19 | it('reject ハンドラーを書ける', function(testDone){ 20 | var promise = Promise.reject('rejected!'); 21 | 22 | // reject ハンドラーを使って、下の assertion が promise の 23 | // エラー値を検証できるように記述してください。 24 | // 25 | // expect(msg).to.equal('rejected!'); 26 | // testDone(); 27 | 28 | // ここにコードを記述してください。 29 | 30 | 31 | }); 32 | 33 | 34 | it('複数の promise すべての完了を待つ promise を作成できる', function() { 35 | var messageFragments = ['あなたと', 'java', '今すぐダウンロード']; 36 | var promise1 = createWaitPromise(messageFragments[0], 10); 37 | var promise2 = createWaitPromise(messageFragments[1], 20); 38 | var promise3 = createWaitPromise(messageFragments[2], 30); 39 | 40 | // 作成した promise を promise 変数に代入してください。 41 | var promise = 'change me!'; 42 | 43 | 44 | return expect(promise).to.eventually.deep.equal(messageFragments); 45 | }); 46 | 47 | 48 | it('複数の promise のうち最も速く解決された値をもつ promise を作成できる', function() { 49 | var messageFragments = ['30億の', 'デバイスで', '走るjava']; 50 | var promise1 = createWaitPromise(messageFragments[0], 30); 51 | var promise2 = createWaitPromise(messageFragments[1], 10); 52 | var promise3 = createWaitPromise(messageFragments[2], 30); 53 | 54 | // 作成した promise を promise 変数に代入してください。 55 | var promise = 'change me!'; 56 | 57 | 58 | return expect(promise).to.eventually.equal(messageFragments[1]); 59 | }); 60 | }); 61 | 62 | 63 | describe('fetch API 編', function() { 64 | it('/api/friends API を使って Sugar の友人を取得できる', function() { 65 | var api = '/api/friends/'; 66 | var username = 'Sugar'; 67 | 68 | // チュートリアル 69 | // 70 | // ここに下記のコードを記述してください。 71 | // 72 | // var promisedFriends = fetch(api + username).then(function(res) { 73 | // return res.json(); 74 | // }); 75 | 76 | 77 | return expect(promisedFriends).to.eventually.have.length(1) 78 | .and.have.members(['PYXC-PJ']); 79 | }); 80 | 81 | 82 | it('/api/friends API を使って Shen の友人を取得できる', function() { 83 | var api = '/api/friends/'; 84 | var username = 'Shen'; 85 | 86 | // 作成した promise を promisedFriends 変数に代入してください。 87 | var promisedFriends = 'change me!'; 88 | 89 | 90 | return expect(promisedFriends).to.eventually.have.length(2) 91 | .and.have.members(['jisp', 'TeJaS']); 92 | }); 93 | 94 | 95 | it('/api/friends API を使って Shen の友人の友人を取得できる', function() { 96 | var api = '/api/friends/'; 97 | var username = 'Shen'; 98 | 99 | // 作成した promise を promisedFriends 変数に代入してください。 100 | var promisedFriends = 'change me!'; 101 | 102 | 103 | return expect(promisedFriends).to.eventually.have.length(1) 104 | .and.have.members(['TypeScript']); 105 | }); 106 | 107 | 108 | it.skip('/api/friends API を使って CoffeeScript の友人を再帰的に取得できる', function() { 109 | // 難易度高いので、自信のある人だけ挑戦してください。 110 | // it.skip の .skip を消せば、テストが走るようになります。 111 | 112 | // 作成した promise を promisedFriends 変数に代入してください。 113 | var promisedFriends = 'change me!'; 114 | 115 | 116 | return expect(promisedFriends).to.eventually.have.length(5) 117 | .and.have.members([ 118 | 'Taijilang', 119 | 'purescript', 120 | 'Wind.js', 121 | 'ScriptBlocks', 122 | 'jangaroo' 123 | ]); 124 | }); 125 | 126 | 127 | it('Github の mixi-inc の organization の情報を取得できる', function() { 128 | 129 | // 作成した promise を mixiOrg 変数に代入してください。 130 | var mixiOrg = 'change me!'; 131 | 132 | return expect(mixiOrg).to.eventually.have.property('id', 1089312); 133 | 134 | // Github API に関する参考情報 135 | // https://developer.github.com/v3/orgs 136 | }); 137 | 138 | 139 | it('Github API を使って、mixi-inc/JavaScriptTraining の情報を取得できる', function() { 140 | var repository = 'mixi-inc/JavaScriptTraining'; 141 | 142 | // 作成した promise を mixiRepo 変数に代入してください。 143 | var mixiRepo = 'change me!'; 144 | 145 | 146 | return expect(mixiRepo).to.eventually.have.property('full_name', repository); 147 | 148 | // Github API に関する参考情報 149 | // https://developer.github.com/v3/repos/ 150 | }); 151 | 152 | 153 | it('Github API を使って、VimL、Emacs Lisp でスターが最も多いプロダクト名を' + 154 | 'それぞれ 1 つずつ取得できる', function() { 155 | var languages = [ 'VimL', '"Emacs Lisp"' ]; 156 | var mostPopularRepos = 'change me!'; 157 | 158 | // 作成した promise を mostPopularRepos 変数に代入してください。 159 | 160 | 161 | return expect(mostPopularRepos).to.eventually.have.length(2) 162 | .and.satisfy(function(names) { 163 | return typeof names[0] === 'string' && 164 | typeof names[1] === 'string'; 165 | }); 166 | 167 | // Github API に関する参考情報 168 | // https://developer.github.com/v3/search 169 | }); 170 | }); 171 | 172 | 173 | function createWaitPromise(value, msec) { 174 | return new Promise(function(resolve) { 175 | setTimeout(resolve, msec, value); 176 | }); 177 | } 178 | }); 179 | -------------------------------------------------------------------------------- /public/stage2/tests.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | 4 | describe('ステージ2(意図した通りに DOM 要素の属性・テキストを変更できるようになる)', function() { 5 | describe('DOMインターフェース編', function() { 6 | it('1 番の要素の寿司を2つに増やす', function() { 7 | 8 | // チュートリアル 9 | // 10 | // ここに以下のコードを記述してください。 11 | // 12 | // var element = document.getElementById('firebrick'); 13 | // element.textContent = element.textContent + element.textContent; 14 | var element = 'change me!'; 15 | 16 | 17 | expect(element).to.have.property(secret('vq'), secret('sveroevpx')); 18 | expect(element).to.have.deep.property( 19 | secret('grkgPbagrag'), '\uD83C\uDF63\uD83C\uDF63'); 20 | }); 21 | 22 | 23 | it('2 番の要素のチョコを2つに増やす', function() { 24 | 25 | // ここにコードを記述してください。 26 | // 変更した DOM 要素は element 変数に代入してください。 27 | var element = 'change me!'; 28 | 29 | 30 | expect(element).to.have.property(secret('vq'), secret('pubpbyngr')); 31 | expect(element).to.have.deep.property( 32 | secret('grkgPbagrag'), '\uD83C\uDF6B\uD83C\uDF6B'); 33 | 34 | // 参考情報 35 | // https://developer.mozilla.org/ja/docs/Web/API/Node/textContent 36 | }); 37 | 38 | 39 | it('3 番の要素の背景色を "limegreen" に変更する', function() { 40 | 41 | // ここにコードを記述してください。 42 | // 変更した DOM 要素は element 変数に代入してください。 43 | var element = 'change me!'; 44 | 45 | 46 | expect(element).to.have.property( 47 | secret('pynffAnzr'), secret('zrqvhzfrnterra')); 48 | 49 | expect(element).to.have.deep.property( 50 | secret('fglyr.onpxtebhaqPbybe'), normalizeColor('limegreen')); 51 | 52 | // 参考情報 53 | // https://developer.mozilla.org/ja/search?q=css+%E8%89%B2 54 | }); 55 | 56 | 57 | it('4 番の要素を 50% の透明度に変更する', function() { 58 | 59 | // ここにコードを記述してください。 60 | // 変更した DOM 要素は element 変数に代入してください。 61 | var element = 'change me!'; 62 | 63 | 64 | expect(element).to.have.property( 65 | secret('pynffAnzr'), secret('ghedhbvfr')); 66 | 67 | expect(element).to.have.deep.property( 68 | secret('fglyr.bcnpvgl'), '0.5'); 69 | 70 | // 参考情報 71 | // https://developer.mozilla.org/ja/search?q=css+%E4%B8%8D%E9%80%8F%E6%98%8E%E5%BA%A6 72 | }); 73 | 74 | 75 | it('5 番の要素を時計回り方向に 10 度回転させる', function() { 76 | 77 | // ここにコードを記述してください。 78 | // 変更した DOM 要素は element 変数に代入してください。 79 | var element = 'change me!'; 80 | 81 | 82 | expect(element).to.have.property( 83 | secret('gntAnzr'), secret('OYBPXDHBGR')); 84 | 85 | expect(element).to.have.deep.property( 86 | secret('fglyr.genafsbez'), secret('ebgngr(10qrt)')); 87 | 88 | // 参考情報 89 | // https://developer.mozilla.org/ja/search?q=css+%E5%9B%9E%E8%BB%A2 90 | }); 91 | 92 | 93 | it('6 番の要素を上に 20px 移動させる', function() { 94 | 95 | // ここにコードを記述してください。 96 | // 変更した DOM 要素は element 変数に代入してください。 97 | // 98 | // なお、上に 20px 移動させる方法は複数ありますが、今回は top 属性を 99 | // 使う方法を使ってください。 100 | var element = 'change me!'; 101 | 102 | 103 | expect(element).to.have.deep.property( 104 | secret('qngnfrg.wfGenvavat'), secret('oyhrivbyrg')); 105 | 106 | expect(element).to.have.deep.property( 107 | secret('fglyr.gbc'), secret('-20ck')); 108 | 109 | expect(element).to.have.deep.property( 110 | secret('fglyr.cbfvgvba'), secret('eryngvir')); 111 | 112 | // 参考情報 113 | // https://developer.mozilla.org/ja/docs/Web/CSS/top 114 | }); 115 | }); 116 | 117 | 118 | describe('jQuery 編', function() { 119 | it('7 番の要素の寿司を jQuery を使って2つに増やす', function() { 120 | 121 | // チュートリアル 122 | // 123 | // 同じように、jQuery ではどのようにして DOM を操作するのか 124 | // 体験してみましょう。 125 | // 126 | // ここに以下のコードを記述してください。 127 | // 128 | // var $element = $('#brown'); 129 | // $element.text($element.text() + $element.text()); 130 | var $element = 'change me!'; 131 | 132 | 133 | expect($element).to.be.instanceof(jQuery); 134 | expect($element).to.have.id(secret('oebja')); 135 | expect($element).to.have.text('\uD83C\uDF63\uD83C\uDF63'); 136 | }); 137 | 138 | 139 | it('8 番の要素のチョコを jQuery を使って2つに増やす', function() { 140 | 141 | // ここにコードを記述してください。 142 | // 変更した DOM 要素は $element 変数に代入してください。 143 | var $element = 'change me!'; 144 | 145 | 146 | expect($element).to.be.instanceof(jQuery); 147 | expect($element).to.have.id(secret('qnexbenatr')); 148 | expect($element).to.have.text('\uD83C\uDF6B\uD83C\uDF6B'); 149 | 150 | // 参考情報 151 | // http://api.jquery.com/category/manipulation/ 152 | }); 153 | 154 | 155 | it('9 番の要素の背景色を jQuery を使って "mediumseagreen" に変更する', function() { 156 | 157 | // ここにコードを記述してください。 158 | // 変更した DOM 要素は $element 変数に代入してください。 159 | var $element = 'change me!'; 160 | 161 | 162 | expect($element).to.be.instanceof(jQuery); 163 | expect($element).to.have.class(secret('yvzrterra')); 164 | expect($element).to.have.css( 165 | secret('onpxtebhaq-pbybe'), normalizeColor('mediumseagreen')); 166 | 167 | // 参考情報 168 | // http://api.jquery.com/category/css/ 169 | }); 170 | 171 | 172 | it('10 番の要素を jQuery を使って 50% の透明度に変更する', function() { 173 | 174 | // ここにコードを記述してください。 175 | // 変更した DOM 要素は $element 変数に代入してください。 176 | var $element = 'change me!'; 177 | 178 | 179 | expect($element).to.be.instanceof(jQuery); 180 | expect($element).to.have.class(secret('zrqvhzghedhbvfr')); 181 | expect($element).to.have.css(secret('bcnpvgl'), '0.5'); 182 | }); 183 | 184 | 185 | it('11 番の要素を jQuery を使って時計回り方向に 10 度回転させる', function() { 186 | 187 | // ここにコードを記述してください。 188 | // 変更した DOM 要素は $element 変数に代入してください。 189 | var $element = 'change me!'; 190 | 191 | 192 | expect($element).to.be.instanceof(jQuery); 193 | 194 | expect($element.get(0)).to.have.property( 195 | secret('gntAnzr'), secret('C')); 196 | 197 | expect($element).to.have.css(secret('genafsbez')).not.equal('none'); 198 | }); 199 | 200 | 201 | it('12 番の要素を jQuery を使って上に 20px 移動させる', function() { 202 | 203 | // ここにコードを記述してください。 204 | // 変更した DOM 要素は $element 変数に代入してください。 205 | // 206 | // なお、上に 20px 移動させる方法は複数ありますが、今回は top 属性を 207 | // 使う方法を使ってください。 208 | var $element = 'change me!'; 209 | 210 | 211 | expect($element).to.be.instanceof(jQuery); 212 | expect($element).to.have.data(secret('wfGenvavat'), secret('qnexbepuvq')); 213 | expect($element).to.have.css(secret('gbc'), secret('-20ck')); 214 | expect($element).to.have.css(secret('cbfvgvba'), secret('eryngvir')); 215 | }); 216 | }); 217 | }); 218 | 219 | 220 | function secret(str) { 221 | // Copyright (c) 2012 K.Adam White 222 | // Released under the MIT license 223 | // https://github.com/kadamwhite/jquery.rot13/blob/master/LICENSE-MIT 224 | return Array.prototype.map.call(str, function(char) { 225 | if (!char.match(/[A-Za-z]/)) { return char; } 226 | 227 | var charCode = char.charCodeAt(0); 228 | if(charCode < 97) { 229 | charCode = (charCode - 52) % 26 + 65; 230 | } else { 231 | charCode = (charCode - 84) % 26 + 97; 232 | } 233 | return String.fromCharCode(charCode); 234 | }).join(''); 235 | } 236 | 237 | function normalizeColor(value) { 238 | // ブラウザごとに color の値がまちまちに読まれるのを、正規化する 239 | var elem = document.createElement('div'); 240 | elem.style.color = value; 241 | return elem.style.color; 242 | } 243 | -------------------------------------------------------------------------------- /public/stage7/tests.js: -------------------------------------------------------------------------------- 1 | describe('ステージ7(よくあるJSのイディオムを読める)', function() { 2 | 'use strict'; 3 | 4 | describe('クロージャー', function() { 5 | var createCounter = function() { 6 | var i = 0; 7 | 8 | return function() { 9 | return i++; 10 | }; 11 | }; 12 | 13 | var counter = createCounter(); 14 | 15 | 16 | it('1回目の値がわかる', function() { 17 | expect(counter()).to.equal(/* ここに値を書き込んでください */); 18 | }); 19 | 20 | 21 | it('2回目の値がわかる', function() { 22 | expect(counter()).to.equal(/* ここに値を書き込んでください */); 23 | }); 24 | 25 | 26 | it('3回目の値がわかる', function() { 27 | expect(counter()).to.equal(/* ここに値を書き込んでください */); 28 | }); 29 | }); 30 | 31 | 32 | describe('ショートサーキット演算', function() { 33 | it("true && 'default' の結果がわかる", function() { 34 | expect(true && 'default').to.equal(/* ここに値を書き込んでください */); 35 | }); 36 | 37 | 38 | it("false || 'default' の結果がわかる", function() { 39 | expect(false || 'default').to.equal(/* ここに値を書き込んでください */); 40 | }); 41 | 42 | 43 | it("0 || 'default' の結果がわかる", function() { 44 | expect(0 || 'default').to.equal(/* ここに値を書き込んでください */); 45 | }); 46 | 47 | 48 | it("{} || 'default' の結果がわかる", function() { 49 | expect({} || 'default').to.deep.equal(/* ここに値を書き込んでください */); 50 | }); 51 | 52 | 53 | it('default 引数コードが読める1', function() { 54 | var func = function(arg) { 55 | return arg || { foo: 'foo' }; 56 | }; 57 | 58 | expect(func({ foo: 'bar' })).to.deep.equal(/* ここに値を書き込んでください */); 59 | }); 60 | 61 | 62 | it('default 引数コードが読める2', function() { 63 | var func = function(arg) { 64 | return arg || { foo: 'foo' }; 65 | }; 66 | 67 | expect(func()).to.deep.equal(/* ここに値を書き込んでください */); 68 | }); 69 | }); 70 | 71 | 72 | it('無名即時実行関数が読める', function() { 73 | var num = 0; 74 | 75 | (function() { 76 | num = 1; 77 | })(); 78 | 79 | expect(num).to.equal(/* ここに値を書き込んでください */); 80 | }); 81 | 82 | 83 | it('setTimeout 0 パターンが読める', function() { 84 | var num = 0; 85 | 86 | setTimeout(function() { 87 | num = 1; 88 | }, 0); 89 | 90 | expect(num).to.equal(/* ここに値を書き込んでください */); 91 | }); 92 | 93 | 94 | describe('真偽値変換', function() { 95 | var truthy = 1; 96 | var falsey = 0; 97 | 98 | 99 | it('!!truthy の結果がわかる', function() { 100 | expect(!!truthy).to.equal(/* ここに値を書き込んでください */); 101 | }); 102 | 103 | 104 | it('!!falsey の結果がわかる', function() { 105 | expect(!!falsey).to.equal(/* ここに値を書き込んでください */); 106 | }); 107 | 108 | 109 | it('Boolean(truthy) の結果がわかる', function() { 110 | expect(Boolean(truthy)).to.equal(/* ここに値を書き込んでください */); 111 | }); 112 | 113 | 114 | it('Boolean(falsey) の結果がわかる', function() { 115 | expect(Boolean(falsey)).to.equal(/* ここに値を書き込んでください */); 116 | }); 117 | }); 118 | 119 | 120 | describe('prototype 継承', function() { 121 | var GrandParent = function() { 122 | this.grandParent = true; 123 | }; 124 | 125 | var Parent = function() { 126 | this.parent = true; 127 | }; 128 | Parent.prototype = new GrandParent(); 129 | 130 | var Child = function() { 131 | this.child = true; 132 | }; 133 | Child.prototype = new Parent(); 134 | 135 | var parent = new Parent(); 136 | var child = new Child(); 137 | 138 | 139 | it('parent.grandParent の値がわかる', function() { 140 | expect(parent.grandParent).to.equal(/* ここに値を書き込んでください */); 141 | }); 142 | 143 | 144 | it('parent.child の値がわかる', function() { 145 | expect(parent.child).to.equal(/* ここに値を書き込んでください */); 146 | }); 147 | 148 | 149 | it('child.grandParent の値がわかる', function() { 150 | expect(child.grandParent).to.equal(/* ここに値を書き込んでください */); 151 | }); 152 | 153 | 154 | it('child.parent の値がわかる', function() { 155 | expect(child.parent).to.equal(/* ここに値を書き込んでください */); 156 | }); 157 | }); 158 | }); 159 | 160 | 161 | 162 | describe.skip('あなたの闇のJS力', function() { 163 | // .skip を外せば始められます 164 | 165 | describe('ゆるふわ == 演算子', function() { 166 | it("'10' == 10 の振る舞いがわかる", function() { 167 | expect('10' == 10) 168 | .to.equal(/* ここに値を書き込んでください */); 169 | }); 170 | 171 | 172 | it('null == undefined の振る舞いがわかる', function() { 173 | expect(null == undefined) 174 | .to.equal(/* ここに値を書き込んでください */); 175 | }); 176 | 177 | 178 | it('null == false の振る舞いがわかる', function() { 179 | expect(null == false) 180 | .to.equal(/* ここに値を書き込んでください */); 181 | }); 182 | 183 | 184 | it('true == 1 の振る舞いがわかる', function() { 185 | expect(true == 1) 186 | .to.equal(/* ここに値を書き込んでください */); 187 | }); 188 | 189 | 190 | it('true == 10 の振る舞いがわかる', function() { 191 | expect(true == 10) 192 | .to.equal(/* ここに値を書き込んでください */); 193 | }); 194 | 195 | 196 | it('[0, 1] == 0 の振る舞いがわかる', function() { 197 | expect([0, 1] == 0) 198 | .to.equal(/* ここに値を書き込んでください */); 199 | }); 200 | 201 | 202 | it('[1] == 1 の振る舞いがわかる', function() { 203 | expect([1] == 1) 204 | .to.equal(/* ここに値を書き込んでください */); 205 | }); 206 | }); 207 | 208 | 209 | describe('意図しない truthy/falsey', function() { 210 | it('Boolean(false) が truthy/falsey のどちらなのかわかる', function() { 211 | expect(Boolean(false) ? true : false) 212 | .to.equal(/* ここに値を書き込んでください */); 213 | }); 214 | 215 | 216 | it('Boolean(0) が truthy/falsey のどちらなのかわかる', function() { 217 | expect(Boolean(0) ? true : false) 218 | .to.equal(/* ここに値を書き込んでください */); 219 | }); 220 | 221 | 222 | it('new Boolean(0) が truthy/falsey のどちらなのかわかる', function() { 223 | expect(new Boolean(0) ? true : false) 224 | .to.equal(/* ここに値を書き込んでください */); 225 | }); 226 | 227 | 228 | it("'abc' が truthy/falsey のどちらなのかわかる", function() { 229 | expect('abc' ? true : false) 230 | .to.equal(/* ここに値を書き込んでください */); 231 | }); 232 | 233 | 234 | it("'' が truthy/falsey のどちらなのかわかる", function() { 235 | expect('' ? true : false) 236 | .to.equal(/* ここに値を書き込んでください */); 237 | }); 238 | 239 | 240 | it('String(0) が truthy/falsey のどちらなのかわかる', function() { 241 | expect(String(0) ? true : false) 242 | .to.equal(/* ここに値を書き込んでください */); 243 | }); 244 | 245 | 246 | it("String('') が truthy/falsey のどちらなのかわかる", function() { 247 | expect(String('') ? true : false) 248 | .to.equal(/* ここに値を書き込んでください */); 249 | }); 250 | 251 | 252 | it('new String(0) が truthy/falsey のどちらなのかわかる', function() { 253 | expect(new String(0) ? true : false) 254 | .to.equal(/* ここに値を書き込んでください */); 255 | }); 256 | 257 | 258 | it("new String('') が truthy/falsey のどちらなのかわかる", function() { 259 | expect(new String('') ? true : false) 260 | .to.equal(/* ここに値を書き込んでください */); 261 | }); 262 | }); 263 | 264 | 265 | describe('読めないキャスト万歳!', function() { 266 | it("10 + '' の値がわかる", function() { 267 | expect(10 + '').to.equal(/* ここに値を書き込んでください */); 268 | }); 269 | 270 | 271 | it("+'10' の値がわかる", function() { 272 | expect(+'10').to.equal(/* ここに値を書き込んでください */); 273 | }); 274 | 275 | 276 | it("'10.1'|0 の値がわかる", function() { 277 | expect('10.1'|0).to.equal(/* ここに値を書き込んでください */); 278 | }); 279 | 280 | 281 | it("Array.prototype.slice.call({ length: 2, 0: 'foo', 1: 'bar' }) の値がわかる", function() { 282 | var obj = { length: 2, 0: 'foo', 1: 'bar' }; 283 | 284 | expect(Array.prototype.slice.call(obj)) 285 | .to.deep.equal(/* ここに値を書き込んでください */); 286 | }); 287 | 288 | 289 | it('+(new Date()) の型がわかる', function() { 290 | expect(typeof +(new Date())) 291 | .to.equal(/* ここに値を書き込んでください */); 292 | }); 293 | 294 | 295 | it('(new Date()) + 0 の型がわかる', function() { 296 | expect(typeof ((new Date()) + 0)) 297 | .to.equal(/* ここに値を書き込んでください */); 298 | }); 299 | }); 300 | 301 | 302 | describe('ダブルスタンダード Array コンストラクタ', function() { 303 | it('Array(3) が作成する配列の長さがわかる', function() { 304 | expect(Array(3)).to.have.length(/* ここに値を書き込んでください */); 305 | }); 306 | 307 | 308 | it('Array(3) が作成する配列の0番目の要素がわかる', function() { 309 | expect(Array(3)[0]).to.equal(/* ここに値を書き込んでください */); 310 | }); 311 | 312 | 313 | it('Array(3) が作成する配列がわかる', function() { 314 | expect(Array(3)).to.deep.equal(/* ここに値を書き込んでください */); 315 | }); 316 | 317 | 318 | it('Array(1, 2, 3) が作成する配列の長さがわかる', function() { 319 | expect(Array(1, 2, 3)).to.have.length(/* ここに値を書き込んでください */); 320 | }); 321 | 322 | 323 | it('Array(1, 2, 3) が作成する配列の0番目の要素がわかる', function() { 324 | expect(Array(1, 2, 3)[0]).to.equal(/* ここに値を書き込んでください */); 325 | }); 326 | 327 | 328 | it('Array(1, 2, 3) が作成する配列がわかる', function() { 329 | expect(Array(1, 2, 3)).to.deep.equal(/* ここに値を書き込んでください */); 330 | }); 331 | }); 332 | 333 | 334 | describe('静的検査スレイヤー with 文', function() { 335 | it("with ({ 'foo': 'bar' }) のもとで foo の値がわかる", function() { 336 | var obj = { foo: 'bar' }; 337 | 338 | with (obj) { 339 | expect(foo).to.equal(/* ここに値を書き込んでください */); 340 | } 341 | }); 342 | 343 | 344 | it("with ({ 'foo': 'bar', 'undefined': 'bar' }) のもとで foo === undefined の結果がわかる", function() { 345 | var obj = { 'foo': 'bar', 'undefined': 'bar' }; 346 | 347 | with (obj) { 348 | expect(foo === undefined).to.equal(/* ここに値を書き込んでください */); 349 | } 350 | }); 351 | 352 | 353 | it("with ({ 'foo': 'bar', 'null': 'bar' }) のもとで foo === null の結果がわかる", function() { 354 | var obj = { 'foo': 'bar', 'null': 'bar' }; 355 | 356 | with (obj) { 357 | expect(foo === null).to.equal(/* ここに値を書き込んでください */); 358 | } 359 | }); 360 | }); 361 | 362 | 363 | describe('JavaScript のゆるふわ型判定', function() { 364 | it('typeof 0 の結果がわかる', function() { 365 | expect(typeof 0).to.equal(/* ここに値を書き込んでください */); 366 | }); 367 | 368 | it('typeof true の結果がわかる', function() { 369 | expect(typeof true).to.equal(/* ここに値を書き込んでください */); 370 | }); 371 | 372 | it("typeof 'string' の結果がわかる", function() { 373 | expect(typeof 'string').to.equal(/* ここに値を書き込んでください */); 374 | }); 375 | 376 | it('typeof function() {} の結果がわかる', function() { 377 | expect(typeof function() {}).to.equal(/* ここに値を書き込んでください */); 378 | }); 379 | 380 | it('typeof {} の結果がわかる', function() { 381 | expect(typeof {}).to.equal(/* ここに値を書き込んでください */); 382 | }); 383 | 384 | it('typeof [] の結果がわかる', function() { 385 | expect(typeof []).to.equal(/* ここに値を書き込んでください */); 386 | }); 387 | 388 | it('typeof undefined の結果がわかる', function() { 389 | expect(typeof undefined).to.equal(/* ここに値を書き込んでください */); 390 | }); 391 | 392 | it('typeof null の結果がわかる', function() { 393 | expect(typeof null).to.equal(/* ここに値を書き込んでください */); 394 | }); 395 | }); 396 | }); 397 | -------------------------------------------------------------------------------- /public/stage1/tests.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | describe('ステージ1(意図した DOM 要素を取得できるようになる)', function() { 4 | describe('DOM インターフェース編', function() { 5 | it('1 番の赤色の要素(ID は "firebrick")が1つ取得できる', function() { 6 | 7 | // チュートリアル 8 | // 9 | // JavaScriptTraining へようこそ。 10 | // 11 | // このステージでは DOM 要素の取得を学びます。 12 | // 'change me!' を document.getElementById(elementId) に 13 | // 書き換え、ブラウザをリロードしてみてください。 14 | var elementId = 'firebrick'; 15 | var element = 'change me!'; 16 | 17 | expect(element).to.be.instanceof(HTMLElement); 18 | expect(element).to.have.property('id', elementId); 19 | 20 | // テストが green になりましたか? 21 | // では、すべてのテストが green になるように、すべてのテストを 22 | // 修正してみましょう。 23 | }); 24 | 25 | 26 | it('2 番の橙色の要素(ID は "chocolate")が1つ取得できる', function() { 27 | 28 | // 'change me!' を書き換えてください。 29 | var elementId = 'chocolate'; 30 | var element = 'change me!'; 31 | 32 | expect(element).to.be.instanceof(HTMLElement); 33 | expect(element).to.have.property('id', elementId); 34 | 35 | // 参考資料 36 | // https://developer.mozilla.org/ja/docs/Web/API/Document/getElementById 37 | }); 38 | 39 | 40 | it('3 番の緑色の要素(CSS クラス名は "mediumseagreen")が1つ取得できる', function() { 41 | 42 | // 'change me!' を書き換えてください。 43 | var elementClassName = 'mediumseagreen'; 44 | var elements = 'change me!'; 45 | 46 | expect(elements).to.have.length(1); 47 | expect(elements[0]).to.have.property('className', elementClassName); 48 | 49 | // 参考資料 50 | // https://developer.mozilla.org/ja/docs/Web/API/Document/getElementsByClassName 51 | }); 52 | 53 | 54 | it('4 番の水色の要素(CSS クラス名は "turquoise")が2つ取得できる', function() { 55 | 56 | // 'change me!' を書き換えてください。 57 | var elementClassName = 'turquoise'; 58 | var elements = 'change me!'; 59 | 60 | expect(elements).to.have.length(2); 61 | expect(elements[0]).to.have.property('className', elementClassName); 62 | expect(elements[1]).to.have.property('className', elementClassName); 63 | 64 | // 参考資料 65 | // https://developer.mozilla.org/ja/docs/Web/API/Document/getElementsByClassName 66 | }); 67 | 68 | 69 | it('5 番の青色の要素(タグ名は "blockquote")が1つ取得できる', function() { 70 | 71 | // 'change me!' を書き換えてください。 72 | var elementTagName = 'blockquote'; 73 | var elements = 'change me!'; 74 | 75 | expect(elements).to.have.length(1); 76 | expect(elements[0]).to.have.property('tagName', elementTagName.toUpperCase()); 77 | 78 | // 参考資料 79 | // https://developer.mozilla.org/ja/docs/Web/API/Document/getElementsByTagName 80 | }); 81 | }); 82 | 83 | 84 | describe('開発ツール編', function() { 85 | it('7 番の赤色の要素が1つ取得できる', function() { 86 | 87 | // チュートリアル 88 | // 89 | // ここからは、開発ツールを使って目印となる ID やクラス名を調べてみましょう。 90 | // 91 | // 調べたい要素の上で右クリック > 要素の検証をクリックします。 92 | // 93 | // すると、開発ツール上で
  • ... が選択されます。 94 | // このことから、7 番の赤色の要素の ID は brown だということがわかります。 95 | // では、'change me!' を document.getElementById('brown') に書き換えてみましょう。 96 | var element = 'change me!'; 97 | 98 | expect(element).to.have.property(secret('vq'), secret('oebja')); 99 | }); 100 | 101 | 102 | it('8 番の橙色の要素が1つ取得できる', function() { 103 | 104 | // 'change me!' を書き換えてください。 105 | var element = 'change me!'; 106 | 107 | expect(element).to.have.property(secret('vq'), secret('qnexbenatr')); 108 | }); 109 | 110 | 111 | it('9 番の緑色の要素が1つ取得できる', function() { 112 | 113 | // 'change me!' を書き換えてください。 114 | var elements = 'change me!'; 115 | 116 | expect(elements).to.have.length(1); 117 | expect(elements[0]).to.have.property(secret('pynffAnzr'), secret('yvzrterra')); 118 | }); 119 | 120 | 121 | it('10 番の水色の要素が2つ取得できる', function() { 122 | 123 | // 'change me!' を書き換えてください。 124 | var elements = 'change me!'; 125 | 126 | expect(elements).to.have.length(2); 127 | expect(elements[0]).to.have.property(secret('pynffAnzr'), secret('zrqvhzghedhbvfr')); 128 | expect(elements[1]).to.have.property(secret('pynffAnzr'), secret('zrqvhzghedhbvfr')); 129 | }); 130 | 131 | 132 | it('11 番の青色の要素が1つ取得できる', function() { 133 | 134 | // 'change me!' を書き換えてください。 135 | // 136 | // なお、11 番の青色の要素は li 要素ではありません! 137 | // よくみると、色がついているのはさらに内側の要素のようです。 138 | var elements = 'change me!'; 139 | 140 | expect(elements).to.have.length(1); 141 | expect(elements[0]).to.have.property(secret('gntAnzr'), secret('C')); 142 | }); 143 | }); 144 | 145 | 146 | describe('基本 CSS セレクタ編', function() { 147 | it('1 番の赤色の要素を querySelector を使って1つ取得できる', function() { 148 | 149 | // チュートリアル 150 | // 151 | // 次に、document.querySelector ファミリを使って、DOM 要素を取得します。 152 | // 153 | // 'change me!' を document.querySelector('#firebrick') に 154 | // 書き換えてください。 155 | var element = 'change me!'; 156 | 157 | expect(element).to.have.property(secret('vq'), secret('sveroevpx')); 158 | 159 | // 参考資料 160 | // https://developer.mozilla.org/ja/docs/DOM/Locating_DOM_elements_using_selectors 161 | }); 162 | 163 | 164 | it('2 番の橙色の要素を querySelector を使って1つ取得できる', function() { 165 | 166 | // 'change me!' を書き換えてください。 167 | var element = 'change me!'; 168 | 169 | expect(element).to.have.property(secret('vq'), secret('pubpbyngr')); 170 | 171 | // 参考資料 172 | // https://developer.mozilla.org/ja/docs/Web/CSS/Reference#Selectors 173 | }); 174 | 175 | 176 | it('3 番の緑色の要素を querySelector を使って1つ取得できる', function() { 177 | 178 | // 'change me!' を書き換えてください。 179 | var element = 'change me!'; 180 | 181 | expect(element).to.have.property(secret('pynffAnzr'), secret('zrqvhzfrnterra')); 182 | }); 183 | 184 | 185 | it('4 番の水色の要素を querySelectorAll を使って2つ取得できる', function() { 186 | 187 | // 'change me!' を書き換えてください。 188 | var elements = 'change me!'; 189 | 190 | expect(elements).to.have.length(2); 191 | expect(elements[0]).to.have.property(secret('pynffAnzr'), secret('ghedhbvfr')); 192 | expect(elements[1]).to.have.property(secret('pynffAnzr'), secret('ghedhbvfr')); 193 | }); 194 | 195 | 196 | it('5 番の青色の要素を querySelector を使って1つ取得できる', function() { 197 | 198 | // 'change me!' を書き換えてください。 199 | var element = 'change me!'; 200 | 201 | expect(element).to.have.property(secret('gntAnzr'), secret('OYBPXDHBGR')); 202 | }); 203 | 204 | 205 | it('6 番の紫色の要素を querySelector を使って1つ取得できる', function() { 206 | 207 | // 'change me!' を書き換えてください。 208 | var element = 'change me!'; 209 | 210 | expect(element).to.have.deep.property(secret('qngnfrg.wfGenvavat'), 211 | secret('oyhrivbyrg')); 212 | }); 213 | }); 214 | 215 | 216 | describe('応用 CSS セレクタ編', function() { 217 | it('7 番の赤色の要素を ID セレクタを使わずに1つ取得できる', function() { 218 | 219 | // チュートリアル 220 | // 221 | // 'change me!' を '.js-training:nth-child(2) li' 222 | // に書き換えてください。 223 | var selector = 'change me!'; 224 | 225 | var element = document.querySelector(selector); 226 | expect(selector).to.not.have.string('#'); 227 | expect(element).to.have.property(secret('vq'), secret('oebja')); 228 | }); 229 | 230 | 231 | it('8 番の橙色の要素を ID セレクタを使わずに1つ取得できる', function() { 232 | 233 | // 'change me!' を書き換えてください。 234 | var selector = 'change me!'; 235 | 236 | var element = document.querySelector(selector); 237 | expect(selector).to.not.have.string('#'); 238 | expect(element).to.have.property(secret('vq'), secret('qnexbenatr')); 239 | 240 | // 参考資料 241 | // https://developer.mozilla.org/ja/docs/Web/CSS/Reference#Selectors 242 | }); 243 | 244 | 245 | it('12 番の紫色の要素を、属性セレクタと :nth-child(N) セレクタを使わずに1つ取得できる', function() { 246 | 247 | // 'change me!' を書き換えてください。 248 | var selector = 'change me!'; 249 | 250 | var element = document.querySelector(selector); 251 | expect(selector).to.not.match(/\[\s*name\s*[~\|\^\$\*]?=/); 252 | expect(selector).to.not.have.string(':nth-child'); 253 | expect(element).to.have.deep.property(secret('qngnfrg.wfGenvavat'), 254 | secret('qnexbepuvq')); 255 | }); 256 | }); 257 | 258 | 259 | describe('jQuery 編', function() { 260 | it('7 番の赤色の要素を jQuery を使って1つ取得できる', function() { 261 | 262 | // チュートリアル 263 | // 264 | // jQuery を使って要素を取得する方法も学んでおきましょう。 265 | // 基本的な使い方は document.querySelectorAll と同じです。 266 | // 267 | // 'change me!' を $('#brown') に書き換えてください。 268 | var $element = 'change me!'; 269 | 270 | expect($element).to.be.instanceof(jQuery); 271 | expect($element).to.have.id(secret('oebja')); 272 | }); 273 | 274 | 275 | it('8 番の橙色の要素を jQuery を使って1つ取得できる', function() { 276 | 277 | // 'change me!' を書き換えてください。 278 | var $element = 'change me!'; 279 | 280 | expect($element).to.be.instanceof(jQuery); 281 | expect($element).to.have.id(secret('qnexbenatr')); 282 | 283 | // 参考情報(英語) 284 | // http://api.jquery.com/jQuery/#jQuery1 285 | }); 286 | 287 | 288 | it('9 番の緑色の要素を jQuery を使って1つ取得できる', function() { 289 | 290 | // 'change me!' を書き換えてください。 291 | var $element = 'change me!'; 292 | 293 | expect($element).to.be.instanceof(jQuery); 294 | expect($element).to.have.class(secret('yvzrterra')); 295 | }); 296 | 297 | 298 | it('10 番の水色の要素を jQuery を使って2つ取得できる', function() { 299 | 300 | // 'change me!' を書き換えてください。 301 | var $element = 'change me!'; 302 | 303 | expect($element).to.be.instanceof(jQuery); 304 | expect($element).to.have.length(2); 305 | expect($element).to.have.class(secret('zrqvhzghedhbvfr')); 306 | }); 307 | 308 | 309 | it('11 番の青色の要素を jQuery を使って1つ取得できる', function() { 310 | 311 | // 'change me!' を書き換えてください。 312 | var $element = 'change me!'; 313 | 314 | expect($element).to.be.instanceof(jQuery); 315 | expect($element).to.have.length(1); 316 | expect($element.get(0)).to.have.property(secret('gntAnzr'), secret('C')); 317 | }); 318 | 319 | 320 | it('12 番の紫色の要素を jQuery を使って1つ取得できる', function() { 321 | 322 | // 'change me!' を書き換えてください。 323 | var $element = 'change me!'; 324 | 325 | expect($element).to.be.instanceof(jQuery); 326 | expect($element).to.have.length(1); 327 | expect($element).to.have.data(secret('wfGenvavat'), 328 | secret('qnexbepuvq')); 329 | }); 330 | }); 331 | 332 | 333 | describe('エクストラステージ', function() { 334 | it('動いている寿司要素を取得する', function() { 335 | 336 | // 'change me!' を書き換えてください。 337 | var element = 'change me!'; 338 | 339 | expect(element).to.have.deep.property( 340 | secret('grkgPbagrag'), '\uD83C\uDF63'); 341 | }); 342 | }); 343 | }); 344 | 345 | 346 | function secret(str) { 347 | // Copyright (c) 2012 K.Adam White 348 | // Released under the MIT license 349 | // https://github.com/kadamwhite/jquery.rot13/blob/master/LICENSE-MIT 350 | return Array.prototype.map.call(str, function(char) { 351 | if (!char.match(/[A-Za-z]/)) { return char; } 352 | 353 | var charCode = char.charCodeAt(0); 354 | if(charCode < 97) { 355 | charCode = (charCode - 52) % 26 + 65; 356 | } else { 357 | charCode = (charCode - 84) % 26 + 97; 358 | } 359 | return String.fromCharCode(charCode); 360 | }).join(''); 361 | } 362 | -------------------------------------------------------------------------------- /server/response/friendsmap.json: -------------------------------------------------------------------------------- 1 | { 2 | "CoffeeScript": [ 3 | "Taijilang", 4 | "purescript", 5 | "Wind.js" 6 | ], 7 | "Coco": [], 8 | "LiveScript": [ 9 | "Red" 10 | ], 11 | "IcedCoffeeScript": [ 12 | "JSX" 13 | ], 14 | "Parsec CoffeeScript": [ 15 | "Six" 16 | ], 17 | "Contracts.coffee": [ 18 | "jisp" 19 | ], 20 | "Uberscript": [ 21 | "ADsafe", 22 | "Java2Script", 23 | "Chlorinejs" 24 | ], 25 | "ToffeeScript": [], 26 | "Caffeine": [], 27 | "heap.coffee": [], 28 | "EmberScript": [], 29 | "Kaffeine": [ 30 | "Quby", 31 | "O'Browser" 32 | ], 33 | "Jack": [ 34 | "Pyjs" 35 | ], 36 | "move": [ 37 | "asm.js", 38 | "WootzJs" 39 | ], 40 | "Moescript": [], 41 | "pogoscript": [ 42 | "Restrict Mode", 43 | "Opal" 44 | ], 45 | "LispyScript": [ 46 | "Continuation.js", 47 | "EdgeLisp" 48 | ], 49 | "wisp": [ 50 | "Uberscript", 51 | "Mochiscript" 52 | ], 53 | "Hot Cocoa Lisp": [ 54 | "Whalesong" 55 | ], 56 | "Sibilant": [ 57 | "node-jvm" 58 | ], 59 | "ki": [ 60 | "Contracts.coffee", 61 | "MoonScript", 62 | "Caja" 63 | ], 64 | "jisp": [], 65 | "Ham": [ 66 | "BiwaScheme" 67 | ], 68 | "GorillaScript": [], 69 | "RedScript": [ 70 | "Mascara" 71 | ], 72 | "Daonode": [], 73 | "LiteScript": [ 74 | "LispyScript", 75 | "LZX (Laszlo XML)" 76 | ], 77 | "Radium": [ 78 | "LLJS" 79 | ], 80 | "ColaScript": [ 81 | "Reb2Static" 82 | ], 83 | "Taijilang": [], 84 | "MoonScript": [ 85 | "uniter" 86 | ], 87 | "Earl Grey": [ 88 | "CirruScript", 89 | "JSX" 90 | ], 91 | "Khepri": [], 92 | "Spider": [ 93 | "Sibilant", 94 | "jmacro", 95 | "phype" 96 | ], 97 | "CirruScript": [], 98 | "Stripes": [ 99 | "Cheerp", 100 | "Gnusto" 101 | ], 102 | "Caja": [], 103 | "ADsafe": [], 104 | "FBJS": [ 105 | "Skulpt" 106 | ], 107 | "Jacaranda": [ 108 | "AtScript" 109 | ], 110 | "Microsoft Web Sandbox": [ 111 | "Flapjax" 112 | ], 113 | "Gatekeeper": [ 114 | "Local.js", 115 | "MileScript", 116 | "scalagwt" 117 | ], 118 | "Dojo Secure": [ 119 | "PythonJS" 120 | ], 121 | "Local.js": [ 122 | "JSPipe", 123 | "PyCow", 124 | "JScriptSuite" 125 | ], 126 | "Dart": [ 127 | "Moescript" 128 | ], 129 | "TypeScript": [], 130 | "TeJaS": [ 131 | "TypeScript" 132 | ], 133 | "asm.js": [], 134 | "JavaScript++": [ 135 | "Js_of_ocaml" 136 | ], 137 | "MileScript": [ 138 | "WebSharper", 139 | "JsMaker", 140 | "Meemoo" 141 | ], 142 | "Mascara": [ 143 | "Parsec CoffeeScript" 144 | ], 145 | "Roy": [ 146 | "Swym" 147 | ], 148 | "Elm": [ 149 | "Silver Smalltalk" 150 | ], 151 | "JSX": [ 152 | "Ralph", 153 | "LispyScript" 154 | ], 155 | "Este.js": [ 156 | "Dart", 157 | "ColdRuby", 158 | "Go2js" 159 | ], 160 | "Swym": [ 161 | "GWT" 162 | ], 163 | "Typecast.js": [ 164 | "Oppo" 165 | ], 166 | "purescript": [ 167 | "ScriptBlocks" 168 | ], 169 | "AtScript": [ 170 | "EmberScript", 171 | "Netjs", 172 | "haste", 173 | "Amber" 174 | ], 175 | "Flow": [], 176 | "Streamline.js": [ 177 | "Objective-J", 178 | "Mandreel", 179 | "GopherJS" 180 | ], 181 | "mobl": [ 182 | "JavaScript++" 183 | ], 184 | "StratifiedJS": [ 185 | "Outlet" 186 | ], 187 | "NarrativeJS": [ 188 | "Flow" 189 | ], 190 | "jwacs": [ 191 | "sql-parser", 192 | "Dogescript" 193 | ], 194 | "Wind.js": [], 195 | "TameJS": [ 196 | "TIScript", 197 | "jshaskell", 198 | "Smart Mobile Studio", 199 | "browserl" 200 | ], 201 | "Continuation.js": [ 202 | "wisp", 203 | "FunScript" 204 | ], 205 | "Kal": [ 206 | "Streamline.js", 207 | "rb2js", 208 | "Ur", 209 | "wForth" 210 | ], 211 | "JSPipe": [], 212 | "promiseLand": [ 213 | "pythonscript" 214 | ], 215 | "ContextJS": [], 216 | "Objective-J": [ 217 | "Elm" 218 | ], 219 | "Mochiscript": [], 220 | "jangaroo": [], 221 | "Flapjax": [], 222 | "jLang": [ 223 | "move" 224 | ], 225 | "Restrict Mode": [], 226 | "TIScript": [ 227 | "NemerleWeb" 228 | ], 229 | "Six": [ 230 | "qb.js" 231 | ], 232 | "js--": [ 233 | "IcedCoffeeScript", 234 | "Radium" 235 | ], 236 | "Latte JS": [ 237 | "RapydScript", 238 | "Blue Storm" 239 | ], 240 | "oj": [ 241 | "heap.coffee", 242 | "Pit" 243 | ], 244 | "Opal": [], 245 | "HotRuby": [], 246 | "ColdRuby": [ 247 | "Jack" 248 | ], 249 | "rb2js": [ 250 | "ContextJS" 251 | ], 252 | "RubyJS": [], 253 | "Red": [ 254 | "GorillaScript", 255 | "QWT", 256 | "Clamato" 257 | ], 258 | "Quby": [ 259 | "Moby Scheme" 260 | ], 261 | "8ball": [ 262 | "sqld3", 263 | "uilang" 264 | ], 265 | "PYXC-PJ": [ 266 | "NarrativeJS" 267 | ], 268 | "Pyjamas": [], 269 | "Pyjaco": [ 270 | "Typecast.js", 271 | "Latte JS" 272 | ], 273 | "Pyjs": [ 274 | "js--", 275 | "p2js" 276 | ], 277 | "Skulpt": [], 278 | "PyCow": [ 279 | "LuvvieScript" 280 | ], 281 | "PyvaScript": [], 282 | "RapydScript": [], 283 | "Brython": [ 284 | "Plaid" 285 | ], 286 | "PythonScript": [ 287 | "E" 288 | ], 289 | "pythonscript": [ 290 | "mobl", 291 | "jsForth" 292 | ], 293 | "PythonJS": [ 294 | "Gatekeeper", 295 | "Clue" 296 | ], 297 | "PyPyJS": [ 298 | "RubyJS" 299 | ], 300 | "Shen": [ 301 | "jisp", 302 | "TeJaS" 303 | ], 304 | "LuvvieScript": [], 305 | "Perlito": [ 306 | "Processing" 307 | ], 308 | "GWT": [], 309 | "Java2Script": [ 310 | "Topaz" 311 | ], 312 | "j2js": [ 313 | "jwacs", 314 | "Fun" 315 | ], 316 | "BicaJVM": [ 317 | "Nimrod" 318 | ], 319 | "Doppio": [ 320 | "Shen" 321 | ], 322 | "Processing": [ 323 | "Perlito", 324 | "NoFlo", 325 | "Agda" 326 | ], 327 | "Kotlin": [], 328 | "Ceylon": [ 329 | "DuoCode" 330 | ], 331 | "GrooScript": [ 332 | "jLang" 333 | ], 334 | "node-jvm": [ 335 | "LiteScript", 336 | "JSIL" 337 | ], 338 | "Bck2Brwsr": [], 339 | "QWT": [ 340 | "Spider", 341 | "Ceylon", 342 | "ErlyJS" 343 | ], 344 | "TeaVM": [ 345 | "Khepri" 346 | ], 347 | "Dragome SDK": [ 348 | "NGN APL" 349 | ], 350 | "Scala.js": [ 351 | "Jacaranda" 352 | ], 353 | "js-scala": [], 354 | "scalagwt": [ 355 | "Opa", 356 | "Waterbear" 357 | ], 358 | "JScala": [], 359 | "jsc": [], 360 | "JSIL": [ 361 | "HotRuby" 362 | ], 363 | "Script#": [ 364 | "forml" 365 | ], 366 | "Prefix": [ 367 | "Este.js", 368 | "JScala" 369 | ], 370 | "Blade": [ 371 | "CoffeeScript", 372 | "Kotlin" 373 | ], 374 | "SharpKit": [ 375 | "Scala.js", 376 | "ki" 377 | ], 378 | "Saltarelle": [ 379 | "Script#", 380 | "NS Basic/App Studio" 381 | ], 382 | "FunScript": [], 383 | "Pit": [], 384 | "WebSharper": [], 385 | "NemerleWeb": [ 386 | "Illumination" 387 | ], 388 | "Blue Storm": [], 389 | "JScriptSuite": [ 390 | "Brython" 391 | ], 392 | "DotNetWebToolkit": [ 393 | "Snap", 394 | "Logo Interpreter" 395 | ], 396 | "Netjs": [], 397 | "WootzJs": [], 398 | "DuoCode": [ 399 | "Scriptjure", 400 | "TARDISgo", 401 | "XLCC" 402 | ], 403 | "ClojureScript": [], 404 | "ClojureJS": [ 405 | "ghcjs", 406 | "Wortel" 407 | ], 408 | "Chlorinejs": [ 409 | "Sibilant" 410 | ], 411 | "Scriptjure": [ 412 | "Microsoft Web Sandbox", 413 | "Pyjamas" 414 | ], 415 | "BiwaScheme": [ 416 | "StratifiedJS", 417 | "Blade" 418 | ], 419 | "Fargo": [ 420 | "Roy", 421 | "Brozula" 422 | ], 423 | "Moby Scheme": [], 424 | "nconc": [ 425 | "BicaJVM", 426 | "Blockly" 427 | ], 428 | "scheme2js": [ 429 | "8ball" 430 | ], 431 | "Spock": [], 432 | "Whalesong": [ 433 | "Daonode" 434 | ], 435 | "EdgeLisp": [], 436 | "Parenscript": [ 437 | "Parenscript", 438 | "Little Smallscript" 439 | ], 440 | "Ralph": [ 441 | "Kal" 442 | ], 443 | "Oppo": [ 444 | "Fantom", 445 | "CobolScript" 446 | ], 447 | "Outlet": [ 448 | "Bck2Brwsr", 449 | "lua.js" 450 | ], 451 | "Ocamljs": [], 452 | "O'Browser": [ 453 | "defrac" 454 | ], 455 | "Js_of_ocaml": [ 456 | "TameJS" 457 | ], 458 | "UHC": [], 459 | "ghcjs": [ 460 | "DotNetWebToolkit" 461 | ], 462 | "jmacro": [], 463 | "YHC": [], 464 | "jshaskell": [], 465 | "haste": [], 466 | "fay": [ 467 | "TeaVM" 468 | ], 469 | "forml": [], 470 | "Amber": [ 471 | "ToffeeScript", 472 | "PyvaScript", 473 | "Dragome SDK", 474 | "Fargo" 475 | ], 476 | "Clamato": [], 477 | "Silver Smalltalk": [ 478 | "SqueakJS" 479 | ], 480 | "Lively Kernel": [ 481 | "php.js" 482 | ], 483 | "Little Smallscript": [], 484 | "SqueakJS": [], 485 | "Emscripten": [], 486 | "Cheerp": [ 487 | "Spock", 488 | "UHC" 489 | ], 490 | "maja": [ 491 | "ki", 492 | "Pygmy" 493 | ], 494 | "Clue": [ 495 | "Coco" 496 | ], 497 | "LLJS": [ 498 | "oj", 499 | "scheme2js" 500 | ], 501 | "Mandreel": [], 502 | "NS Basic/App Studio": [ 503 | "promiseLand" 504 | ], 505 | "qb.js": [ 506 | "SMLtoJs" 507 | ], 508 | "Smart Mobile Studio": [ 509 | "RedScript" 510 | ], 511 | "Elevate Web Builder": [ 512 | "LiveScript", 513 | "SharpKit" 514 | ], 515 | "Go2js": [ 516 | "FBJS", 517 | "ClojureJS" 518 | ], 519 | "GopherJS": [ 520 | "ColaScript" 521 | ], 522 | "TARDISgo": [ 523 | "Monkey" 524 | ], 525 | "Haxe": [], 526 | "Fantom": [], 527 | "LZX (Laszlo XML)": [], 528 | "Nimrod": [ 529 | "Ocamljs" 530 | ], 531 | "Monkey": [ 532 | "Emscripten" 533 | ], 534 | "defrac": [ 535 | "mobl" 536 | ], 537 | "Fun": [], 538 | "Ur": [ 539 | "Pyjaco", 540 | "Elevate Web Builder" 541 | ], 542 | "E": [ 543 | "Doppio", 544 | "Jotlin" 545 | ], 546 | "Sugar": [ 547 | "PYXC-PJ" 548 | ], 549 | "Opa": [], 550 | "Waterbear": [ 551 | "Oia" 552 | ], 553 | "Snap": [ 554 | "pogoscript", 555 | "PyPyJS", 556 | "jsc" 557 | ], 558 | "ScriptBlocks": [ 559 | "jangaroo" 560 | ], 561 | "Illumination": [], 562 | "JsMaker": [], 563 | "Meemoo": [ 564 | "maja" 565 | ], 566 | "NoFlo": [], 567 | "Blockly": [], 568 | "Maeda Block": [ 569 | "GrooScript" 570 | ], 571 | "sql-parser": [ 572 | "Caffeine" 573 | ], 574 | "sqld3": [ 575 | "ClojureScript" 576 | ], 577 | "Alasql": [ 578 | "Lively Kernel" 579 | ], 580 | "phype": [ 581 | "js-scala", 582 | "Saltarelle" 583 | ], 584 | "uniter": [], 585 | "php.js": [], 586 | "Oia": [], 587 | "Plaid": [], 588 | "Quixe": [], 589 | "Gnusto": [ 590 | "Dojo Secure", 591 | "Idris" 592 | ], 593 | "Logo Interpreter": [], 594 | "p2js": [ 595 | "Kaffeine", 596 | "Haxe" 597 | ], 598 | "Reb2Static": [ 599 | "Earl Grey", 600 | "Hot Cocoa Lisp", 601 | "fay" 602 | ], 603 | "RPN": [ 604 | "Hot Cocoa Lisp" 605 | ], 606 | "jsForth": [ 607 | "PythonScript" 608 | ], 609 | "wForth": [ 610 | "Stripes", 611 | "Prefix" 612 | ], 613 | "Agda": [], 614 | "XLCC": [ 615 | "Alasql", 616 | "Quixe" 617 | ], 618 | "SMLtoJs": [], 619 | "lua.js": [ 620 | "nconc" 621 | ], 622 | "Brozula": [], 623 | "Pygmy": [ 624 | "Maeda Block" 625 | ], 626 | "browserl": [ 627 | "wisp" 628 | ], 629 | "ErlyJS": [], 630 | "Topaz": [], 631 | "NGN APL": [], 632 | "CobolScript": [], 633 | "Idris": [ 634 | "Ham" 635 | ], 636 | "Dogescript": [], 637 | "Wortel": [ 638 | "j2js" 639 | ], 640 | "JEnglish": [ 641 | "RPN", 642 | "JEnglish" 643 | ], 644 | "Jotlin": [ 645 | "YHC", 646 | "Sugar" 647 | ], 648 | "uilang": [] 649 | } 650 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2日でできる JavaScriptTraining 2 | ============================== 3 | 4 | JavaScript 初心者が JS の未来を見据えつつ、 5 | 基礎をひととおり身に付けるための資料です。 6 | 7 | 8 | 9 | この README は `npm run presentation` で 10 | 再生することができます。 11 | 12 | 13 | 14 | 解答・解説について 15 | ------------------ 16 | 17 | 解答は [2015-example-solution](https://github.com/mixi-inc/JavaScriptTraining/compare/2015...2015-example-solution) で見られます! 18 | 19 | 20 | 21 | トレーニングの目標 22 | ------------------ 23 | 24 | 25 | 26 | このトレーニングの目標は、 27 | **モジュールを読み書きできるようになり、** 28 | 自分の好きなモジュールを 29 | つくれるようになることです。 30 | 31 | 32 | 33 | トレーニングの前に、セットアップを 34 | 終わらせてしまいましょう。 35 | 36 | 37 | 38 | セットアップ 39 | ------------ 40 | 41 | 42 | 43 | ### 1. 環境をセットアップ 44 | 45 | この研修では [Google Chrome](https://www.google.co.jp/chrome/browser/desktop/index.html) を利用します。 46 | 上のリンクから Chrome をインストールしてください。 47 | 48 | [Node.js](http://nodejs.jp/nodejs.org_ja/) も利用しています。 49 | こちらも上のリンクからインストールしてください。 50 | 51 | 52 | 53 | ### 2. JavaScriptTraining を fork 54 | 55 | JavaScriptTraining の学習履歴を残すために、 56 | JavaScriptTraining リポジトリを fork します。 57 | 58 | 画面右上にある fork ボタンを押してください。 59 | 60 | [](http://mixi-inc.github.io/JavaScriptTraining/images/fork-button.png) 61 | 62 | 63 | 64 | ### 3. 必要なものをダウンロード 65 | 66 | ここからはターミナル上での操作になります。 67 | リポジトリの URL をコピーし、下のコマンドを 68 | ターミナルで実行してください。 69 | 70 | git clone コピーしたURL 71 | 72 | 73 | 74 | ### 4. セットアップ 75 | 76 | 下のコマンドをターミナルで実行してください。 77 | 78 | cd JavaScriptTraining 79 | npm install 80 | 81 | 82 | 83 | ### 5. webサーバーを立ち上げる 84 | 85 | 下のコマンドをターミナルで実行してください。 86 | 87 | なお、トレーニング中はこのコマンドを 88 | 終了しないでください。 89 | 90 | npm start 91 | 92 | 93 | 94 | ### 6. トップページにアクセスする 95 | 96 | ブラウザから [http://localhost:8000](http://localhost:8000) へ 97 | アクセスしてください。 98 | 99 | トレーニングの一覧が表示されていれば完了です。 100 | 101 | 102 | 103 | トレーニング前レクチャー 104 | ------------------------ 105 | 106 | 107 | 108 | ### JavaScript とは 109 | 110 | > JavaScript はウェブの言語です。 111 | > 112 | > ウェブページにある特定の要素を 113 | > 操作する手段として始まりましたが、 114 | > 途方もなく成長しました。 115 | > 116 | > (JavaScript パターン, O'Reilly) 117 | 118 | 119 | 120 | ### JavaScript のすごいところ 121 | 122 | > クラスというものがなく、 123 | > 第一級オブジェクトである関数が 124 | > 多くの仕事に使われます。 125 | > 126 | > (JavaScript パターン, O'Reilly) 127 | 128 | 129 | 130 | > Java や PHP が追加しはじめた 131 | > クロージャーや無名関数といった 132 | > 機能は、JavaScript 開発者が 133 | > 楽しんできた機能であり、 134 | > あるのが当然だと思われていました。 135 | > 136 | > (JavaScript パターン, O'Reilly) 137 | 138 | 139 | 140 | ### 楽しんできた機能??? 141 | 142 | ```javascript 143 | ['Foo', 'Bar', 'Buz'].forEach(function(name) { 144 | console.log('hello ' + name); 145 | }); 146 | ``` 147 | 148 | (クロージャーはトレーニングで扱います) 149 | 150 | 151 | 152 | ### JavaScript はどこで動くのか 153 | 154 | - Web ブラウザ 155 | - Node.js, io.js 156 | 157 | JavaScript の特色のひとつは、ブラウザ上で 158 | 動作するということです。ブラウザ上で動作できる 159 | 言語はいくつかありますが、一般的に 160 | JavaScript がよく使われます。 161 | 162 | 163 | 164 | ### いつ JavaScript を使うのか 165 | 166 | - Web ページに独自の動きをつけたいとき 167 | 168 | (一部は CSS でできます) 169 | 170 | - ページ遷移なしにサーバーと通信したいとき 171 | - パフォーマンスチューニング 172 | - フロントエンドエコシステム使いたいとき 173 | 174 | (タスクランナーとかパッケージマネージャ) 175 | 176 | 177 | 178 | ### JavaScript を使うと… 179 | 180 | - アニメーションの例: [Si digital](http://sidigital.co/) 181 | - インタラクションの例: [Vim.js](http://coolwanglu.github.io/vim.js/emterpreter/vim.html) 182 | - Web API の例: [Google Map](https://www.google.co.jp/maps) 183 | 184 | 185 | 186 | JavaScript に会いにいこう 187 | ------------------------- 188 | 189 | 190 | 191 | ### 1. 開発ツールを開く 192 | 193 | Chrome で [http://localhost:8000](http://localhost:8000) を開きます。 194 | 195 | Web ページの適当な場所で 196 | 右クリック > 要素の検証 197 | 198 | または 199 | 200 | - Mac の人: ⌘ + ⌥ + i 201 | - Windows の人:Ctrl + Shift + i 202 | 203 | 204 | 205 | ### 2. Console を開く 206 | 207 | 開発ツールを選択し、Esc キーを 208 | 数回おしてみてください。 209 | 210 | すると、下に Console が出てきます。 211 | この Console から、JavaScript を 212 | 実行することができます。 213 | 214 | [](http://mixi-inc.github.io/JavaScriptTraining/images/console.png) 215 | 216 | 217 | 218 | ### 3. 何か実行してみる 219 | 220 | 試しに `alert('Foo');` と実行してみてください。 221 | 222 | アラートポップアップが表示されます。 223 | 224 | 225 | 226 | ### 4. 計算させてみる 227 | 228 | `1 + 1` や `'Foo' + 'Bar'` なども実行できますね。 229 | 230 | 231 | 232 | ### 5. 変数代入・参照してみる 233 | 234 | 変数代入・参照もできますね。 235 | 236 | ```javascript 237 | var foo = 'bar'; 238 | foo; 239 | ``` 240 | 241 | 242 | 243 | ### 6. ブラウザオブジェクトをいじる 244 | 245 | ブラウザオブジェクトもいじってみましょう。 246 | 247 | ```javascript 248 | document.title = 'あなたとjava 今すぐダウンロード'; 249 | ``` 250 | 251 | Chrome のタブ名が書き変わりました。 252 | 253 | 254 | 255 | ### 7. ページを再読み込みすると戻る 256 | 257 | ページを再読み込みしてみてください。 258 | 259 | これまでの変更はすべてリセットされます。 260 | (つまり、この方法で本番リリースは 261 | できないということですね!) 262 | 263 | 264 | 265 | ### 8. JavaScript とここで会える 266 | 267 | - スクリプト読み込みパターン(推奨) 268 | 269 | <script src="foo.js"></script> 270 | 271 | - インラインパターン 272 | 273 | <script>alert('inline!');</script> 274 | 275 | - インラインイベントハンドラーパターン 276 | 277 | <img src="buz.png" onerror="alert('onerror!')"> 278 | 279 | - ブックマークレットパターン 280 | 281 | <a href="javascript: alert('bookmarklet!')"></a> 282 | 283 | 284 | 285 | 開発環境道場 286 | ------------ 287 | 288 | (あるいはポエム) 289 | 290 | 291 | 292 | JavaScript を効率的に書けるようにするために 293 | 最低限の開発環境を整えます。 294 | 295 | 296 | 297 | JavaScript に精通していない人に 298 | 「どんなツールを使ったらいいですか?」と 299 | 聞かれることがよくあります。 300 | 301 | 私は「構文ハイライトと lint を使うといいですよ」、 302 | と答えることにしています。 303 | 304 | [](http://mixi-inc.github.io/JavaScriptTraining/images/syntax-error.png) 305 | 306 | 307 | 308 | ひとつエピソードを紹介します。 309 | 310 | 311 | 312 | JavaScript には静的型検査がないことや、 313 | 記号が多い構文や、まずい仕様がいくつもあるので、 314 | ミスを犯しやすい言語の一つです。 315 | 316 | 317 | 318 | たとえば、JavaScript には `"use strict"` という 319 | 宣言があります。この宣言は JavaScript の 320 | まずい仕様の一部をエラーにすることで修正を 321 | 促す効果があり、よく記述を推奨される宣言です。 322 | 323 | 324 | 325 | あるプロジェクトで気を利かした 326 | プログラマーが `"use strict"` を 327 | 新しいスクリプトで使い始めました。 328 | 329 | ```javascript 330 | "use strict"; 331 | 332 | // Do something... 333 | ``` 334 | 335 | これは、開発時のミスを早期発見できるように 336 | するよい方法です! 337 | 338 | 339 | 340 | しかし、リリース後、新しいスクリプトとは 341 | 関係ないはずの JavaScript による 342 | メニューが動作しなくなっていました。 343 | 344 | なぜでしょうか? 345 | 346 | 347 | 348 | これは、パフォーマンスチューニングの一環で 349 | 複数の JavaScript ファイルを結合していたこと、 350 | ファイルに対する `"use strict"` を利用していた 351 | ことの2つが原因となって起きた不具合です。 352 | 353 | `"use strict"` が結合された 354 | すべてのファイル全体に効くように 355 | なり、`"use strict"` に対応していない 356 | 古いファイルがエラーを出すように 357 | なってしまっていたのでした。 358 | 359 | 360 | 361 | このエピソードは、いわゆる**初見殺し**です。 362 | 363 | 「何それどうしてそんな仕様なの😱」 364 | と言いたくなりますね。 365 | 366 | 367 | 368 | 悲しいことに、このような落とし穴は 369 | JavaScript の仕様・文化に数多く 370 | 潜んでいます。 371 | 372 | これらのミスをどのようにしたら 373 | 防げるのでしょうか? 374 | 375 | 376 | 377 | [ESLint](http://eslint.org/) や [JSHint](http://jshint.com/)、 [JSLint](http://www.jslint.com/) のような lint を 378 | 使いましょう。 379 | 380 | たとえば、ESLint を実行すると 381 | 下のような警告が出されます。これによって、 382 | 潜在的な不具合をだいぶ減らせるようになるのです。 383 | 384 | Use the function form of "use strict". 385 | (関数形式の "use strict" を使ってね) 386 | 387 | 388 | 389 | ミスを防ぐためには、「頑張る」とか 390 | 「注意する」のような精神論ではなく、 391 | lint によって防止することが必要です。 392 | あなたが JavaScript にまだ精通していないので 393 | あれば、真っ先にいれるべきは lint なのです。 394 | 395 | 396 | 397 | 1. lint をかけてみる 398 | 399 | ターミナルで下のコマンドを実行してください。 400 | ESLint が実行されます。 401 | 402 | npm run lint-stage-1 403 | 404 | 2. 構文ハイライトを効かせる 405 | 406 | ほとんどのエディタは構文ハイライトを 407 | サポートしています。Vim のように 408 | 構文ハイライトが選べるのであれば、 409 | よりミスのわかりやすい構文ハイライトを 410 | 利用します。 411 | 412 | 413 | 414 | トレーニング 415 | ------------ 416 | 417 | 418 | 419 | ### ステージ1 420 | 421 | DOM 要素を取得するトレーニング 422 | 423 | 424 | 425 | #### DOM とは 426 | 427 | Web ページは HTML のタグによって 428 | 構成されています。 429 | 430 | [](http://mixi-inc.github.io/JavaScriptTraining/images/github.png) 431 | [](http://mixi-inc.github.io/JavaScriptTraining/images/github-elements.png) 432 | 433 | この 3D ビューを見ると、複数の HTML タグから 434 | Web ページが構成されていることがよくわかります。 435 | 436 | 437 | 438 | この HTML タグは下のような木構造をとっています。 439 | 440 | [](http://mixi-inc.github.io/JavaScriptTraining/images/github-elements.png) 441 | [](http://mixi-inc.github.io/JavaScriptTraining/images/github-tree.png) 442 | 443 | 実際に、[mixi-inc/JavaScriptTraining](https://github.com/mixi-inc/JavaScriptTraining) を開き、 444 | 開発コンソールのElement タブに表示されている 445 | 構造を確認してみてください。 446 | 447 | 448 | 449 | DOM (Document Object Model) は、この HTML のタグを 450 | JavaScript の世界で操作することができる API です。 451 | 452 | HTML タグは、JavaScript の世界で 453 | DOM 要素というオブジェクトとして扱われます。 454 | 455 | 456 | 457 | [](http://mixi-inc.github.io/JavaScriptTraining/images/github-tree.png) 458 | 459 | HTML のタグを JavaScript 側で操作するためには 460 | HTML のタグを HTML 文書から取り出し、 461 | JavaScript の世界へと取ってこなければなりません。 462 | 463 | このステージでは、HTML から DOM 要素を 464 | 取得するという操作について学びます。 465 | 466 | 467 | 468 | HTML タグには、目印となるいくつかの情報が 469 | 付属しています。たとえば、下の div タグには 470 | ID 属性が付属しています。 471 | 472 | ```html 473 |
    foo
    474 | ``` 475 | 476 | JavaScript はこの目印を DOM API に渡すことで、 477 | DOM 要素を取得することができます。 478 | 479 | ```javascript 480 | var div = document.getElementById('foo'); 481 | ``` 482 | 483 | 484 | 485 | 他にも CSS クラスやタグ名、その他の属性から、 486 | DOM 要素を取得することができます。 487 | 488 | ```html 489 |
    foo
    490 | ``` 491 | 492 | 493 | 494 | #### CSS セレクタについて 495 | 496 | また、目印の指定の仕方のひとつに、 497 | CSS セレクタがあります。 498 | 499 | たとえば、`foo` という ID のついたタグであれば、 500 | 501 | ```html 502 |
    foo
    503 | ``` 504 | 505 | ```javascript 506 | var div = document.querySelector('#foo'); 507 | ``` 508 | 509 | というように、ID の先頭に `#` をつけた 510 | IDセレクタ `#foo` で、取得したい DOM 要素を指示します。 511 | 512 | 513 | 514 | この方法の利点は、複雑な位置にある DOM 要素を 515 | 取得することができるということでしょう。 516 | 517 | 下の HTML の bar を包む `div` タグにあたる 518 | DOM 要素を取得する場合、 519 | 520 | ```html 521 |
    522 |
    foo
    523 |
    bar
    524 |
    525 | ``` 526 | 527 | ```javascript 528 | var div = document.querySelector('.foo div:last-child'); 529 | ``` 530 | 531 | というように、CSS クラスセレクタ `.foo` に 532 | 該当する要素の子要素を子孫セレクタ (スペース) で 533 | 取得し、このうち `div` タグから CSS 疑似セレクタ 534 | `:last-child` にマッチするものを取得する 535 | という操作になります。 536 | 537 | 538 | 539 | 図にすると、このようになります。 540 | 541 | [](http://mixi-inc.github.io/JavaScriptTraining/images/css-selector-example.png) 542 | 543 | CSS セレクタについては、[MDN のCSS リファレンス](https://developer.mozilla.org/ja/docs/Web/CSS/Reference#Selectors) が 544 | 参考になります。 545 | 546 | 仕様を見ないと我慢ならぬ!という立派な方は、 547 | [セレクタ Level 3 仕様](http://standards.mitsue.co.jp/resources/w3c/TR/css3-selectors/) を見るとよいでしょう。 548 | 549 | 550 | 551 | #### 実習 552 | 553 | 下のテストが green になるように、 554 | `public/stage1/tests.js` を 555 | 修正してください。 556 | 557 | [http://localhost:8000/stage1/](http://localhost:8000/stage1/) 558 | 559 | 560 | 561 | #### クリアできたら 562 | 563 | Lint をかけてみましょう。 564 | 565 | npm run lint-stage-1 566 | 567 | 警告があれば、修正してみてください。 568 | 569 | 570 | 571 | ### ステージ2 572 | 573 | DOM 要素の属性・テキストを変更する 574 | トレーニング 575 | 576 | 577 | 578 | このステージでは、スタイルの変更や 579 | 表示文字列を変更するやり方を学びます。 580 | 581 | 582 | 583 | #### DOM 要素の属性・テキスト 584 | 585 | DOM 要素には、 586 | 587 | - 先ほど DOM API に渡した ID 属性 588 | - CSS クラス属性などの目印となる属性 589 | - 見た目を操作するスタイル属性 590 | 591 | などが付属しています。 592 | 593 | (DOM の属性の一覧は [MDN DOM リファレンス](https://developer.mozilla.org/ja/docs/DOM/DOM_Reference) を 594 | 参照してください) 595 | 596 | 597 | 598 | このうち、スタイル属性を編集すると、DOM 要素の 599 | 見た目を変化させることができます。 600 | 601 | たとえば、Github のヘッダの octocat の 602 | style.color 属性を変更してみました。 603 | 604 | [](http://mixi-inc.github.io/JavaScriptTraining/images/octocats.png) 605 | 606 | 607 | 608 | このスタイル属性は CSS の仕様と対応するように 609 | 定められています。 610 | 611 | ただ、アニメーションを含め、見た目の変更は 612 | CSS クラス名の追加/編集/削除によっておこなう 613 | ことが推奨されてきています。 614 | 615 | ([レンダリングエンジンによる最適化が効くのです!](https://developer.mozilla.org/ja/docs/Web/Guide/CSS/Using_CSS_animations)) 616 | 617 | JavaScript は見た目の変更のきっかけを 618 | 与えるだけにとどめるのが、上手な 619 | HTML/JavaScript/CSS 分業の基本です。 620 | 621 | 622 | 623 | 残念なお知らせですが、 624 | 今回のトレーニングは CSS を 625 | 書けるようになることが目的ではないので、 626 | レガシーな element.style を編集するやり方を 627 | 学びます。 628 | 629 | 630 | 631 | レガシー… 😱 632 | 633 | 634 | 635 | まあ、肩を落とさないでください。 636 | 637 | レガシーとはいえ、レガシーブラウザーを 638 | 相手にするライブラリを読み書きするときには、 639 | どうしても必要になります。 640 | 641 | ちなみに、「レガシー?帰らせていただきます」は 642 | フロントエンドエンジニアとして大切な感覚ですので 643 | 大事にしてください。 644 | 645 | 646 | 647 | #### 実習 648 | 649 | 下のテストが green になるように、 650 | `public/stage2/tests.js` を 651 | 修正してください。 652 | 653 | [http://localhost:8000/stage2/](http://localhost:8000/stage2/) 654 | 655 | 656 | 657 | #### クリアできたら 658 | 659 | Lint をかけてみましょう。 660 | 661 | npm run lint-stage-2 662 | 663 | 警告があれば、修正してみてください。 664 | 665 | 666 | 667 | ### ステージ3 668 | 669 | DOM の構造を変更するトレーニング 670 | 671 | 672 | 673 | #### DOM の構造 674 | 675 | このステージでは、DOM の属性ではなく、 676 | 構造を変更するトレーニングをおこないます。 677 | 678 | たとえば、書籍を検索する Web API を使って、 679 | 書籍検索サービスを開発することを例に、 680 | DOM の構造を変更する必要性を考えてみます。 681 | 682 | 683 | 684 | 書籍検索サービスの API は、検索結果を 685 | 下のように返したとしましょう。 686 | 687 | ```javascript 688 | [ 689 | { 690 | "title": "紅", 691 | "score": 5 692 | }, 693 | { 694 | "title": "円環少女", 695 | "score": 5 696 | }, 697 | { 698 | "title": "SHI-NO -シノ- 黒き魂の少女", 699 | "score": 5 700 | }, 701 | ... 702 | ] 703 | ``` 704 | 705 | 706 | 707 | このとき、画面に表示するために下のような HTML を 708 | 追加することになります。 709 | 710 | ```html 711 | 726 | ``` 727 | 728 | 729 | 730 | サーバー側で上のような HTML を 731 | 生成してもよいのですが、 732 | JavaScript による DOM 構造の操作に 733 | よって実現させることができれば、 734 | 軽快な書籍検索サービスをつくることができます。 735 | 736 | (ページのリロードが必要ないからですね!) 737 | 738 | 739 | 740 | このように、Web サービスの使いやすさを 741 | 追求するためには、JavaScript による 742 | DOM 構造の操作が重要なのです。 743 | 744 | 745 | 746 | #### 実習 747 | 748 | 下のテストが green になるように、 749 | `public/stage3/tests.js` を 750 | 修正してください。 751 | 752 | [http://localhost:8000/stage3/](http://localhost:8000/stage3/) 753 | 754 | 755 | 756 | #### クリアできたら 757 | 758 | Lint をかけてみましょう。 759 | 760 | npm run lint-stage-3 761 | 762 | 警告があれば、修正してみてください。 763 | 764 | 765 | 766 | ### ステージ4 767 | 768 | DOM イベントを利用するトレーニング 769 | 770 | 771 | 772 | ### DOM イベント解説編 773 | 774 | ユーザーがボタンを押したり、 775 | 検索欄に入力したとき、JavaScript は 776 | DOM イベントをうけとることができます。 777 | 778 | たとえば、下のボタンは click イベントを 779 | 引きがねとして、DOM 構造を書き換えます。 780 | 781 |
    782 | 783 | 784 | 785 | click イベント以外にも多様なイベントがあります: 786 | 787 | - dblclick: 要素上でダブルクリックされたとき 788 | - mousemove: 要素上でポインタが移動しているとき 789 | - scroll: 画面がスクロールされたとき 790 | - unload: 次のページに遷移する直前 791 | - keydown: キーボードが押されたとき 792 | - animationstart: CSS アニメーションが開始したとき 793 | - offline: ブラウザがオフラインになったとき 794 | 795 | ここに載っていないイベントの一覧は 796 | [MDN DOM イベントリファレンス](https://developer.mozilla.org/ja/docs/Web/Reference/Events) を 797 | 参照するとよいでしょう。 798 | 799 | 800 | 801 | 試しに、このページを制御する JavaScript が 802 | 監視しているイベントを見てみましょう。 803 | 804 | 開発ツールを開き、Elements タブの中段にある 805 | Event Listeners タブを開いてみてください。 806 | 807 | 808 | 809 | [](http://mixi-inc.github.io/JavaScriptTraining/images/chrome-dev-tool-event-debugging.png) 810 | 811 | たくさんのイベントが登録されていますね。 812 | 813 | では、これらのイベントの使い方を解説していきます。 814 | 815 | 816 | 817 | #### DOM イベント実装編 818 | 819 | DOM のイベントを JavaScript 側で監視するには、 820 | いくつかの方法があります。 821 | 822 | - addEventListener スタイル 823 | 824 | ```javascript 825 | var button = document.getElementById('button'); 826 | button.addEventListener('click', function(event) { 827 | console.log(event); 828 | }); 829 | ``` 830 | 831 | - インラインイベントハンドラースタイル 832 | 833 | ```html 834 | 835 | ``` 836 | 837 | - イベント属性スタイル(レガシー) 838 | 839 | ```javascript 840 | var button = document.getElementById('button'); 841 | button.onclick = function(event) { 842 | console.log(event); 843 | }; 844 | ``` 845 | 846 | 847 | 848 | このうち、 `addEventListener` スタイルが 849 | お行儀のよい方法だといわれ、 850 | 推奨されてきました。 851 | 852 | ```javascript 853 | // お行儀のよさ 854 | button.addEventListener('click', function(event) { 855 | console.log(event); 856 | }); 857 | ``` 858 | 859 | 860 | 861 | しかし、[AngularJS](https://angularjs.org/) という最近の 862 | フレームワークでイベント属性スタイルを 863 | 積極的に採用する動きもあります。 864 | 865 | ```html 866 | 867 | 868 | 869 | 870 | 871 | ``` 872 | 873 | このような場合は、無理に `addEventListener` を 874 | 使わずに、そのフレームワークのしきたりに 875 | 従うとよいでしょう。 876 | 877 | 878 | 879 | ### DOM イベント伝搬の仕組み 880 | 881 | 次に、DOM のイベント伝搬(propagation) 882 | について解説します。 883 | 884 | 885 | 886 | 下のようなボタンを例に、伝搬の必要性を 887 | 考えていきます。このボタンは、アイコンつきで 888 | 表示されることを意図しています。 889 | 890 | ```html 891 | 892 | ``` 893 | 894 | この button 要素の `click` イベントを 895 | 監視することを考えます。 896 | 897 | button 要素に `addEventListener` すればよいように 898 | 見えますが、アイコン画像をクリックされた場合 899 | どうなるのでしょうか? 900 | 901 | 902 | 903 | 実は、子要素で発生した DOM イベントは 904 | 親要素からも監視することができます。 905 | 906 | この仕組みが DOM イベントの伝搬です。 907 | 908 | 909 | 910 | [](http://www.w3.org/TR/DOM-Level-3-Events/#event-flow) 911 | 912 | 913 | 914 | `addEventListener` の引数で 915 | 1-2-4 か 2-3-4 のどちらかを選べます。 916 | 917 | 1. capturing フェーズ 918 | 919 | ルート要素からイベントの対象要素まで降りていく 920 | 921 | 2. target フェーズ 922 | 923 | イベントの対象要素に到着 924 | 925 | 3. bubbling フェーズ 926 | 927 | イベントの対象要素からルート要素まで昇っていく 928 | 929 | 4. ブラウザ既定の処理がおこなわれるフェーズ 930 | 931 | リンクなどによる画面遷移がおこなわれる 932 | 933 | 934 | 935 | 先ほどのボタンの例では、img 要素の 936 | click イベントは bubbling によって 937 | button 要素まで通知されるのです。 938 | 939 | ```html 940 | 941 | ``` 942 | 943 | ```javascript 944 | // button への addEventListener で OK 945 | button.addEventListener('click', function(event) { 946 | // Do something 947 | }); 948 | ``` 949 | 950 | 951 | 952 | #### 実習 953 | 954 | 下のテストが green になるように、 955 | `public/stage4/tests.js` を 956 | 修正してください。 957 | 958 | [http://localhost:8000/stage4/](http://localhost:8000/stage4/) 959 | 960 | 961 | 962 | #### クリアできたら 963 | 964 | Lint をかけてみましょう。 965 | 966 | npm run lint-stage-4 967 | 968 | 警告があれば、修正してみてください。 969 | 970 | 971 | 972 | ### ステージ5 973 | 974 | 非同期処理のトレーニング 975 | 976 | 977 | 978 | JavaScript の美しい機能のひとつに 979 | 非同期処理があります。 980 | 981 | 下のコードは 1 秒まったあとに 982 | `console.log(1)` を実行するコードです。 983 | 984 | ```javascript 985 | setTimeout(function() { 986 | console.log(1); 987 | }, 0); 988 | 989 | console.log(2); 990 | ``` 991 | 992 | このコードを実行すると、`1` と `2` の 993 | どちらか先に表示されるでしょうか。 994 | 995 | 996 | 997 | 答えは、`2` です。`setTimeout` に登録された 998 | 関数はいま実行途中のすべての関数が終了してから 999 | 呼び出されます([JavaScriptのsetTimeoutを理解する](http://blog.mouten.info/2014/09/20/article/))。 1000 | 1001 | ここでは、関数を実行するタイミングを 1002 | 後回しにすることによって、待っている間に 1003 | 別のことができる、ということを覚えてください。 1004 | 1005 | この待ち時間の間に別の処理を実行する 1006 | やり方を非同期処理と呼びます。 1007 | 1008 | 1009 | 1010 | #### サーバーとの通信 1011 | 1012 | 非同期処理の代表例といえばサーバーとの通信です。 1013 | 1014 | サーバーとの通信はネットワークを通過するため、 1015 | かなりの時間がかかります。そこで、レスポンスが 1016 | 返ってくるまでの間に、別の処理をおこなうことに 1017 | よって、時間を有効活用することが重要になります。 1018 | 1019 | 1020 | 1021 | JavaScript にはサーバーと非同期に通信するための 1022 | API が用意されています。 1023 | 1024 | - [Fetch API](http://www.hcn.zaq.ne.jp/___/WEB/Fetch-ja.html) 1025 | 1026 | 現在策定中の新しい標準仕様 1027 | 1028 | - [XMLHttpRequest](https://developer.mozilla.org/ja/docs/Web/API/XMLHttpRequest) 1029 | 1030 | jQuery.ajax のようなショートハンドが使われる 1031 | ことが多く、実際手で書くことはほとんどない 1032 | 1033 | 1034 | 1035 | 今回は、JavaScript の将来を見据えて、 1036 | Fetch API によるサーバーとの通信を 1037 | トレーニングします。 1038 | 1039 | 1040 | 1041 | #### Fetch API 1042 | 1043 | Fetch API は下のように書きます。 1044 | このコードは、`/users.json` を 1045 | 取得します。 1046 | 1047 | ```javascript 1048 | fetch('/users.json') 1049 | .then(function(response) { 1050 | return response.json() 1051 | }) 1052 | .then(function(json) { 1053 | console.log('parsed json', json) 1054 | }) 1055 | .catch(function(error) { 1056 | console.error('parsing failed', error) 1057 | }); 1058 | ``` 1059 | 1060 | `.then`、`.catch` という不思議なメソッドで 1061 | つながっています。 1062 | 1063 | 1064 | 1065 | #### Promise を使った非同期処理 1066 | 1067 | さきほどの `.then`、`.catch` は、非同期処理の 1068 | 結果を、引数に渡した関数で受け取るために 1069 | 用意されています。 1070 | 1071 | たとえば、`.then` を使うと、正常にレスポンスが 1072 | 受け取れた場合に関数を実行できます。 1073 | 1074 | ```javascript 1075 | fetch('/users.json') 1076 | .then(function(response) { 1077 | 1078 | // /users.json を正常に取得できたときに、 1079 | // response をログに出力する 1080 | console.log(response); 1081 | }); 1082 | ``` 1083 | 1084 | エラーがあった場合は、ログ出力は実行されません。 1085 | 1086 | 1087 | 1088 | また、`.catch` を使うと、エラーが発生した場合に 1089 | 関数を実行できます。 1090 | 1091 | ```javascript 1092 | fetch('/users.json') 1093 | .catch(function(errror) { 1094 | 1095 | // /users.json の取得時にエラーがでたときに、 1096 | // error をログに出力する 1097 | console.error(error); 1098 | }); 1099 | ``` 1100 | 1101 | こちらは、正常にレスポンスを受け取れた場合は、 1102 | ログ出力は実行されません。 1103 | 1104 | なお、先ほどの例のように `.then` と `.catch` を 1105 | 同時につけることもできます。 1106 | 1107 | 1108 | 1109 | サーバーと通信するだけなのに、 1110 | なんか複雑すぎるような…? 1111 | 1112 | 1113 | 1114 | 実はこの Promise という複雑な仕組みを使う理由は、 1115 | 1116 | - 並行非同期処理 1117 | - 直列非同期処理 1118 | 1119 | を書きやすくする、ということなのです。 1120 | 1121 | 1122 | 1123 | #### Promise による並行非同期処理 1124 | 1125 | `Promise.all` を使います。 1126 | 1127 | ```javascript 1128 | // 2つの Web API からレスポンスが欲しい! 1129 | 1130 | Promise.all([ 1131 | fetch('/api/foo'), 1132 | fetch('/api/bar') 1133 | ]) 1134 | .then(function(responses) { 1135 | var responseFoo = responses[0]; 1136 | var responseBar = responses[1]; 1137 | doSomething(responseFoo, responseBar); 1138 | }); 1139 | ``` 1140 | 1141 | 1142 | 1143 | #### Promise による直列非同期処理 1144 | 1145 | `.then` で次々に処理を連結できます。 1146 | 1147 | ```javascript 1148 | // Web API の結果を利用して別の API を実行したい! 1149 | 1150 | fetch('/api/foo') 1151 | .then(doSomething) 1152 | .then(function() { return fetch('/api/bar'); }) 1153 | .then(doSomething) 1154 | .then(function() { return fetch('/api/buz'); }) 1155 | .then(doSomething); 1156 | ``` 1157 | 1158 | 1159 | 1160 | #### 実習 1161 | 1162 | 下のテストが green になるように、 1163 | `public/stage5/tests.js` を 1164 | 修正してください。 1165 | 1166 | [http://localhost:8000/stage5/](http://localhost:8000/stage5/) 1167 | 1168 | 1169 | 1170 | #### 参考になる資料 1171 | 1172 | - [Promise に関する参考情報](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Promise) 1173 | - [Promise 参考情報(重量級)](http://azu.github.io/promises-book/) 1174 | - [Fetch API に関する参考情報](https://github.com/github/fetch) 1175 | - [Github API に関する参考情報](https://developer.github.com/v3/) 1176 | 1177 | 1178 | 1179 | #### クリアできたら 1180 | 1181 | Lint をかけてみましょう。 1182 | 1183 | npm run lint-stage-5 1184 | 1185 | 警告があれば、修正してみてください。 1186 | 1187 | 1188 | 1189 | ### ステージ6 1190 | 1191 | モジュールを実装するトレーニング 1192 | 1193 | 1194 | 1195 | JavaScript は言語機能としてモジュールの 1196 | 仕組みをもっていません。 1197 | 1198 | 言語機能としてのモジュールシステムを利用するには 1199 | [ECMAScript 6](https://developer.mozilla.org/ja/docs/Web/JavaScript/ECMAScript_6_support_in_Mozilla) を待たなければなりません。 1200 | 1201 | 1202 | 1203 | とはいっても、みんなモジュールを使いたかったので、 1204 | さまざまなモジュールシステムとそれに付随する 1205 | エコシステムが開発されてきました。 1206 | 1207 | 1208 | 1209 | - bower 1210 | - component 1211 | - jam 1212 | - volo 1213 | - npm with browserify 1214 | - spm 1215 | - jspm 1216 | - duo 1217 | 1218 | (source: [wilmoore/frontend-packagers](https://github.com/wilmoore/frontend-packagers)) 1219 | 1220 | 1221 | 1222 | あ…めっちゃ多い…😵 1223 | 1224 | 1225 | 1226 | 今回は、利用方法がシンプルな「[bower](http://bower.io)」を使います。 1227 | 1228 | 1229 | 1230 | #### bower 1231 | 1232 | bower は、JavaScript、HTML、CSSなどを 1233 | 共有して使えるようにするフロントエンドの 1234 | エコシステムです。 1235 | 1236 | 他の人が作ったモジュールを利用することや、 1237 | 自分が作ったモジュールを公開することも 1238 | できます。 1239 | 1240 | 1241 | 1242 | ただ、bower はモジュール読み込みの 1243 | 仕組みを提供していません。 1244 | 1245 | この部分は RequireJS など、別の 1246 | モジュールシステムに頼ることになります。 1247 | 1248 | どのモジュールシステムに対応するかという選択は、 1249 | bower によって読み込まれるパッケージ側に 1250 | 裁量(責務)があります。 1251 | 1252 | 1253 | 1254 | この方針を[公式ドキュメント](http://bower.io/#getting-started)は端的に 1255 | 言い表しています。 1256 | 1257 | > How you use packages is up to you. 1258 | > 1259 | > (どのようにしてパッケージを使うのかはあなた次第です) 1260 | 1261 | 1262 | 1263 | #### 実習 1264 | 1265 | まず、bower を実行することを体験してみます。 1266 | bower の設定ファイル bower.json を対話的に 1267 | 作成します。 1268 | 1269 | cd public/stage6/sample 1270 | bower init 1271 | 1272 | 1273 | 1274 | あとは説明に従って選択していくと、bower の 1275 | パッケージ設定ファイル `bower.json` が作成されます。 1276 | 1277 | 1278 | 1279 | ##### 1. name 1280 | 1281 | このパッケージの名前を指定します。 1282 | 1283 | パッケージとして公開する場合には、既に同じ 1284 | パッケージ名が存在していないか確かめる必要が 1285 | あります。 1286 | 1287 | この研修では、公開/非公開を問わないので、 1288 | お好きな名前をつけてください。 1289 | 1290 | 1291 | 1292 | ##### 2. version 1293 | 1294 | このパッケージのバージョンを指定します。 1295 | 1296 | バージョンの形式は [Semantic Versioning](http://semver.org/lang/ja/) に 1297 | 準拠しています。 1298 | 1299 | この形式は、一般的に `X.Y.Z` と記述されます。 1300 | 1301 | - `X` は major version(後方互換性がなくなる変更) 1302 | - `Y` は minor version(前方互換性がなくなる変更) 1303 | - `Z` は patch version(バグ修正など) 1304 | 1305 | 今回は開発版なので、0.0.0 にしておきましょう 1306 | (major versionの 0 は開発版であることを示します)。 1307 | 1308 | 1309 | 1310 | ##### 3. description 1311 | 1312 | パッケージの簡単な概要を記述します。 1313 | 1314 | 有名どころの説明をみてみます。 1315 | 1316 | - bootstrap: The most popular HTML, CSS, and JavaScript framework for developing responsive, mobile first projects on the web. 1317 | - angular-latest: HTML enhanced for web apps 1318 | - less.js: Leaner CSS 1319 | 1320 | 1321 | 1322 | ##### 4. main file 1323 | 1324 | このパッケージが外部のパッケージに公開したい 1325 | ファイルを指定します。文字列と配列が指定できます。 1326 | 今回は空で問題ありません。 1327 | 1328 | 1329 | 1330 | ##### 5. what types of module does this package expose? 1331 | 1332 | このパッケージが外部にエンドポイントを公開する 1333 | 方法を明示します。 1334 | 1335 | - amd: [Asynchronouse Module Definition](https://github.com/amdjs/amdjs-api/wiki/AMD) ([参考資料](http://www.matzmtok.com/blog/?p=845)) 1336 | - es6: [EcmaScript 6](http://wiki.ecmascript.org/lib/exe/fetch.php?id=harmony%3Aspecification_drafts&cache=cache&media=harmony:ecma-262_edition_6_03-17-15-releasecandidate3.pdf) ([参考資料](https://www.xenophy.com/javascript/8447#run-time-renaissance)) 1337 | - globals: グローバル変数経由でエンドポイント公開 1338 | - node: [Node.js](https://nodejs.org/api/modules.html) 1339 | - yui: [YUI](http://yuilibrary.com/yui/docs/yui/create.html) (メンテ停止したのでもうやめましょう) 1340 | 1341 | 今回は何も選択しないで問題ありません。 1342 | 1343 | 1344 | 1345 | ##### 6. keywords 1346 | 1347 | このパッケージを検索でヒットさせるための 1348 | キーワードを指定します。 1349 | 1350 | 1351 | 1352 | ##### 7. authors 1353 | 1354 | このパッケージの作者を指定します。 1355 | 1356 | 1357 | 1358 | ##### 8. license 1359 | 1360 | 好きなライセンスを選ぶとよいです。 1361 | 1362 | デフォルトは [MIT ライセンス](http://sourceforge.jp/projects/opensource/wiki/licenses%2FMIT_license)です。 1363 | 1364 | 1365 | 1366 | ##### 9. homepage 1367 | 1368 | このパッケージの情報が見られる URL を記述します。 1369 | 1370 | 1371 | 1372 | ##### 10. set currenttly installed components as dependencies? 1373 | 1374 | 既に `bower_components` に含まれている 1375 | コンポーネントをパッケージ設定に 1376 | 含まれるようにするかどうかを指定します。 1377 | 1378 | n で構いません。 1379 | 1380 | 1381 | 1382 | ##### 11. add commonly ignored files to ignore list? 1383 | 1384 | `.gitignore` などのファイルから、 1385 | パッケージに含めないファイルの指定を 1386 | 読み込むかどうか指定します。 1387 | 1388 | y で読み込ませます。 1389 | 1390 | 1391 | 1392 | ##### 12. would you like to mark this package as private which prevents it from being accidentally published to the registry? 1393 | 1394 | bower のレジストリへ登録できないようにするか 1395 | どうか指定します。 1396 | 1397 | y でレジストリへの公開ができないように設定します。 1398 | 1399 | 1400 | 1401 | ##### 13. Looks good? 1402 | 1403 | この設定で問題なければ y を入力します。 1404 | 1405 | 1406 | 1407 | ##### bower install 1408 | 1409 | いよいよ、パッケージを追加していきます。 1410 | 1411 | パッケージは [Search Bower packages](http://bower.io/search/) で 1412 | 検索することができます。 1413 | 1414 | もしくは 1415 | 1416 | bower search Buttons 1417 | 1418 | でも検索することができます。 1419 | 1420 | 1421 | 1422 | では、試しに [Buttons](https://github.com/alexwolfe/Buttons) パッケージを 1423 | 追加してみましょう。 1424 | 1425 | 下のコマンドによって、Buttons パッケージが、 1426 | `bower_components` 以下に配置されます。 1427 | 1428 | bower install --save Buttons 1429 | 1430 | 1431 | 1432 | `--save` はパッケージ設定に依存ファイルを 1433 | 追記する効果があります(`bower.json` の 1434 | 内容が変化しているので、見てみてください)。 1435 | 1436 | ここで設定に追記されたパッケージは、 1437 | 次回から `bower install` でまとめて 1438 | 取得することができるようになります。 1439 | 1440 | 1441 | 1442 | 今回は、簡単のために script タグで直接 1443 | `bower_components` 以下の JavaScript/CSS を 1444 | 読み込みます。 1445 | 1446 | 1447 | 1448 | 今回の実習はテスト駆動形式ではありません。 1449 | 1450 | 満足のいく Web アプリケーションが書けたら、 1451 | `qualityOfYourAppliation` に `true` を 1452 | 代入してください。 1453 | 1454 | [http://localhost:8000/stage6/](http://localhost:8000/stage6/) 1455 | 1456 | 1457 | 1458 | #### クリアできたら 1459 | 1460 | Lint をかけてみましょう。 1461 | 1462 | npm run lint-stage-6 1463 | 1464 | 警告があれば、修正してみてください。 1465 | 1466 | 1467 | 1468 | ### ステージ7 1469 | 1470 | よくあるイディオムを読むトレーニング 1471 | 1472 | 1473 | 1474 | このステージでは、よくある JavaScript の 1475 | 不思議な書き方を学びます。 1476 | 1477 | なお、今回はヒントがありません! 1478 | ぜひ自分で調べて、結果を確かめてみてください! 1479 | 1480 | 1481 | 1482 | なお、興味のある方は、ステージ「闇」に 1483 | 挑戦してみてくださいね! 1484 | 1485 | `.skip` を削除すれば挑戦できるようにに 1486 | なります。 1487 | 1488 | 1489 | 1490 | #### 実習 1491 | 1492 | 下のテストが green になるように、 1493 | `public/stage7/tests.js` を 1494 | 修正してください。 1495 | 1496 | [http://localhost:8000/stage7/](http://localhost:8000/stage7/) 1497 | 1498 | 1499 | 1500 | #### クリアできたら 1501 | 1502 | Lint をかけてみましょう。 1503 | 1504 | npm run lint-stage-7 1505 | 1506 | 警告があれば、修正してみてください。 1507 | 1508 | 1509 | 付録 1510 | ---- 1511 | 1512 | 1513 | 1514 | ### Promise について 1515 | 1516 | 1517 | 1518 | #### Promise による並行非同期処理 1519 | 1520 | Promise による並行非同期処理を通常のやりかたと、 1521 | Promise らしいやり方とでやってみました。 1522 | 1523 | コードを比較してみてください。 1524 | 1525 | 1526 | 1527 | ```javascript 1528 | // 2つの Web API からレスポンスが欲しい! 1529 | 1530 | var done = { foo: false, bar: false }; 1531 | var responses = { foo: null, bar: false }; 1532 | fetch('/api/foo').then(function(responseFoo) { 1533 | if (!done.bar) { 1534 | done.foo = true; 1535 | responses.foo = responseFoo; 1536 | return; 1537 | } 1538 | doSomething(responseFoo, responses.bar); 1539 | }); 1540 | fetch('/api/bar').then(function(responseBar) { 1541 | if (!done.foo) { 1542 | done.bar = true; 1543 | responses.bar = responseFoo; 1544 | return; 1545 | } 1546 | doSomething(responses.foo, responseBar); 1547 | }); 1548 | ``` 1549 | 1550 | レスポンス取得の待ち合わせ処理があり、 1551 | 状態を複数もつ厄介なコードにしあがっていますね。 1552 | 1553 | 1554 | 1555 | ```javascript 1556 | // 2つの Web API からレスポンスが欲しい! 1557 | 1558 | Promise.all([ 1559 | fetch('/api/foo'), 1560 | fetch('/api/bar') 1561 | ]) 1562 | .then(function(responses) { 1563 | var responseFoo = responses[0]; 1564 | var responseBar = responses[1]; 1565 | doSomething(responseFoo, responseBar); 1566 | }); 1567 | ``` 1568 | 1569 | `Promise.all` を使うと、待ち合わせ処理が 1570 | なくスッキリ! 1571 | 1572 | 1573 | 1574 | #### Promise による直列非同期処理 1575 | 1576 | 直列非同期処理についても、通常のやり方と、 1577 | Promise らしいやり方でやってみました。 1578 | 1579 | コードを比較してみてください。 1580 | 1581 | 1582 | 1583 | ```javascript 1584 | // Web API の結果を利用して別の API を実行したい! 1585 | 1586 | fetch('/api/foo').then(function(responseFoo) { 1587 | doSomething(responseFoo); 1588 | fetch('/api/bar').then(function(responseBar) { 1589 | doSomething(responseBar); 1590 | fetch('/api/buz').then(function(responseBuz) { 1591 | doSomething(responseBuz); 1592 | }); 1593 | }); 1594 | }); 1595 | ``` 1596 | 1597 | コードがネストしているので、後ろの方の 1598 | 関数のスコープが深くなってしまっています。 1599 | 変数を追跡するのに手間がかかりそうです。 1600 | 1601 | 1602 | 1603 | ネストの外に出すだけならば、終了コールバックを 1604 | 呼び出す[継続渡しスタイル](http://ja.wikipedia.org/wiki/%E7%B6%99%E7%B6%9A%E6%B8%A1%E3%81%97%E3%82%B9%E3%82%BF%E3%82%A4%E3%83%AB) で 1605 | 書くことができます。 1606 | 1607 | ```javascript 1608 | // Web API の結果を利用して別の API を実行したい! 1609 | 1610 | fetch('/api/foo').then(callbackFoo); 1611 | 1612 | function callbackFoo(responseFoo) { 1613 | doSomething(responseFoo); 1614 | fetchBar(callbackBar); 1615 | } 1616 | 1617 | function fetchBar(callback) { 1618 | fetch('/api/bar').then(callback); 1619 | } 1620 | 1621 | function callbackBar(responseBar) { 1622 | doSomething(responseBar); 1623 | fetchBuz(callbackBuz); 1624 | } 1625 | 1626 | function fetchBuz(callback) { 1627 | fetch('/api/buz').then(callback); 1628 | } 1629 | 1630 | function callbackBuz(responseBuz) { 1631 | doSomething(responseBuz); 1632 | } 1633 | ``` 1634 | 1635 | 流れが追いづらい! 1636 | 1637 | 1638 | 1639 | クロージャー + 継続渡しスタイルを使うと… 1640 | 1641 | ```javascript 1642 | // Web API の結果を利用して別の API を実行したい! 1643 | 1644 | fetch('/api/foo').then(fetchBar(fetchBuz(doSomething))); 1645 | 1646 | function fetchBar(callback) { 1647 | return function(responseFoo) { 1648 | doSomething(responseFoo); 1649 | fetch('/api/bar').then(callback); 1650 | }; 1651 | } 1652 | 1653 | function fetchBuz(callback) { 1654 | return function(responseBar) { 1655 | doSomething(responseBar); 1656 | fetch('/api/buz').then(callback); 1657 | }; 1658 | } 1659 | ``` 1660 | 1661 | 1662 | 1663 | これはこれで美しい…😌 1664 | 1665 | (JS に慣れるまではちょっと読みづらいと思います) 1666 | 1667 | 1668 | 1669 | Promise らしいやり方をとると `.then` で 1670 | 次々に処理を連結できます。 1671 | 1672 | ```javascript 1673 | // Web API の結果を利用して別の API を実行したい! 1674 | 1675 | fetch('/api/foo') 1676 | .then(doSomething) 1677 | .then(function() { return fetch('/api/bar'); }) 1678 | .then(doSomething) 1679 | .then(function() { return fetch('/api/buz'); }) 1680 | .then(doSomething); 1681 | ``` 1682 | -------------------------------------------------------------------------------- /npm-shrinkwrap.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mixi-js-training", 3 | "version": "0.0.0", 4 | "dependencies": { 5 | "bower": { 6 | "version": "1.5.2", 7 | "from": "bower@1.5.2", 8 | "resolved": "https://registry.npmjs.org/bower/-/bower-1.5.2.tgz", 9 | "dependencies": { 10 | "abbrev": { 11 | "version": "1.0.7", 12 | "from": "abbrev@>=1.0.5 <2.0.0", 13 | "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.0.7.tgz" 14 | }, 15 | "archy": { 16 | "version": "1.0.0", 17 | "from": "archy@1.0.0", 18 | "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz" 19 | }, 20 | "bower-config": { 21 | "version": "0.6.1", 22 | "from": "bower-config@>=0.6.1 <0.7.0", 23 | "resolved": "https://registry.npmjs.org/bower-config/-/bower-config-0.6.1.tgz", 24 | "dependencies": { 25 | "graceful-fs": { 26 | "version": "2.0.3", 27 | "from": "graceful-fs@>=2.0.0 <2.1.0", 28 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-2.0.3.tgz" 29 | }, 30 | "mout": { 31 | "version": "0.9.1", 32 | "from": "mout@>=0.9.0 <0.10.0" 33 | }, 34 | "optimist": { 35 | "version": "0.6.1", 36 | "from": "optimist@>=0.6.0 <0.7.0", 37 | "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz", 38 | "dependencies": { 39 | "wordwrap": { 40 | "version": "0.0.3", 41 | "from": "wordwrap@>=0.0.2 <0.1.0", 42 | "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz" 43 | }, 44 | "minimist": { 45 | "version": "0.0.10", 46 | "from": "minimist@>=0.0.1 <0.1.0", 47 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz" 48 | } 49 | } 50 | }, 51 | "osenv": { 52 | "version": "0.0.3", 53 | "from": "osenv@0.0.3" 54 | } 55 | } 56 | }, 57 | "bower-endpoint-parser": { 58 | "version": "0.2.2", 59 | "from": "bower-endpoint-parser@>=0.2.2 <0.3.0" 60 | }, 61 | "bower-json": { 62 | "version": "0.4.0", 63 | "from": "bower-json@>=0.4.0 <0.5.0", 64 | "dependencies": { 65 | "deep-extend": { 66 | "version": "0.2.11", 67 | "from": "deep-extend@>=0.2.5 <0.3.0" 68 | }, 69 | "graceful-fs": { 70 | "version": "2.0.3", 71 | "from": "graceful-fs@>=2.0.0 <2.1.0", 72 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-2.0.3.tgz" 73 | }, 74 | "intersect": { 75 | "version": "0.0.3", 76 | "from": "intersect@>=0.0.3 <0.1.0" 77 | } 78 | } 79 | }, 80 | "bower-logger": { 81 | "version": "0.2.2", 82 | "from": "bower-logger@>=0.2.2 <0.3.0" 83 | }, 84 | "bower-registry-client": { 85 | "version": "0.3.0", 86 | "from": "bower-registry-client@>=0.3.0 <0.4.0", 87 | "resolved": "https://registry.npmjs.org/bower-registry-client/-/bower-registry-client-0.3.0.tgz", 88 | "dependencies": { 89 | "async": { 90 | "version": "0.2.10", 91 | "from": "async@>=0.2.8 <0.3.0", 92 | "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz" 93 | }, 94 | "graceful-fs": { 95 | "version": "2.0.3", 96 | "from": "graceful-fs@>=2.0.0 <2.1.0", 97 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-2.0.3.tgz" 98 | }, 99 | "lru-cache": { 100 | "version": "2.3.1", 101 | "from": "lru-cache@>=2.3.0 <2.4.0" 102 | }, 103 | "request": { 104 | "version": "2.51.0", 105 | "from": "request@>=2.51.0 <2.52.0", 106 | "resolved": "https://registry.npmjs.org/request/-/request-2.51.0.tgz", 107 | "dependencies": { 108 | "bl": { 109 | "version": "0.9.4", 110 | "from": "bl@>=0.9.0 <0.10.0", 111 | "resolved": "https://registry.npmjs.org/bl/-/bl-0.9.4.tgz", 112 | "dependencies": { 113 | "readable-stream": { 114 | "version": "1.0.33", 115 | "from": "readable-stream@>=1.0.26 <1.1.0", 116 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.33.tgz", 117 | "dependencies": { 118 | "core-util-is": { 119 | "version": "1.0.1", 120 | "from": "core-util-is@>=1.0.0 <1.1.0", 121 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz" 122 | }, 123 | "isarray": { 124 | "version": "0.0.1", 125 | "from": "isarray@0.0.1", 126 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz" 127 | }, 128 | "string_decoder": { 129 | "version": "0.10.31", 130 | "from": "string_decoder@>=0.10.0 <0.11.0", 131 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz" 132 | }, 133 | "inherits": { 134 | "version": "2.0.1", 135 | "from": "inherits@>=2.0.1 <2.1.0", 136 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz" 137 | } 138 | } 139 | } 140 | } 141 | }, 142 | "caseless": { 143 | "version": "0.8.0", 144 | "from": "caseless@>=0.8.0 <0.9.0" 145 | }, 146 | "forever-agent": { 147 | "version": "0.5.2", 148 | "from": "forever-agent@>=0.5.0 <0.6.0", 149 | "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.5.2.tgz" 150 | }, 151 | "form-data": { 152 | "version": "0.2.0", 153 | "from": "form-data@>=0.2.0 <0.3.0", 154 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-0.2.0.tgz", 155 | "dependencies": { 156 | "async": { 157 | "version": "0.9.2", 158 | "from": "async@>=0.9.0 <0.10.0", 159 | "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz" 160 | }, 161 | "mime-types": { 162 | "version": "2.0.14", 163 | "from": "mime-types@>=2.0.3 <2.1.0", 164 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.0.14.tgz", 165 | "dependencies": { 166 | "mime-db": { 167 | "version": "1.12.0", 168 | "from": "mime-db@>=1.12.0 <1.13.0", 169 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.12.0.tgz" 170 | } 171 | } 172 | } 173 | } 174 | }, 175 | "json-stringify-safe": { 176 | "version": "5.0.1", 177 | "from": "json-stringify-safe@>=5.0.0 <5.1.0", 178 | "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz" 179 | }, 180 | "mime-types": { 181 | "version": "1.0.2", 182 | "from": "mime-types@>=1.0.1 <1.1.0" 183 | }, 184 | "node-uuid": { 185 | "version": "1.4.3", 186 | "from": "node-uuid@>=1.4.0 <1.5.0", 187 | "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.3.tgz" 188 | }, 189 | "qs": { 190 | "version": "2.3.3", 191 | "from": "qs@>=2.3.1 <2.4.0", 192 | "resolved": "https://registry.npmjs.org/qs/-/qs-2.3.3.tgz" 193 | }, 194 | "tunnel-agent": { 195 | "version": "0.4.1", 196 | "from": "tunnel-agent@>=0.4.0 <0.5.0", 197 | "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.1.tgz" 198 | }, 199 | "tough-cookie": { 200 | "version": "2.0.0", 201 | "from": "tough-cookie@>=0.12.0", 202 | "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.0.0.tgz" 203 | }, 204 | "http-signature": { 205 | "version": "0.10.1", 206 | "from": "http-signature@>=0.10.0 <0.11.0", 207 | "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-0.10.1.tgz", 208 | "dependencies": { 209 | "assert-plus": { 210 | "version": "0.1.5", 211 | "from": "assert-plus@>=0.1.5 <0.2.0", 212 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz" 213 | }, 214 | "asn1": { 215 | "version": "0.1.11", 216 | "from": "asn1@0.1.11", 217 | "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz" 218 | }, 219 | "ctype": { 220 | "version": "0.5.3", 221 | "from": "ctype@0.5.3", 222 | "resolved": "https://registry.npmjs.org/ctype/-/ctype-0.5.3.tgz" 223 | } 224 | } 225 | }, 226 | "oauth-sign": { 227 | "version": "0.5.0", 228 | "from": "oauth-sign@>=0.5.0 <0.6.0" 229 | }, 230 | "hawk": { 231 | "version": "1.1.1", 232 | "from": "hawk@1.1.1", 233 | "resolved": "https://registry.npmjs.org/hawk/-/hawk-1.1.1.tgz", 234 | "dependencies": { 235 | "hoek": { 236 | "version": "0.9.1", 237 | "from": "hoek@>=0.9.0 <0.10.0" 238 | }, 239 | "boom": { 240 | "version": "0.4.2", 241 | "from": "boom@>=0.4.0 <0.5.0" 242 | }, 243 | "cryptiles": { 244 | "version": "0.2.2", 245 | "from": "cryptiles@>=0.2.0 <0.3.0" 246 | }, 247 | "sntp": { 248 | "version": "0.2.4", 249 | "from": "sntp@>=0.2.0 <0.3.0" 250 | } 251 | } 252 | }, 253 | "aws-sign2": { 254 | "version": "0.5.0", 255 | "from": "aws-sign2@>=0.5.0 <0.6.0", 256 | "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.5.0.tgz" 257 | }, 258 | "stringstream": { 259 | "version": "0.0.4", 260 | "from": "stringstream@>=0.0.4 <0.1.0", 261 | "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.4.tgz" 262 | }, 263 | "combined-stream": { 264 | "version": "0.0.7", 265 | "from": "combined-stream@>=0.0.5 <0.1.0", 266 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-0.0.7.tgz", 267 | "dependencies": { 268 | "delayed-stream": { 269 | "version": "0.0.5", 270 | "from": "delayed-stream@0.0.5", 271 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-0.0.5.tgz" 272 | } 273 | } 274 | } 275 | } 276 | }, 277 | "request-replay": { 278 | "version": "0.2.0", 279 | "from": "request-replay@>=0.2.0 <0.3.0" 280 | }, 281 | "rimraf": { 282 | "version": "2.2.8", 283 | "from": "rimraf@>=2.2.0 <2.3.0", 284 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz" 285 | }, 286 | "mkdirp": { 287 | "version": "0.3.5", 288 | "from": "mkdirp@>=0.3.5 <0.4.0" 289 | } 290 | } 291 | }, 292 | "cardinal": { 293 | "version": "0.4.4", 294 | "from": "cardinal@0.4.4", 295 | "resolved": "https://registry.npmjs.org/cardinal/-/cardinal-0.4.4.tgz", 296 | "dependencies": { 297 | "redeyed": { 298 | "version": "0.4.4", 299 | "from": "redeyed@>=0.4.0 <0.5.0", 300 | "dependencies": { 301 | "esprima": { 302 | "version": "1.0.4", 303 | "from": "esprima@>=1.0.4 <1.1.0", 304 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.0.4.tgz" 305 | } 306 | } 307 | }, 308 | "ansicolors": { 309 | "version": "0.2.1", 310 | "from": "ansicolors@>=0.2.1 <0.3.0" 311 | } 312 | } 313 | }, 314 | "chalk": { 315 | "version": "1.1.1", 316 | "from": "chalk@>=1.0.0 <2.0.0", 317 | "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.1.tgz", 318 | "dependencies": { 319 | "ansi-styles": { 320 | "version": "2.1.0", 321 | "from": "ansi-styles@>=2.1.0 <3.0.0", 322 | "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.1.0.tgz" 323 | }, 324 | "escape-string-regexp": { 325 | "version": "1.0.3", 326 | "from": "escape-string-regexp@>=1.0.2 <2.0.0", 327 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.3.tgz" 328 | }, 329 | "has-ansi": { 330 | "version": "2.0.0", 331 | "from": "has-ansi@>=2.0.0 <3.0.0", 332 | "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", 333 | "dependencies": { 334 | "ansi-regex": { 335 | "version": "2.0.0", 336 | "from": "ansi-regex@>=2.0.0 <3.0.0", 337 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz" 338 | } 339 | } 340 | }, 341 | "strip-ansi": { 342 | "version": "3.0.0", 343 | "from": "strip-ansi@>=3.0.0 <4.0.0", 344 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.0.tgz", 345 | "dependencies": { 346 | "ansi-regex": { 347 | "version": "2.0.0", 348 | "from": "ansi-regex@>=2.0.0 <3.0.0", 349 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz" 350 | } 351 | } 352 | }, 353 | "supports-color": { 354 | "version": "2.0.0", 355 | "from": "supports-color@>=2.0.0 <3.0.0", 356 | "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz" 357 | } 358 | } 359 | }, 360 | "chmodr": { 361 | "version": "0.1.0", 362 | "from": "chmodr@0.1.0", 363 | "resolved": "https://registry.npmjs.org/chmodr/-/chmodr-0.1.0.tgz" 364 | }, 365 | "configstore": { 366 | "version": "0.3.2", 367 | "from": "configstore@>=0.3.2 <0.4.0", 368 | "dependencies": { 369 | "js-yaml": { 370 | "version": "3.4.2", 371 | "from": "js-yaml@>=3.1.0 <4.0.0", 372 | "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.4.2.tgz", 373 | "dependencies": { 374 | "argparse": { 375 | "version": "1.0.2", 376 | "from": "argparse@>=1.0.2 <1.1.0", 377 | "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.2.tgz", 378 | "dependencies": { 379 | "lodash": { 380 | "version": "3.10.1", 381 | "from": "lodash@>=3.2.0 <4.0.0", 382 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-3.10.1.tgz" 383 | }, 384 | "sprintf-js": { 385 | "version": "1.0.3", 386 | "from": "sprintf-js@>=1.0.2 <1.1.0", 387 | "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz" 388 | } 389 | } 390 | }, 391 | "esprima": { 392 | "version": "2.2.0", 393 | "from": "esprima@>=2.2.0 <2.3.0", 394 | "resolved": "https://registry.npmjs.org/esprima/-/esprima-2.2.0.tgz" 395 | } 396 | } 397 | }, 398 | "object-assign": { 399 | "version": "2.1.1", 400 | "from": "object-assign@>=2.0.0 <3.0.0", 401 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz" 402 | }, 403 | "osenv": { 404 | "version": "0.1.3", 405 | "from": "osenv@>=0.1.0 <0.2.0", 406 | "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.3.tgz", 407 | "dependencies": { 408 | "os-homedir": { 409 | "version": "1.0.1", 410 | "from": "os-homedir@>=1.0.0 <2.0.0", 411 | "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.1.tgz" 412 | }, 413 | "os-tmpdir": { 414 | "version": "1.0.1", 415 | "from": "os-tmpdir@>=1.0.0 <2.0.0", 416 | "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.1.tgz" 417 | } 418 | } 419 | }, 420 | "uuid": { 421 | "version": "2.0.1", 422 | "from": "uuid@>=2.0.1 <3.0.0" 423 | }, 424 | "xdg-basedir": { 425 | "version": "1.0.1", 426 | "from": "xdg-basedir@>=1.0.0 <2.0.0" 427 | } 428 | } 429 | }, 430 | "decompress-zip": { 431 | "version": "0.1.0", 432 | "from": "decompress-zip@>=0.1.0 <0.2.0", 433 | "resolved": "https://registry.npmjs.org/decompress-zip/-/decompress-zip-0.1.0.tgz", 434 | "dependencies": { 435 | "binary": { 436 | "version": "0.3.0", 437 | "from": "binary@>=0.3.0 <0.4.0", 438 | "resolved": "https://registry.npmjs.org/binary/-/binary-0.3.0.tgz", 439 | "dependencies": { 440 | "chainsaw": { 441 | "version": "0.1.0", 442 | "from": "chainsaw@>=0.1.0 <0.2.0", 443 | "resolved": "https://registry.npmjs.org/chainsaw/-/chainsaw-0.1.0.tgz", 444 | "dependencies": { 445 | "traverse": { 446 | "version": "0.3.9", 447 | "from": "traverse@>=0.3.0 <0.4.0", 448 | "resolved": "https://registry.npmjs.org/traverse/-/traverse-0.3.9.tgz" 449 | } 450 | } 451 | }, 452 | "buffers": { 453 | "version": "0.1.1", 454 | "from": "buffers@>=0.1.1 <0.2.0", 455 | "resolved": "https://registry.npmjs.org/buffers/-/buffers-0.1.1.tgz" 456 | } 457 | } 458 | }, 459 | "mkpath": { 460 | "version": "0.1.0", 461 | "from": "mkpath@>=0.1.0 <0.2.0" 462 | }, 463 | "readable-stream": { 464 | "version": "1.1.13", 465 | "from": "readable-stream@>=1.1.8 <2.0.0", 466 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.13.tgz", 467 | "dependencies": { 468 | "core-util-is": { 469 | "version": "1.0.1", 470 | "from": "core-util-is@>=1.0.0 <1.1.0", 471 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz" 472 | }, 473 | "isarray": { 474 | "version": "0.0.1", 475 | "from": "isarray@0.0.1", 476 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz" 477 | }, 478 | "string_decoder": { 479 | "version": "0.10.31", 480 | "from": "string_decoder@>=0.10.0 <0.11.0", 481 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz" 482 | }, 483 | "inherits": { 484 | "version": "2.0.1", 485 | "from": "inherits@>=2.0.1 <2.1.0", 486 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz" 487 | } 488 | } 489 | }, 490 | "touch": { 491 | "version": "0.0.3", 492 | "from": "touch@0.0.3", 493 | "resolved": "https://registry.npmjs.org/touch/-/touch-0.0.3.tgz", 494 | "dependencies": { 495 | "nopt": { 496 | "version": "1.0.10", 497 | "from": "nopt@>=1.0.10 <1.1.0", 498 | "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz" 499 | } 500 | } 501 | } 502 | } 503 | }, 504 | "deep-sort-object": { 505 | "version": "0.1.1", 506 | "from": "deep-sort-object@>=0.1.1 <0.2.0", 507 | "resolved": "https://registry.npmjs.org/deep-sort-object/-/deep-sort-object-0.1.1.tgz", 508 | "dependencies": { 509 | "mout": { 510 | "version": "0.9.1", 511 | "from": "mout@>=0.9.1 <0.10.0" 512 | } 513 | } 514 | }, 515 | "fstream": { 516 | "version": "1.0.8", 517 | "from": "fstream@>=1.0.3 <2.0.0", 518 | "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.8.tgz", 519 | "dependencies": { 520 | "graceful-fs": { 521 | "version": "4.1.2", 522 | "from": "graceful-fs@>=4.1.2 <5.0.0", 523 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.2.tgz" 524 | }, 525 | "inherits": { 526 | "version": "2.0.1", 527 | "from": "inherits@>=2.0.0 <2.1.0", 528 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz" 529 | } 530 | } 531 | }, 532 | "fstream-ignore": { 533 | "version": "1.0.2", 534 | "from": "fstream-ignore@>=1.0.2 <2.0.0", 535 | "dependencies": { 536 | "inherits": { 537 | "version": "2.0.1", 538 | "from": "inherits@>=2.0.0 <3.0.0", 539 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz" 540 | }, 541 | "minimatch": { 542 | "version": "2.0.10", 543 | "from": "minimatch@>=2.0.1 <3.0.0", 544 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", 545 | "dependencies": { 546 | "brace-expansion": { 547 | "version": "1.1.0", 548 | "from": "brace-expansion@>=1.0.0 <2.0.0", 549 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.0.tgz", 550 | "dependencies": { 551 | "balanced-match": { 552 | "version": "0.2.0", 553 | "from": "balanced-match@>=0.2.0 <0.3.0", 554 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.2.0.tgz" 555 | }, 556 | "concat-map": { 557 | "version": "0.0.1", 558 | "from": "concat-map@0.0.1", 559 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" 560 | } 561 | } 562 | } 563 | } 564 | } 565 | } 566 | }, 567 | "github": { 568 | "version": "0.2.4", 569 | "from": "github@>=0.2.3 <0.3.0", 570 | "resolved": "https://registry.npmjs.org/github/-/github-0.2.4.tgz", 571 | "dependencies": { 572 | "mime": { 573 | "version": "1.3.4", 574 | "from": "mime@>=1.2.11 <2.0.0", 575 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz" 576 | } 577 | } 578 | }, 579 | "glob": { 580 | "version": "4.5.3", 581 | "from": "glob@>=4.3.2 <5.0.0", 582 | "resolved": "https://registry.npmjs.org/glob/-/glob-4.5.3.tgz", 583 | "dependencies": { 584 | "inflight": { 585 | "version": "1.0.4", 586 | "from": "inflight@>=1.0.4 <2.0.0", 587 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.4.tgz", 588 | "dependencies": { 589 | "wrappy": { 590 | "version": "1.0.1", 591 | "from": "wrappy@>=1.0.0 <2.0.0", 592 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz" 593 | } 594 | } 595 | }, 596 | "inherits": { 597 | "version": "2.0.1", 598 | "from": "inherits@>=2.0.0 <3.0.0", 599 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz" 600 | }, 601 | "minimatch": { 602 | "version": "2.0.10", 603 | "from": "minimatch@>=2.0.1 <3.0.0", 604 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", 605 | "dependencies": { 606 | "brace-expansion": { 607 | "version": "1.1.0", 608 | "from": "brace-expansion@>=1.0.0 <2.0.0", 609 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.0.tgz", 610 | "dependencies": { 611 | "balanced-match": { 612 | "version": "0.2.0", 613 | "from": "balanced-match@>=0.2.0 <0.3.0", 614 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.2.0.tgz" 615 | }, 616 | "concat-map": { 617 | "version": "0.0.1", 618 | "from": "concat-map@0.0.1", 619 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" 620 | } 621 | } 622 | } 623 | } 624 | }, 625 | "once": { 626 | "version": "1.3.2", 627 | "from": "once@>=1.3.0 <2.0.0", 628 | "resolved": "https://registry.npmjs.org/once/-/once-1.3.2.tgz", 629 | "dependencies": { 630 | "wrappy": { 631 | "version": "1.0.1", 632 | "from": "wrappy@>=1.0.0 <2.0.0", 633 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz" 634 | } 635 | } 636 | } 637 | } 638 | }, 639 | "graceful-fs": { 640 | "version": "3.0.8", 641 | "from": "graceful-fs@>=3.0.5 <4.0.0", 642 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-3.0.8.tgz" 643 | }, 644 | "handlebars": { 645 | "version": "2.0.0", 646 | "from": "handlebars@>=2.0.0 <3.0.0", 647 | "dependencies": { 648 | "optimist": { 649 | "version": "0.3.7", 650 | "from": "optimist@>=0.3.0 <0.4.0", 651 | "dependencies": { 652 | "wordwrap": { 653 | "version": "0.0.3", 654 | "from": "wordwrap@>=0.0.2 <0.1.0", 655 | "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz" 656 | } 657 | } 658 | }, 659 | "uglify-js": { 660 | "version": "2.3.6", 661 | "from": "uglify-js@>=2.3.0 <2.4.0", 662 | "dependencies": { 663 | "async": { 664 | "version": "0.2.10", 665 | "from": "async@>=0.2.6 <0.3.0", 666 | "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz" 667 | }, 668 | "source-map": { 669 | "version": "0.1.43", 670 | "from": "source-map@>=0.1.7 <0.2.0", 671 | "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", 672 | "dependencies": { 673 | "amdefine": { 674 | "version": "1.0.0", 675 | "from": "amdefine@>=0.0.4", 676 | "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.0.tgz" 677 | } 678 | } 679 | } 680 | } 681 | } 682 | } 683 | }, 684 | "inquirer": { 685 | "version": "0.8.0", 686 | "from": "inquirer@0.8.0", 687 | "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-0.8.0.tgz", 688 | "dependencies": { 689 | "ansi-regex": { 690 | "version": "1.1.1", 691 | "from": "ansi-regex@>=1.1.0 <2.0.0", 692 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-1.1.1.tgz" 693 | }, 694 | "chalk": { 695 | "version": "0.5.1", 696 | "from": "chalk@>=0.5.0 <0.6.0", 697 | "dependencies": { 698 | "ansi-styles": { 699 | "version": "1.1.0", 700 | "from": "ansi-styles@>=1.1.0 <2.0.0" 701 | }, 702 | "escape-string-regexp": { 703 | "version": "1.0.3", 704 | "from": "escape-string-regexp@>=1.0.0 <2.0.0", 705 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.3.tgz" 706 | }, 707 | "has-ansi": { 708 | "version": "0.1.0", 709 | "from": "has-ansi@>=0.1.0 <0.2.0", 710 | "dependencies": { 711 | "ansi-regex": { 712 | "version": "0.2.1", 713 | "from": "ansi-regex@>=0.2.0 <0.3.0" 714 | } 715 | } 716 | }, 717 | "strip-ansi": { 718 | "version": "0.3.0", 719 | "from": "strip-ansi@>=0.3.0 <0.4.0", 720 | "dependencies": { 721 | "ansi-regex": { 722 | "version": "0.2.1", 723 | "from": "ansi-regex@>=0.2.0 <0.3.0" 724 | } 725 | } 726 | }, 727 | "supports-color": { 728 | "version": "0.2.0", 729 | "from": "supports-color@>=0.2.0 <0.3.0" 730 | } 731 | } 732 | }, 733 | "cli-color": { 734 | "version": "0.3.3", 735 | "from": "cli-color@>=0.3.2 <0.4.0", 736 | "resolved": "https://registry.npmjs.org/cli-color/-/cli-color-0.3.3.tgz", 737 | "dependencies": { 738 | "d": { 739 | "version": "0.1.1", 740 | "from": "d@>=0.1.1 <0.2.0" 741 | }, 742 | "es5-ext": { 743 | "version": "0.10.7", 744 | "from": "es5-ext@>=0.10.6 <0.11.0", 745 | "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.7.tgz", 746 | "dependencies": { 747 | "es6-iterator": { 748 | "version": "0.1.3", 749 | "from": "es6-iterator@>=0.1.3 <0.2.0", 750 | "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-0.1.3.tgz" 751 | }, 752 | "es6-symbol": { 753 | "version": "2.0.1", 754 | "from": "es6-symbol@>=2.0.1 <2.1.0", 755 | "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-2.0.1.tgz" 756 | } 757 | } 758 | }, 759 | "memoizee": { 760 | "version": "0.3.9", 761 | "from": "memoizee@>=0.3.8 <0.4.0", 762 | "resolved": "https://registry.npmjs.org/memoizee/-/memoizee-0.3.9.tgz", 763 | "dependencies": { 764 | "es6-weak-map": { 765 | "version": "0.1.4", 766 | "from": "es6-weak-map@>=0.1.4 <0.2.0", 767 | "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-0.1.4.tgz", 768 | "dependencies": { 769 | "es6-iterator": { 770 | "version": "0.1.3", 771 | "from": "es6-iterator@>=0.1.3 <0.2.0", 772 | "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-0.1.3.tgz" 773 | }, 774 | "es6-symbol": { 775 | "version": "2.0.1", 776 | "from": "es6-symbol@>=2.0.1 <2.1.0", 777 | "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-2.0.1.tgz" 778 | } 779 | } 780 | }, 781 | "event-emitter": { 782 | "version": "0.3.3", 783 | "from": "event-emitter@>=0.3.3 <0.4.0" 784 | }, 785 | "lru-queue": { 786 | "version": "0.1.0", 787 | "from": "lru-queue@>=0.1.0 <0.2.0" 788 | }, 789 | "next-tick": { 790 | "version": "0.2.2", 791 | "from": "next-tick@>=0.2.2 <0.3.0" 792 | } 793 | } 794 | }, 795 | "timers-ext": { 796 | "version": "0.1.0", 797 | "from": "timers-ext@>=0.1.0 <0.2.0", 798 | "dependencies": { 799 | "next-tick": { 800 | "version": "0.2.2", 801 | "from": "next-tick@>=0.2.2 <0.3.0" 802 | } 803 | } 804 | } 805 | } 806 | }, 807 | "figures": { 808 | "version": "1.4.0", 809 | "from": "figures@>=1.3.2 <2.0.0", 810 | "resolved": "https://registry.npmjs.org/figures/-/figures-1.4.0.tgz" 811 | }, 812 | "lodash": { 813 | "version": "2.4.2", 814 | "from": "lodash@>=2.4.1 <2.5.0", 815 | "resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz" 816 | }, 817 | "mute-stream": { 818 | "version": "0.0.4", 819 | "from": "mute-stream@0.0.4", 820 | "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.4.tgz" 821 | }, 822 | "readline2": { 823 | "version": "0.1.1", 824 | "from": "readline2@>=0.1.0 <0.2.0", 825 | "dependencies": { 826 | "strip-ansi": { 827 | "version": "2.0.1", 828 | "from": "strip-ansi@>=2.0.1 <3.0.0", 829 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-2.0.1.tgz" 830 | } 831 | } 832 | }, 833 | "rx": { 834 | "version": "2.5.3", 835 | "from": "rx@>=2.2.27 <3.0.0", 836 | "resolved": "https://registry.npmjs.org/rx/-/rx-2.5.3.tgz" 837 | }, 838 | "through": { 839 | "version": "2.3.8", 840 | "from": "through@>=2.3.4 <2.4.0", 841 | "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz" 842 | } 843 | } 844 | }, 845 | "insight": { 846 | "version": "0.5.3", 847 | "from": "insight@>=0.5.0 <0.6.0", 848 | "resolved": "https://registry.npmjs.org/insight/-/insight-0.5.3.tgz", 849 | "dependencies": { 850 | "async": { 851 | "version": "0.9.2", 852 | "from": "async@>=0.9.0 <0.10.0", 853 | "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz" 854 | }, 855 | "lodash.debounce": { 856 | "version": "3.1.1", 857 | "from": "lodash.debounce@>=3.0.1 <4.0.0", 858 | "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-3.1.1.tgz", 859 | "dependencies": { 860 | "lodash._getnative": { 861 | "version": "3.9.1", 862 | "from": "lodash._getnative@>=3.0.0 <4.0.0", 863 | "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz" 864 | } 865 | } 866 | }, 867 | "object-assign": { 868 | "version": "2.1.1", 869 | "from": "object-assign@>=2.0.0 <3.0.0", 870 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz" 871 | }, 872 | "os-name": { 873 | "version": "1.0.3", 874 | "from": "os-name@>=1.0.0 <2.0.0", 875 | "dependencies": { 876 | "osx-release": { 877 | "version": "1.1.0", 878 | "from": "osx-release@>=1.0.0 <2.0.0", 879 | "resolved": "https://registry.npmjs.org/osx-release/-/osx-release-1.1.0.tgz", 880 | "dependencies": { 881 | "minimist": { 882 | "version": "1.2.0", 883 | "from": "minimist@>=1.1.0 <2.0.0", 884 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz" 885 | } 886 | } 887 | }, 888 | "win-release": { 889 | "version": "1.1.1", 890 | "from": "win-release@>=1.0.0 <2.0.0", 891 | "resolved": "https://registry.npmjs.org/win-release/-/win-release-1.1.1.tgz", 892 | "dependencies": { 893 | "semver": { 894 | "version": "5.0.3", 895 | "from": "semver@>=5.0.1 <6.0.0", 896 | "resolved": "https://registry.npmjs.org/semver/-/semver-5.0.3.tgz" 897 | } 898 | } 899 | } 900 | } 901 | }, 902 | "tough-cookie": { 903 | "version": "0.12.1", 904 | "from": "tough-cookie@>=0.12.1 <0.13.0", 905 | "dependencies": { 906 | "punycode": { 907 | "version": "1.3.2", 908 | "from": "punycode@>=0.2.0" 909 | } 910 | } 911 | } 912 | } 913 | }, 914 | "is-root": { 915 | "version": "1.0.0", 916 | "from": "is-root@>=1.0.0 <2.0.0" 917 | }, 918 | "junk": { 919 | "version": "1.0.2", 920 | "from": "junk@>=1.0.0 <2.0.0", 921 | "resolved": "https://registry.npmjs.org/junk/-/junk-1.0.2.tgz" 922 | }, 923 | "lockfile": { 924 | "version": "1.0.1", 925 | "from": "lockfile@>=1.0.0 <2.0.0", 926 | "resolved": "https://registry.npmjs.org/lockfile/-/lockfile-1.0.1.tgz" 927 | }, 928 | "lru-cache": { 929 | "version": "2.7.0", 930 | "from": "lru-cache@>=2.5.0 <3.0.0", 931 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.0.tgz" 932 | }, 933 | "mkdirp": { 934 | "version": "0.5.0", 935 | "from": "mkdirp@0.5.0", 936 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.0.tgz", 937 | "dependencies": { 938 | "minimist": { 939 | "version": "0.0.8", 940 | "from": "minimist@0.0.8", 941 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz" 942 | } 943 | } 944 | }, 945 | "mout": { 946 | "version": "0.11.0", 947 | "from": "mout@>=0.11.0 <0.12.0", 948 | "resolved": "https://registry.npmjs.org/mout/-/mout-0.11.0.tgz" 949 | }, 950 | "nopt": { 951 | "version": "3.0.4", 952 | "from": "nopt@>=3.0.1 <4.0.0", 953 | "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.4.tgz" 954 | }, 955 | "opn": { 956 | "version": "1.0.2", 957 | "from": "opn@>=1.0.1 <2.0.0", 958 | "resolved": "https://registry.npmjs.org/opn/-/opn-1.0.2.tgz" 959 | }, 960 | "p-throttler": { 961 | "version": "0.1.1", 962 | "from": "p-throttler@0.1.1", 963 | "resolved": "https://registry.npmjs.org/p-throttler/-/p-throttler-0.1.1.tgz", 964 | "dependencies": { 965 | "q": { 966 | "version": "0.9.7", 967 | "from": "q@>=0.9.2 <0.10.0" 968 | } 969 | } 970 | }, 971 | "promptly": { 972 | "version": "0.2.0", 973 | "from": "promptly@0.2.0", 974 | "resolved": "https://registry.npmjs.org/promptly/-/promptly-0.2.0.tgz", 975 | "dependencies": { 976 | "read": { 977 | "version": "1.0.7", 978 | "from": "read@>=1.0.4 <1.1.0", 979 | "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", 980 | "dependencies": { 981 | "mute-stream": { 982 | "version": "0.0.5", 983 | "from": "mute-stream@>=0.0.4 <0.1.0", 984 | "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.5.tgz" 985 | } 986 | } 987 | } 988 | } 989 | }, 990 | "q": { 991 | "version": "1.4.1", 992 | "from": "q@>=1.1.2 <2.0.0", 993 | "resolved": "https://registry.npmjs.org/q/-/q-1.4.1.tgz" 994 | }, 995 | "request": { 996 | "version": "2.53.0", 997 | "from": "request@2.53.0", 998 | "resolved": "https://registry.npmjs.org/request/-/request-2.53.0.tgz", 999 | "dependencies": { 1000 | "bl": { 1001 | "version": "0.9.4", 1002 | "from": "bl@>=0.9.0 <0.10.0", 1003 | "resolved": "https://registry.npmjs.org/bl/-/bl-0.9.4.tgz", 1004 | "dependencies": { 1005 | "readable-stream": { 1006 | "version": "1.0.33", 1007 | "from": "readable-stream@>=1.0.26 <1.1.0", 1008 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.33.tgz", 1009 | "dependencies": { 1010 | "core-util-is": { 1011 | "version": "1.0.1", 1012 | "from": "core-util-is@>=1.0.0 <1.1.0", 1013 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz" 1014 | }, 1015 | "isarray": { 1016 | "version": "0.0.1", 1017 | "from": "isarray@0.0.1", 1018 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz" 1019 | }, 1020 | "string_decoder": { 1021 | "version": "0.10.31", 1022 | "from": "string_decoder@>=0.10.0 <0.11.0", 1023 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz" 1024 | }, 1025 | "inherits": { 1026 | "version": "2.0.1", 1027 | "from": "inherits@>=2.0.1 <2.1.0", 1028 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz" 1029 | } 1030 | } 1031 | } 1032 | } 1033 | }, 1034 | "caseless": { 1035 | "version": "0.9.0", 1036 | "from": "caseless@>=0.9.0 <0.10.0", 1037 | "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.9.0.tgz" 1038 | }, 1039 | "forever-agent": { 1040 | "version": "0.5.2", 1041 | "from": "forever-agent@>=0.5.0 <0.6.0", 1042 | "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.5.2.tgz" 1043 | }, 1044 | "form-data": { 1045 | "version": "0.2.0", 1046 | "from": "form-data@>=0.2.0 <0.3.0", 1047 | "resolved": "https://registry.npmjs.org/form-data/-/form-data-0.2.0.tgz", 1048 | "dependencies": { 1049 | "async": { 1050 | "version": "0.9.2", 1051 | "from": "async@>=0.9.0 <0.10.0", 1052 | "resolved": "https://registry.npmjs.org/async/-/async-0.9.2.tgz" 1053 | } 1054 | } 1055 | }, 1056 | "json-stringify-safe": { 1057 | "version": "5.0.1", 1058 | "from": "json-stringify-safe@>=5.0.0 <5.1.0", 1059 | "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz" 1060 | }, 1061 | "mime-types": { 1062 | "version": "2.0.14", 1063 | "from": "mime-types@>=2.0.1 <2.1.0", 1064 | "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.0.14.tgz", 1065 | "dependencies": { 1066 | "mime-db": { 1067 | "version": "1.12.0", 1068 | "from": "mime-db@>=1.12.0 <1.13.0", 1069 | "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.12.0.tgz" 1070 | } 1071 | } 1072 | }, 1073 | "node-uuid": { 1074 | "version": "1.4.3", 1075 | "from": "node-uuid@>=1.4.0 <1.5.0", 1076 | "resolved": "https://registry.npmjs.org/node-uuid/-/node-uuid-1.4.3.tgz" 1077 | }, 1078 | "qs": { 1079 | "version": "2.3.3", 1080 | "from": "qs@>=2.3.1 <2.4.0", 1081 | "resolved": "https://registry.npmjs.org/qs/-/qs-2.3.3.tgz" 1082 | }, 1083 | "tunnel-agent": { 1084 | "version": "0.4.1", 1085 | "from": "tunnel-agent@>=0.4.0 <0.5.0", 1086 | "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.4.1.tgz" 1087 | }, 1088 | "tough-cookie": { 1089 | "version": "2.0.0", 1090 | "from": "tough-cookie@>=0.12.0", 1091 | "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.0.0.tgz" 1092 | }, 1093 | "http-signature": { 1094 | "version": "0.10.1", 1095 | "from": "http-signature@>=0.10.0 <0.11.0", 1096 | "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-0.10.1.tgz", 1097 | "dependencies": { 1098 | "assert-plus": { 1099 | "version": "0.1.5", 1100 | "from": "assert-plus@>=0.1.5 <0.2.0", 1101 | "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-0.1.5.tgz" 1102 | }, 1103 | "asn1": { 1104 | "version": "0.1.11", 1105 | "from": "asn1@0.1.11", 1106 | "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.1.11.tgz" 1107 | }, 1108 | "ctype": { 1109 | "version": "0.5.3", 1110 | "from": "ctype@0.5.3", 1111 | "resolved": "https://registry.npmjs.org/ctype/-/ctype-0.5.3.tgz" 1112 | } 1113 | } 1114 | }, 1115 | "oauth-sign": { 1116 | "version": "0.6.0", 1117 | "from": "oauth-sign@>=0.6.0 <0.7.0", 1118 | "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.6.0.tgz" 1119 | }, 1120 | "hawk": { 1121 | "version": "2.3.1", 1122 | "from": "hawk@>=2.3.0 <2.4.0", 1123 | "resolved": "https://registry.npmjs.org/hawk/-/hawk-2.3.1.tgz", 1124 | "dependencies": { 1125 | "hoek": { 1126 | "version": "2.16.2", 1127 | "from": "hoek@>=2.0.0 <3.0.0", 1128 | "resolved": "https://registry.npmjs.org/hoek/-/hoek-2.16.2.tgz" 1129 | }, 1130 | "boom": { 1131 | "version": "2.8.0", 1132 | "from": "boom@>=2.0.0 <3.0.0", 1133 | "resolved": "https://registry.npmjs.org/boom/-/boom-2.8.0.tgz" 1134 | }, 1135 | "cryptiles": { 1136 | "version": "2.0.5", 1137 | "from": "cryptiles@>=2.0.0 <3.0.0", 1138 | "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-2.0.5.tgz" 1139 | }, 1140 | "sntp": { 1141 | "version": "1.0.9", 1142 | "from": "sntp@>=1.0.0 <2.0.0", 1143 | "resolved": "https://registry.npmjs.org/sntp/-/sntp-1.0.9.tgz" 1144 | } 1145 | } 1146 | }, 1147 | "aws-sign2": { 1148 | "version": "0.5.0", 1149 | "from": "aws-sign2@>=0.5.0 <0.6.0", 1150 | "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.5.0.tgz" 1151 | }, 1152 | "stringstream": { 1153 | "version": "0.0.4", 1154 | "from": "stringstream@>=0.0.4 <0.1.0", 1155 | "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.4.tgz" 1156 | }, 1157 | "combined-stream": { 1158 | "version": "0.0.7", 1159 | "from": "combined-stream@>=0.0.5 <0.1.0", 1160 | "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-0.0.7.tgz", 1161 | "dependencies": { 1162 | "delayed-stream": { 1163 | "version": "0.0.5", 1164 | "from": "delayed-stream@0.0.5", 1165 | "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-0.0.5.tgz" 1166 | } 1167 | } 1168 | }, 1169 | "isstream": { 1170 | "version": "0.1.2", 1171 | "from": "isstream@>=0.1.1 <0.2.0", 1172 | "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz" 1173 | } 1174 | } 1175 | }, 1176 | "request-progress": { 1177 | "version": "0.3.1", 1178 | "from": "request-progress@0.3.1", 1179 | "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-0.3.1.tgz", 1180 | "dependencies": { 1181 | "throttleit": { 1182 | "version": "0.0.2", 1183 | "from": "throttleit@>=0.0.2 <0.1.0" 1184 | } 1185 | } 1186 | }, 1187 | "retry": { 1188 | "version": "0.6.1", 1189 | "from": "retry@0.6.1", 1190 | "resolved": "https://registry.npmjs.org/retry/-/retry-0.6.1.tgz" 1191 | }, 1192 | "rimraf": { 1193 | "version": "2.4.3", 1194 | "from": "rimraf@>=2.2.8 <3.0.0", 1195 | "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.4.3.tgz", 1196 | "dependencies": { 1197 | "glob": { 1198 | "version": "5.0.14", 1199 | "from": "glob@>=5.0.14 <6.0.0", 1200 | "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.14.tgz", 1201 | "dependencies": { 1202 | "inflight": { 1203 | "version": "1.0.4", 1204 | "from": "inflight@>=1.0.4 <2.0.0", 1205 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.4.tgz", 1206 | "dependencies": { 1207 | "wrappy": { 1208 | "version": "1.0.1", 1209 | "from": "wrappy@>=1.0.0 <2.0.0", 1210 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz" 1211 | } 1212 | } 1213 | }, 1214 | "inherits": { 1215 | "version": "2.0.1", 1216 | "from": "inherits@>=2.0.0 <3.0.0", 1217 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz" 1218 | }, 1219 | "minimatch": { 1220 | "version": "2.0.10", 1221 | "from": "minimatch@>=2.0.1 <3.0.0", 1222 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", 1223 | "dependencies": { 1224 | "brace-expansion": { 1225 | "version": "1.1.0", 1226 | "from": "brace-expansion@>=1.0.0 <2.0.0", 1227 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.0.tgz", 1228 | "dependencies": { 1229 | "balanced-match": { 1230 | "version": "0.2.0", 1231 | "from": "balanced-match@>=0.2.0 <0.3.0", 1232 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.2.0.tgz" 1233 | }, 1234 | "concat-map": { 1235 | "version": "0.0.1", 1236 | "from": "concat-map@0.0.1", 1237 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" 1238 | } 1239 | } 1240 | } 1241 | } 1242 | }, 1243 | "once": { 1244 | "version": "1.3.2", 1245 | "from": "once@>=1.3.0 <2.0.0", 1246 | "resolved": "https://registry.npmjs.org/once/-/once-1.3.2.tgz", 1247 | "dependencies": { 1248 | "wrappy": { 1249 | "version": "1.0.1", 1250 | "from": "wrappy@>=1.0.0 <2.0.0", 1251 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz" 1252 | } 1253 | } 1254 | }, 1255 | "path-is-absolute": { 1256 | "version": "1.0.0", 1257 | "from": "path-is-absolute@>=1.0.0 <2.0.0", 1258 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz" 1259 | } 1260 | } 1261 | } 1262 | } 1263 | }, 1264 | "semver": { 1265 | "version": "2.3.2", 1266 | "from": "semver@>=2.3.0 <3.0.0", 1267 | "resolved": "https://registry.npmjs.org/semver/-/semver-2.3.2.tgz" 1268 | }, 1269 | "shell-quote": { 1270 | "version": "1.4.3", 1271 | "from": "shell-quote@>=1.4.2 <2.0.0", 1272 | "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.4.3.tgz", 1273 | "dependencies": { 1274 | "jsonify": { 1275 | "version": "0.0.0", 1276 | "from": "jsonify@>=0.0.0 <0.1.0", 1277 | "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz" 1278 | }, 1279 | "array-filter": { 1280 | "version": "0.0.1", 1281 | "from": "array-filter@>=0.0.0 <0.1.0", 1282 | "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-0.0.1.tgz" 1283 | }, 1284 | "array-reduce": { 1285 | "version": "0.0.0", 1286 | "from": "array-reduce@>=0.0.0 <0.1.0", 1287 | "resolved": "https://registry.npmjs.org/array-reduce/-/array-reduce-0.0.0.tgz" 1288 | }, 1289 | "array-map": { 1290 | "version": "0.0.0", 1291 | "from": "array-map@>=0.0.0 <0.1.0", 1292 | "resolved": "https://registry.npmjs.org/array-map/-/array-map-0.0.0.tgz" 1293 | } 1294 | } 1295 | }, 1296 | "stringify-object": { 1297 | "version": "1.0.1", 1298 | "from": "stringify-object@>=1.0.0 <2.0.0", 1299 | "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-1.0.1.tgz" 1300 | }, 1301 | "tar-fs": { 1302 | "version": "1.8.1", 1303 | "from": "tar-fs@>=1.4.1 <2.0.0", 1304 | "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-1.8.1.tgz", 1305 | "dependencies": { 1306 | "pump": { 1307 | "version": "1.0.0", 1308 | "from": "pump@>=1.0.0 <2.0.0", 1309 | "resolved": "https://registry.npmjs.org/pump/-/pump-1.0.0.tgz", 1310 | "dependencies": { 1311 | "end-of-stream": { 1312 | "version": "1.1.0", 1313 | "from": "end-of-stream@>=1.1.0 <2.0.0" 1314 | }, 1315 | "once": { 1316 | "version": "1.3.2", 1317 | "from": "once@>=1.3.1 <2.0.0", 1318 | "resolved": "https://registry.npmjs.org/once/-/once-1.3.2.tgz", 1319 | "dependencies": { 1320 | "wrappy": { 1321 | "version": "1.0.1", 1322 | "from": "wrappy@>=1.0.0 <2.0.0", 1323 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz" 1324 | } 1325 | } 1326 | } 1327 | } 1328 | }, 1329 | "tar-stream": { 1330 | "version": "1.2.1", 1331 | "from": "tar-stream@>=1.1.2 <2.0.0", 1332 | "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-1.2.1.tgz", 1333 | "dependencies": { 1334 | "bl": { 1335 | "version": "1.0.0", 1336 | "from": "bl@>=1.0.0 <2.0.0", 1337 | "resolved": "https://registry.npmjs.org/bl/-/bl-1.0.0.tgz" 1338 | }, 1339 | "end-of-stream": { 1340 | "version": "1.1.0", 1341 | "from": "end-of-stream@>=1.1.0 <2.0.0", 1342 | "dependencies": { 1343 | "once": { 1344 | "version": "1.3.2", 1345 | "from": "once@>=1.3.0 <1.4.0", 1346 | "resolved": "https://registry.npmjs.org/once/-/once-1.3.2.tgz", 1347 | "dependencies": { 1348 | "wrappy": { 1349 | "version": "1.0.1", 1350 | "from": "wrappy@>=1.0.0 <2.0.0", 1351 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz" 1352 | } 1353 | } 1354 | } 1355 | } 1356 | }, 1357 | "readable-stream": { 1358 | "version": "2.0.2", 1359 | "from": "readable-stream@>=2.0.0 <3.0.0", 1360 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.2.tgz", 1361 | "dependencies": { 1362 | "core-util-is": { 1363 | "version": "1.0.1", 1364 | "from": "core-util-is@>=1.0.0 <1.1.0", 1365 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz" 1366 | }, 1367 | "inherits": { 1368 | "version": "2.0.1", 1369 | "from": "inherits@>=2.0.1 <2.1.0", 1370 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz" 1371 | }, 1372 | "isarray": { 1373 | "version": "0.0.1", 1374 | "from": "isarray@0.0.1", 1375 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz" 1376 | }, 1377 | "process-nextick-args": { 1378 | "version": "1.0.3", 1379 | "from": "process-nextick-args@>=1.0.0 <1.1.0", 1380 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.3.tgz" 1381 | }, 1382 | "string_decoder": { 1383 | "version": "0.10.31", 1384 | "from": "string_decoder@>=0.10.0 <0.11.0", 1385 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz" 1386 | }, 1387 | "util-deprecate": { 1388 | "version": "1.0.1", 1389 | "from": "util-deprecate@>=1.0.1 <1.1.0", 1390 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.1.tgz" 1391 | } 1392 | } 1393 | }, 1394 | "xtend": { 1395 | "version": "4.0.0", 1396 | "from": "xtend@>=4.0.0 <5.0.0", 1397 | "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.0.tgz" 1398 | } 1399 | } 1400 | } 1401 | } 1402 | }, 1403 | "tmp": { 1404 | "version": "0.0.24", 1405 | "from": "tmp@0.0.24", 1406 | "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.24.tgz" 1407 | }, 1408 | "update-notifier": { 1409 | "version": "0.3.2", 1410 | "from": "update-notifier@>=0.3.0 <0.4.0", 1411 | "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-0.3.2.tgz", 1412 | "dependencies": { 1413 | "is-npm": { 1414 | "version": "1.0.0", 1415 | "from": "is-npm@>=1.0.0 <2.0.0" 1416 | }, 1417 | "latest-version": { 1418 | "version": "1.0.1", 1419 | "from": "latest-version@>=1.0.0 <2.0.0", 1420 | "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-1.0.1.tgz", 1421 | "dependencies": { 1422 | "package-json": { 1423 | "version": "1.2.0", 1424 | "from": "package-json@>=1.0.0 <2.0.0", 1425 | "resolved": "https://registry.npmjs.org/package-json/-/package-json-1.2.0.tgz", 1426 | "dependencies": { 1427 | "got": { 1428 | "version": "3.3.1", 1429 | "from": "got@>=3.2.0 <4.0.0", 1430 | "resolved": "https://registry.npmjs.org/got/-/got-3.3.1.tgz", 1431 | "dependencies": { 1432 | "duplexify": { 1433 | "version": "3.4.2", 1434 | "from": "duplexify@>=3.2.0 <4.0.0", 1435 | "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.4.2.tgz", 1436 | "dependencies": { 1437 | "end-of-stream": { 1438 | "version": "1.0.0", 1439 | "from": "end-of-stream@1.0.0", 1440 | "dependencies": { 1441 | "once": { 1442 | "version": "1.3.2", 1443 | "from": "once@>=1.3.0 <1.4.0", 1444 | "resolved": "https://registry.npmjs.org/once/-/once-1.3.2.tgz", 1445 | "dependencies": { 1446 | "wrappy": { 1447 | "version": "1.0.1", 1448 | "from": "wrappy@>=1.0.0 <2.0.0", 1449 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz" 1450 | } 1451 | } 1452 | } 1453 | } 1454 | }, 1455 | "readable-stream": { 1456 | "version": "2.0.2", 1457 | "from": "readable-stream@>=2.0.0 <3.0.0", 1458 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.2.tgz", 1459 | "dependencies": { 1460 | "core-util-is": { 1461 | "version": "1.0.1", 1462 | "from": "core-util-is@>=1.0.0 <1.1.0", 1463 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz" 1464 | }, 1465 | "inherits": { 1466 | "version": "2.0.1", 1467 | "from": "inherits@>=2.0.1 <2.1.0", 1468 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz" 1469 | }, 1470 | "isarray": { 1471 | "version": "0.0.1", 1472 | "from": "isarray@0.0.1", 1473 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz" 1474 | }, 1475 | "process-nextick-args": { 1476 | "version": "1.0.3", 1477 | "from": "process-nextick-args@>=1.0.0 <1.1.0", 1478 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.3.tgz" 1479 | }, 1480 | "string_decoder": { 1481 | "version": "0.10.31", 1482 | "from": "string_decoder@>=0.10.0 <0.11.0", 1483 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz" 1484 | }, 1485 | "util-deprecate": { 1486 | "version": "1.0.1", 1487 | "from": "util-deprecate@>=1.0.1 <1.1.0", 1488 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.1.tgz" 1489 | } 1490 | } 1491 | } 1492 | } 1493 | }, 1494 | "infinity-agent": { 1495 | "version": "2.0.3", 1496 | "from": "infinity-agent@>=2.0.0 <3.0.0", 1497 | "resolved": "https://registry.npmjs.org/infinity-agent/-/infinity-agent-2.0.3.tgz" 1498 | }, 1499 | "is-redirect": { 1500 | "version": "1.0.0", 1501 | "from": "is-redirect@>=1.0.0 <2.0.0", 1502 | "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz" 1503 | }, 1504 | "is-stream": { 1505 | "version": "1.0.1", 1506 | "from": "is-stream@>=1.0.0 <2.0.0" 1507 | }, 1508 | "lowercase-keys": { 1509 | "version": "1.0.0", 1510 | "from": "lowercase-keys@>=1.0.0 <2.0.0" 1511 | }, 1512 | "nested-error-stacks": { 1513 | "version": "1.0.1", 1514 | "from": "nested-error-stacks@>=1.0.0 <2.0.0", 1515 | "resolved": "https://registry.npmjs.org/nested-error-stacks/-/nested-error-stacks-1.0.1.tgz", 1516 | "dependencies": { 1517 | "inherits": { 1518 | "version": "2.0.1", 1519 | "from": "inherits@>=2.0.0 <3.0.0", 1520 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz" 1521 | } 1522 | } 1523 | }, 1524 | "object-assign": { 1525 | "version": "3.0.0", 1526 | "from": "object-assign@>=3.0.0 <4.0.0", 1527 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz" 1528 | }, 1529 | "prepend-http": { 1530 | "version": "1.0.3", 1531 | "from": "prepend-http@>=1.0.0 <2.0.0", 1532 | "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.3.tgz" 1533 | }, 1534 | "read-all-stream": { 1535 | "version": "3.0.1", 1536 | "from": "read-all-stream@>=3.0.0 <4.0.0", 1537 | "resolved": "https://registry.npmjs.org/read-all-stream/-/read-all-stream-3.0.1.tgz", 1538 | "dependencies": { 1539 | "pinkie-promise": { 1540 | "version": "1.0.0", 1541 | "from": "pinkie-promise@>=1.0.0 <2.0.0", 1542 | "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-1.0.0.tgz", 1543 | "dependencies": { 1544 | "pinkie": { 1545 | "version": "1.0.0", 1546 | "from": "pinkie@>=1.0.0 <2.0.0", 1547 | "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-1.0.0.tgz" 1548 | } 1549 | } 1550 | }, 1551 | "readable-stream": { 1552 | "version": "2.0.2", 1553 | "from": "readable-stream@>=2.0.0 <3.0.0", 1554 | "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.0.2.tgz", 1555 | "dependencies": { 1556 | "core-util-is": { 1557 | "version": "1.0.1", 1558 | "from": "core-util-is@>=1.0.0 <1.1.0", 1559 | "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.1.tgz" 1560 | }, 1561 | "inherits": { 1562 | "version": "2.0.1", 1563 | "from": "inherits@>=2.0.1 <2.1.0", 1564 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz" 1565 | }, 1566 | "isarray": { 1567 | "version": "0.0.1", 1568 | "from": "isarray@0.0.1", 1569 | "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz" 1570 | }, 1571 | "process-nextick-args": { 1572 | "version": "1.0.3", 1573 | "from": "process-nextick-args@>=1.0.0 <1.1.0", 1574 | "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.3.tgz" 1575 | }, 1576 | "string_decoder": { 1577 | "version": "0.10.31", 1578 | "from": "string_decoder@>=0.10.0 <0.11.0", 1579 | "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz" 1580 | }, 1581 | "util-deprecate": { 1582 | "version": "1.0.1", 1583 | "from": "util-deprecate@>=1.0.1 <1.1.0", 1584 | "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.1.tgz" 1585 | } 1586 | } 1587 | } 1588 | } 1589 | }, 1590 | "timed-out": { 1591 | "version": "2.0.0", 1592 | "from": "timed-out@>=2.0.0 <3.0.0" 1593 | } 1594 | } 1595 | }, 1596 | "registry-url": { 1597 | "version": "3.0.3", 1598 | "from": "registry-url@>=3.0.0 <4.0.0", 1599 | "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-3.0.3.tgz", 1600 | "dependencies": { 1601 | "rc": { 1602 | "version": "1.1.1", 1603 | "from": "rc@>=1.0.1 <2.0.0", 1604 | "resolved": "https://registry.npmjs.org/rc/-/rc-1.1.1.tgz", 1605 | "dependencies": { 1606 | "minimist": { 1607 | "version": "1.2.0", 1608 | "from": "minimist@>=1.1.2 <2.0.0", 1609 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz" 1610 | }, 1611 | "deep-extend": { 1612 | "version": "0.2.11", 1613 | "from": "deep-extend@>=0.2.5 <0.3.0" 1614 | }, 1615 | "strip-json-comments": { 1616 | "version": "0.1.3", 1617 | "from": "strip-json-comments@>=0.1.0 <0.2.0", 1618 | "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-0.1.3.tgz" 1619 | }, 1620 | "ini": { 1621 | "version": "1.3.4", 1622 | "from": "ini@>=1.3.0 <1.4.0", 1623 | "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz" 1624 | } 1625 | } 1626 | } 1627 | } 1628 | } 1629 | } 1630 | } 1631 | } 1632 | }, 1633 | "semver-diff": { 1634 | "version": "2.0.0", 1635 | "from": "semver-diff@>=2.0.0 <3.0.0", 1636 | "dependencies": { 1637 | "semver": { 1638 | "version": "4.3.6", 1639 | "from": "semver@>=4.0.0 <5.0.0", 1640 | "resolved": "https://registry.npmjs.org/semver/-/semver-4.3.6.tgz" 1641 | } 1642 | } 1643 | }, 1644 | "string-length": { 1645 | "version": "1.0.1", 1646 | "from": "string-length@>=1.0.0 <2.0.0", 1647 | "resolved": "https://registry.npmjs.org/string-length/-/string-length-1.0.1.tgz", 1648 | "dependencies": { 1649 | "strip-ansi": { 1650 | "version": "3.0.0", 1651 | "from": "strip-ansi@>=3.0.0 <4.0.0", 1652 | "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.0.tgz", 1653 | "dependencies": { 1654 | "ansi-regex": { 1655 | "version": "2.0.0", 1656 | "from": "ansi-regex@>=2.0.0 <3.0.0", 1657 | "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.0.0.tgz" 1658 | } 1659 | } 1660 | } 1661 | } 1662 | } 1663 | } 1664 | }, 1665 | "user-home": { 1666 | "version": "1.1.1", 1667 | "from": "user-home@>=1.1.0 <2.0.0", 1668 | "resolved": "https://registry.npmjs.org/user-home/-/user-home-1.1.1.tgz" 1669 | }, 1670 | "which": { 1671 | "version": "1.1.2", 1672 | "from": "which@>=1.0.8 <2.0.0", 1673 | "resolved": "https://registry.npmjs.org/which/-/which-1.1.2.tgz", 1674 | "dependencies": { 1675 | "is-absolute": { 1676 | "version": "0.1.7", 1677 | "from": "is-absolute@>=0.1.7 <0.2.0", 1678 | "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-0.1.7.tgz", 1679 | "dependencies": { 1680 | "is-relative": { 1681 | "version": "0.1.3", 1682 | "from": "is-relative@>=0.1.0 <0.2.0", 1683 | "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-0.1.3.tgz" 1684 | } 1685 | } 1686 | } 1687 | } 1688 | } 1689 | } 1690 | }, 1691 | "reveal-md": { 1692 | "version": "0.0.20", 1693 | "from": "reveal-md@0.0.20", 1694 | "resolved": "https://registry.npmjs.org/reveal-md/-/reveal-md-0.0.20.tgz", 1695 | "dependencies": { 1696 | "reveal.js": { 1697 | "version": "3.1.0", 1698 | "from": "reveal.js@3.1.0", 1699 | "resolved": "https://registry.npmjs.org/reveal.js/-/reveal.js-3.1.0.tgz", 1700 | "dependencies": { 1701 | "underscore": { 1702 | "version": "1.5.2", 1703 | "from": "underscore@>=1.5.1 <1.6.0", 1704 | "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.5.2.tgz" 1705 | }, 1706 | "express": { 1707 | "version": "2.5.11", 1708 | "from": "express@>=2.5.9 <2.6.0", 1709 | "resolved": "https://registry.npmjs.org/express/-/express-2.5.11.tgz", 1710 | "dependencies": { 1711 | "connect": { 1712 | "version": "1.9.2", 1713 | "from": "connect@>=1.0.0 <2.0.0", 1714 | "resolved": "https://registry.npmjs.org/connect/-/connect-1.9.2.tgz", 1715 | "dependencies": { 1716 | "formidable": { 1717 | "version": "1.0.17", 1718 | "from": "formidable@>=1.0.0 <1.1.0", 1719 | "resolved": "https://registry.npmjs.org/formidable/-/formidable-1.0.17.tgz" 1720 | } 1721 | } 1722 | }, 1723 | "mime": { 1724 | "version": "1.2.4", 1725 | "from": "mime@1.2.4", 1726 | "resolved": "https://registry.npmjs.org/mime/-/mime-1.2.4.tgz" 1727 | }, 1728 | "qs": { 1729 | "version": "0.4.2", 1730 | "from": "qs@>=0.4.0 <0.5.0", 1731 | "resolved": "https://registry.npmjs.org/qs/-/qs-0.4.2.tgz" 1732 | }, 1733 | "mkdirp": { 1734 | "version": "0.3.0", 1735 | "from": "mkdirp@0.3.0" 1736 | } 1737 | } 1738 | }, 1739 | "mustache": { 1740 | "version": "0.7.3", 1741 | "from": "mustache@>=0.7.2 <0.8.0", 1742 | "resolved": "https://registry.npmjs.org/mustache/-/mustache-0.7.3.tgz" 1743 | }, 1744 | "socket.io": { 1745 | "version": "0.9.17", 1746 | "from": "socket.io@>=0.9.16 <0.10.0", 1747 | "dependencies": { 1748 | "socket.io-client": { 1749 | "version": "0.9.16", 1750 | "from": "socket.io-client@0.9.16", 1751 | "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-0.9.16.tgz", 1752 | "dependencies": { 1753 | "uglify-js": { 1754 | "version": "1.2.5", 1755 | "from": "uglify-js@1.2.5", 1756 | "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-1.2.5.tgz" 1757 | }, 1758 | "ws": { 1759 | "version": "0.4.32", 1760 | "from": "ws@>=0.4.0 <0.5.0", 1761 | "dependencies": { 1762 | "commander": { 1763 | "version": "2.1.0", 1764 | "from": "commander@>=2.1.0 <2.2.0" 1765 | }, 1766 | "nan": { 1767 | "version": "1.0.0", 1768 | "from": "nan@>=1.0.0 <1.1.0" 1769 | }, 1770 | "tinycolor": { 1771 | "version": "0.0.1", 1772 | "from": "tinycolor@>=0.0.0 <1.0.0", 1773 | "resolved": "https://registry.npmjs.org/tinycolor/-/tinycolor-0.0.1.tgz" 1774 | }, 1775 | "options": { 1776 | "version": "0.0.6", 1777 | "from": "options@>=0.0.5", 1778 | "resolved": "https://registry.npmjs.org/options/-/options-0.0.6.tgz" 1779 | } 1780 | } 1781 | }, 1782 | "xmlhttprequest": { 1783 | "version": "1.4.2", 1784 | "from": "xmlhttprequest@1.4.2", 1785 | "resolved": "https://registry.npmjs.org/xmlhttprequest/-/xmlhttprequest-1.4.2.tgz" 1786 | }, 1787 | "active-x-obfuscator": { 1788 | "version": "0.0.1", 1789 | "from": "active-x-obfuscator@0.0.1", 1790 | "resolved": "https://registry.npmjs.org/active-x-obfuscator/-/active-x-obfuscator-0.0.1.tgz", 1791 | "dependencies": { 1792 | "zeparser": { 1793 | "version": "0.0.5", 1794 | "from": "zeparser@0.0.5", 1795 | "resolved": "https://registry.npmjs.org/zeparser/-/zeparser-0.0.5.tgz" 1796 | } 1797 | } 1798 | } 1799 | } 1800 | }, 1801 | "policyfile": { 1802 | "version": "0.0.4", 1803 | "from": "policyfile@0.0.4", 1804 | "resolved": "https://registry.npmjs.org/policyfile/-/policyfile-0.0.4.tgz" 1805 | }, 1806 | "base64id": { 1807 | "version": "0.1.0", 1808 | "from": "base64id@0.1.0", 1809 | "resolved": "https://registry.npmjs.org/base64id/-/base64id-0.1.0.tgz" 1810 | }, 1811 | "redis": { 1812 | "version": "0.7.3", 1813 | "from": "redis@0.7.3", 1814 | "resolved": "https://registry.npmjs.org/redis/-/redis-0.7.3.tgz" 1815 | } 1816 | } 1817 | } 1818 | } 1819 | }, 1820 | "mustache": { 1821 | "version": "2.1.3", 1822 | "from": "mustache@2.1.3", 1823 | "resolved": "https://registry.npmjs.org/mustache/-/mustache-2.1.3.tgz" 1824 | }, 1825 | "open": { 1826 | "version": "0.0.5", 1827 | "from": "open@0.0.5", 1828 | "resolved": "https://registry.npmjs.org/open/-/open-0.0.5.tgz" 1829 | }, 1830 | "glob": { 1831 | "version": "5.0.14", 1832 | "from": "glob@5.0.14", 1833 | "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.14.tgz", 1834 | "dependencies": { 1835 | "inflight": { 1836 | "version": "1.0.4", 1837 | "from": "inflight@>=1.0.4 <2.0.0", 1838 | "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.4.tgz", 1839 | "dependencies": { 1840 | "wrappy": { 1841 | "version": "1.0.1", 1842 | "from": "wrappy@>=1.0.0 <2.0.0", 1843 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz" 1844 | } 1845 | } 1846 | }, 1847 | "inherits": { 1848 | "version": "2.0.1", 1849 | "from": "inherits@>=2.0.1 <2.1.0", 1850 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz" 1851 | }, 1852 | "minimatch": { 1853 | "version": "2.0.10", 1854 | "from": "minimatch@>=2.0.1 <3.0.0", 1855 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-2.0.10.tgz", 1856 | "dependencies": { 1857 | "brace-expansion": { 1858 | "version": "1.1.0", 1859 | "from": "brace-expansion@>=1.0.0 <2.0.0", 1860 | "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.0.tgz", 1861 | "dependencies": { 1862 | "balanced-match": { 1863 | "version": "0.2.0", 1864 | "from": "balanced-match@>=0.2.0 <0.3.0", 1865 | "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-0.2.0.tgz" 1866 | }, 1867 | "concat-map": { 1868 | "version": "0.0.1", 1869 | "from": "concat-map@0.0.1", 1870 | "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" 1871 | } 1872 | } 1873 | } 1874 | } 1875 | }, 1876 | "once": { 1877 | "version": "1.3.2", 1878 | "from": "once@>=1.3.0 <2.0.0", 1879 | "resolved": "https://registry.npmjs.org/once/-/once-1.3.2.tgz", 1880 | "dependencies": { 1881 | "wrappy": { 1882 | "version": "1.0.1", 1883 | "from": "wrappy@>=1.0.0 <2.0.0", 1884 | "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.1.tgz" 1885 | } 1886 | } 1887 | }, 1888 | "path-is-absolute": { 1889 | "version": "1.0.0", 1890 | "from": "path-is-absolute@>=1.0.0 <2.0.0", 1891 | "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.0.tgz" 1892 | } 1893 | } 1894 | }, 1895 | "commander": { 1896 | "version": "2.8.1", 1897 | "from": "commander@2.8.1", 1898 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.8.1.tgz", 1899 | "dependencies": { 1900 | "graceful-readlink": { 1901 | "version": "1.0.1", 1902 | "from": "graceful-readlink@>=1.0.0", 1903 | "resolved": "https://registry.npmjs.org/graceful-readlink/-/graceful-readlink-1.0.1.tgz" 1904 | } 1905 | } 1906 | }, 1907 | "highlight.js": { 1908 | "version": "8.7.0", 1909 | "from": "highlight.js@8.7.0", 1910 | "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-8.7.0.tgz" 1911 | } 1912 | } 1913 | } 1914 | } 1915 | } 1916 | --------------------------------------------------------------------------------