From 1572cc0d999e2352cfe52d09ec8ff62f910cc28c Mon Sep 17 00:00:00 2001 From: SKatiyar Date: Sun, 12 Jul 2015 20:46:27 +0530 Subject: [PATCH 01/49] added server folder --- server/README.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 server/README.md diff --git a/server/README.md b/server/README.md new file mode 100644 index 0000000..944eff0 --- /dev/null +++ b/server/README.md @@ -0,0 +1 @@ +## Trapped Server From 67c277d75778bf1878ceb4c910d3695e132bc022 Mon Sep 17 00:00:00 2001 From: ghome vic Date: Mon, 13 Jul 2015 02:21:12 +0530 Subject: [PATCH 02/49] Init Client. --- client/README.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 client/README.md diff --git a/client/README.md b/client/README.md new file mode 100644 index 0000000..e69de29 From f4eacc199cfda3c104ce2b0c9488aa4c4fe44616 Mon Sep 17 00:00:00 2001 From: ghome vic Date: Mon, 13 Jul 2015 02:22:17 +0530 Subject: [PATCH 03/49] Configurations added. --- client/config/development.json | 3 +++ client/config/production.json | 3 +++ client/package.json | 36 ++++++++++++++++++++++++++++++++++ client/webpack.config.js | 33 +++++++++++++++++++++++++++++++ 4 files changed, 75 insertions(+) create mode 100644 client/config/development.json create mode 100644 client/config/production.json create mode 100644 client/package.json create mode 100644 client/webpack.config.js diff --git a/client/config/development.json b/client/config/development.json new file mode 100644 index 0000000..c1a6cb0 --- /dev/null +++ b/client/config/development.json @@ -0,0 +1,3 @@ +{ + "env" : "development" +} diff --git a/client/config/production.json b/client/config/production.json new file mode 100644 index 0000000..77d1841 --- /dev/null +++ b/client/config/production.json @@ -0,0 +1,3 @@ +{ + "env" : "production" +} diff --git a/client/package.json b/client/package.json new file mode 100644 index 0000000..7234ba3 --- /dev/null +++ b/client/package.json @@ -0,0 +1,36 @@ +{ + "name": "entrapped", + "version": "1.0.0", + "description": "Tiny little minefield of our dreams.", + "main": "app.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "https://github.com/SKatiyar/entrapped" + }, + "keywords": [ + "mine", + "field", + "boom" + ], + "author": "Rabi C Shah", + "license": "ISC", + "bugs": { + "url": "https://github.com/SKatiyar/entrapped/issues" + }, + "homepage": "https://github.com/SKatiyar/entrapped", + "devDependencies": { + "babel-core": "^5.6.18", + "babel-loader": "^5.3.1", + "file-loader": "^0.8.4", + "node-libs-browser": "^0.5.2", + "webpack": "^1.10.1" + }, + "dependencies": { + "flux": "^2.0.3", + "react": "^0.13.3", + "react-router": "^0.13.3" + } +} diff --git a/client/webpack.config.js b/client/webpack.config.js new file mode 100644 index 0000000..f1faea7 --- /dev/null +++ b/client/webpack.config.js @@ -0,0 +1,33 @@ +'use strict' + +var src = '/src', + dist = '/dist'; + +module.exports = { + context: __dirname + '/src', + entry: [ + './app.jsx', + './templates/index.html' + ], + + output: { + filename: 'app.js', + path: __dirname + '/dist' + }, + + debug : false, + + module: { + loaders: [ + { + test: /\.jsx?$/, + exclude: /node_modules/, + loader: 'babel-loader' + }, + { + test: /\.html$/, + loader: "file?name=[name].[ext]", + }, + ] + } +}; From 49abab97796c5e701f6fdc16370a15e195c15061 Mon Sep 17 00:00:00 2001 From: ghome vic Date: Mon, 13 Jul 2015 02:22:53 +0530 Subject: [PATCH 04/49] Source code. --- client/src/app.jsx | 28 ++++++++++++++++++++++++++++ client/src/components/Home.jsx | 16 ++++++++++++++++ client/src/components/Minefield.jsx | 13 +++++++++++++ client/src/templates/index.html | 9 +++++++++ 4 files changed, 66 insertions(+) create mode 100644 client/src/app.jsx create mode 100644 client/src/components/Home.jsx create mode 100644 client/src/components/Minefield.jsx create mode 100644 client/src/templates/index.html diff --git a/client/src/app.jsx b/client/src/app.jsx new file mode 100644 index 0000000..83c8dac --- /dev/null +++ b/client/src/app.jsx @@ -0,0 +1,28 @@ +'use strict'; + +import React from 'react'; +import Router from 'react-router'; +import { DefaultRoute, Route, RouteHandler } from 'react-router'; + +import Home from './components/Home.jsx'; +import Minefield from './components/Minefield.jsx'; + +let App = React.createClass({ + render() { + return ( + + ); + } +}); + +let Routes = ( + + + + + +) + +Router.run(Routes, function(Handler) { + React.render(, document.body); +}); diff --git a/client/src/components/Home.jsx b/client/src/components/Home.jsx new file mode 100644 index 0000000..1b55f29 --- /dev/null +++ b/client/src/components/Home.jsx @@ -0,0 +1,16 @@ +import React from 'react'; +import { Router, Link } from 'react-router'; + +class Home extends React.Component { + render() { + return ( +
+

Entrapped v0.0

+
Tiny little minefield of our dreams.
+ Play +
+ ) + } +}; + +export default Home; diff --git a/client/src/components/Minefield.jsx b/client/src/components/Minefield.jsx new file mode 100644 index 0000000..c96f760 --- /dev/null +++ b/client/src/components/Minefield.jsx @@ -0,0 +1,13 @@ +import React from 'react'; + +class Minefield extends React.Component { + render() { + return ( +
+
Mines Mines every where.
+
+ ) + } +}; + +export default Minefield; diff --git a/client/src/templates/index.html b/client/src/templates/index.html new file mode 100644 index 0000000..9f1d688 --- /dev/null +++ b/client/src/templates/index.html @@ -0,0 +1,9 @@ + + + + + Webpack + React + + + + From 91e27bd7e343cde8d4d5e39faa3c124a475392ff Mon Sep 17 00:00:00 2001 From: ghome vic Date: Mon, 13 Jul 2015 02:27:39 +0530 Subject: [PATCH 05/49] Ignored. Added. --- client/.gitignore | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 client/.gitignore diff --git a/client/.gitignore b/client/.gitignore new file mode 100644 index 0000000..de4d1f0 --- /dev/null +++ b/client/.gitignore @@ -0,0 +1,2 @@ +dist +node_modules From a0cce88b480f3783c3d9363bc45b5acbc981aba1 Mon Sep 17 00:00:00 2001 From: ghome vic Date: Mon, 13 Jul 2015 04:17:37 +0530 Subject: [PATCH 06/49] React hot reload and webpack dev server introduced. --- client/package.json | 9 +++++++-- client/webpack.config.js | 21 +++++++++++++++------ 2 files changed, 22 insertions(+), 8 deletions(-) diff --git a/client/package.json b/client/package.json index 7234ba3..0a9ca68 100644 --- a/client/package.json +++ b/client/package.json @@ -4,7 +4,9 @@ "description": "Tiny little minefield of our dreams.", "main": "app.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "test": "echo \"Error: no test specified\" && exit 1", + "start": "webpack-dev-server --hot --progress --colors --port 3000", + "build": "webpack --progress --colors" }, "repository": { "type": "git", @@ -22,11 +24,14 @@ }, "homepage": "https://github.com/SKatiyar/entrapped", "devDependencies": { + "babel": "^5.6.14", "babel-core": "^5.6.18", "babel-loader": "^5.3.1", "file-loader": "^0.8.4", "node-libs-browser": "^0.5.2", - "webpack": "^1.10.1" + "react-hot-loader": "^1.2.8", + "webpack": "^1.10.1", + "webpack-dev-server": "^1.10.1" }, "dependencies": { "flux": "^2.0.3", diff --git a/client/webpack.config.js b/client/webpack.config.js index f1faea7..64f0c7c 100644 --- a/client/webpack.config.js +++ b/client/webpack.config.js @@ -1,13 +1,12 @@ 'use strict' -var src = '/src', - dist = '/dist'; +var webpack = require('webpack'); module.exports = { - context: __dirname + '/src', entry: [ - './app.jsx', - './templates/index.html' + 'webpack/hot/only-dev-server', + './src/app.jsx', + './src/templates/index.html' ], output: { @@ -22,6 +21,11 @@ module.exports = { { test: /\.jsx?$/, exclude: /node_modules/, + loaders: ['react-hot', 'babel'] + }, + { + test: /\.js$/, + exclude: /node_modules/, loader: 'babel-loader' }, { @@ -29,5 +33,10 @@ module.exports = { loader: "file?name=[name].[ext]", }, ] - } + }, + + plugins: [ + new webpack.HotModuleReplacementPlugin(), + new webpack.NoErrorsPlugin() + ] }; From fe92fd1804a6d3f2d3eb104550b8011a58de5c13 Mon Sep 17 00:00:00 2001 From: ghome vic Date: Mon, 13 Jul 2015 16:44:24 +0530 Subject: [PATCH 07/49] Minefields introduced. --- client/package.json | 1 + client/src/components/Blocks.jsx | 71 ++++++++++++++++++++++++ client/src/components/Minefield.jsx | 42 +++++++++++++- client/src/constants/app_constants.js | 15 +++++ client/src/dispatchers/app_dispatcher.js | 22 ++++++++ client/src/stores/minestore.js | 66 ++++++++++++++++++++++ client/src/styles/main.css | 60 ++++++++++++++++++++ client/src/templates/index.html | 3 + client/webpack.config.js | 7 ++- 9 files changed, 285 insertions(+), 2 deletions(-) create mode 100644 client/src/components/Blocks.jsx create mode 100644 client/src/constants/app_constants.js create mode 100644 client/src/dispatchers/app_dispatcher.js create mode 100644 client/src/stores/minestore.js create mode 100644 client/src/styles/main.css diff --git a/client/package.json b/client/package.json index 0a9ca68..bbc83d8 100644 --- a/client/package.json +++ b/client/package.json @@ -35,6 +35,7 @@ }, "dependencies": { "flux": "^2.0.3", + "object-assign": "^3.0.0", "react": "^0.13.3", "react-router": "^0.13.3" } diff --git a/client/src/components/Blocks.jsx b/client/src/components/Blocks.jsx new file mode 100644 index 0000000..095fc56 --- /dev/null +++ b/client/src/components/Blocks.jsx @@ -0,0 +1,71 @@ +import React from 'react/addons'; + +/** + * Returns a random integer between min (inclusive) and max (inclusive) + * Using Math.round() will give you a non-uniform distribution! + */ +function getRandomInt(min, max) { + return Math.floor(Math.random() * (max - min + 1)) + min; +} + +class Block extends React.Component { + constructor(props) { + super(props); + this.handleClick = this.handleClick.bind(this); + } + + render() { + var cx = React.addons.classSet; + var classes = cx({ + 'block': true, + 'block__visited': this.props.status === -1, + 'block__dead': this.props.status === -2 + }); + + return( + + ) + } + + handleClick() { + console.log('clicked block', this); + } +}; +Block.propTypes = { status: React.PropTypes.number }; +Block.defaultProps = { status: 0 }; + +class Blocks extends React.Component { + constructor(props) { + super(props); + console.log('props', props); + } + + render() { + + var nodes = []; + var size = this.props.size; + + /* construct blocks */ + for (var i = 0; i < size; i++) { + var _blocks = []; + + for (var j = 0; j < size; j++) { + _blocks.push(); + } + + nodes.push(({_blocks})); + } + + return ( + + + {nodes} + +
+ ); + } +}; +Blocks.propTypes = { size: React.PropTypes.number, mines: React.PropTypes.array }; +Blocks.defaultProps = { size: 7, mines: [] } + +export default Blocks; diff --git a/client/src/components/Minefield.jsx b/client/src/components/Minefield.jsx index c96f760..31259ac 100644 --- a/client/src/components/Minefield.jsx +++ b/client/src/components/Minefield.jsx @@ -1,10 +1,50 @@ import React from 'react'; +import Blocks from './Blocks.jsx'; +import MinesStore from '../stores/minestore.js'; + class Minefield extends React.Component { + constructor() { + super(); + this.state = { + mines : MinesStore.getMines() + } + } + render() { return (
-
Mines Mines every where.
+

Your Turn

+ +
+
+
Enemy Minefield. Click on a block to place a mine.
+ +
+ + + + + + + +
+
+ +
+
Your Minefield.
+ +
+ + + + + + + +
+
+
) } diff --git a/client/src/constants/app_constants.js b/client/src/constants/app_constants.js new file mode 100644 index 0000000..9315efb --- /dev/null +++ b/client/src/constants/app_constants.js @@ -0,0 +1,15 @@ +module.exports = { + ActionTypes : { + GET_MINES_LOAD: null, + GET_MINES_SUCCESS: null, + GET_MINES_FAIL: null, + + LOGIN_LOAD: null, + LOGIN_SUCCESS: null, + LOGIN_FAIL: null + }, + + PayloadSources: { + SERVER_ACTION: "SERVER_ACTION" + } +}; diff --git a/client/src/dispatchers/app_dispatcher.js b/client/src/dispatchers/app_dispatcher.js new file mode 100644 index 0000000..5fa7e49 --- /dev/null +++ b/client/src/dispatchers/app_dispatcher.js @@ -0,0 +1,22 @@ +var Dispatcher = require('flux').Dispatcher; +var assign = require('object-assign'); + +/* constants */ +var AppConstants = require('../constants/app_constants.js'); +var PayloadSources = AppConstants.PayloadSources; + +var AppDispatcher = assign(new Dispatcher(), { + /** + * @param {object} action The details of the action, including the action's + * type and additional data coming from the server. + */ + handleServerAction: function(action) { + var payload = { + source: PayloadSources.SERVER_ACTION, + action: action + }; + this.dispatch(payload); + } +}); + +module.exports = AppDispatcher; diff --git a/client/src/stores/minestore.js b/client/src/stores/minestore.js new file mode 100644 index 0000000..331dd66 --- /dev/null +++ b/client/src/stores/minestore.js @@ -0,0 +1,66 @@ +var AppDispatcher = require('../dispatchers/app_dispatcher.js'); +var assign = require('object-assign'); +var EventEmitter = require('events').EventEmitter; +var AppConstants = require('../constants/app_constants.js'); + +/* + * Minesfield. + * + * Status: + * + * 0 : default, not clicked, + * -1 : visited, + * 2 : life, + * -2 : death + * + * Size: 7 by 7 + * + * Mines position (x, y) from array can be calculated by,: + * x : index of an element / size of minesfield + * y : index of an element % size of minesfield + */ + +var mines = [ + 0, -1, 0, 0, 0, 0, 0, + 0, 0, 0, 2, 0, 0, -1, + 0, -2, 0, 0, 0, 0, 0, + 0, 0, 0, -1, 0, 0, 0, + 0, 0, 0, -1, 0, 0, 0, + 0, 0, 0, 0, 0, 0, -1, + 0, 0, 0, 0, 0, 0, -1, +]; + + +var MinesStore = assign({}, EventEmitter.prototype, { + emitChange: function() { + this.emit(CHANGE_EVENT); + }, + + addChangeListener: function(callback) { + this.on(CHANGE_EVENT, callback); + }, + + removeChangeListener: function(callback) { + this.removeListener(CHANGE_EVENT, callback); + }, + + 'getMines': function() { + return mines; + }, +}); + +MinesStore.dispatchToken = AppDispatcher.register(function(payload) { + var action = payload.action; + + switch(action.type) { + case ActionTypes.GET_MINES_SUCCESS: + console.log('mines', action); + MinesStore.emitChange(); + break; + + default: + // do nothing + } +}); + +module.exports = MinesStore; diff --git a/client/src/styles/main.css b/client/src/styles/main.css new file mode 100644 index 0000000..9b16104 --- /dev/null +++ b/client/src/styles/main.css @@ -0,0 +1,60 @@ +/* block css */ +.blocks { + margin: auto; +} +.block { + width: 45px; + height: 45px; + background-color: #eee; +} + +.block:hover { + background-color: #A8CAC5; +} + +.block__visited { + background-color: #16a085; +} + +.block__dead { + background-color: #e74c3c; +} + +/* field */ +.minefield { + width: 50%; + text-align: center; +} +.minefield__wrapper { + width: 80%; + margin: auto; +} +.minefield__enemy { + float: left; +} +.minefield__user { + float: right; +} + +/* turn */ +.turn { + text-align: center; + margin: 1em; +} + +/* hearts */ +.heart-icons { + margin: 5px; +} + +/* life */ +.life-status { + position: relative; + clear: both; + text-align: center; + padding: 4em; +} +.life-status__active { + color: #e74c3c; +} + diff --git a/client/src/templates/index.html b/client/src/templates/index.html index 9f1d688..ab9f057 100644 --- a/client/src/templates/index.html +++ b/client/src/templates/index.html @@ -3,6 +3,9 @@ Webpack + React + + + diff --git a/client/webpack.config.js b/client/webpack.config.js index 64f0c7c..c292c55 100644 --- a/client/webpack.config.js +++ b/client/webpack.config.js @@ -6,7 +6,8 @@ module.exports = { entry: [ 'webpack/hot/only-dev-server', './src/app.jsx', - './src/templates/index.html' + './src/templates/index.html', + './src/styles/main.css' ], output: { @@ -32,6 +33,10 @@ module.exports = { test: /\.html$/, loader: "file?name=[name].[ext]", }, + { + test: /\.css$/, + loader: "file?name=[name].[ext]", + }, ] }, From d721394a04eb8c874c4b67072ae22ffe42a116c8 Mon Sep 17 00:00:00 2001 From: ghome vic Date: Mon, 13 Jul 2015 16:49:52 +0530 Subject: [PATCH 08/49] Color pallete changes --- client/src/styles/main.css | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/src/styles/main.css b/client/src/styles/main.css index 9b16104..474a7d3 100644 --- a/client/src/styles/main.css +++ b/client/src/styles/main.css @@ -13,11 +13,11 @@ } .block__visited { - background-color: #16a085; + background-color: #C8C8C8; } .block__dead { - background-color: #e74c3c; + background-color: #D36B6B; } /* field */ @@ -52,7 +52,7 @@ position: relative; clear: both; text-align: center; - padding: 4em; + padding: 3em; } .life-status__active { color: #e74c3c; From 16871a5ca8ab56fb64e38849765aa96379ba90b1 Mon Sep 17 00:00:00 2001 From: SKatiyar Date: Mon, 13 Jul 2015 17:31:25 +0530 Subject: [PATCH 09/49] able to create streams --- server/.bkp/controllers/controllers.go | 8 ++ server/.bkp/controllers/minefield.go | 1 + server/.bkp/models/README.md | 2 + server/.bkp/models/errors.go | 13 ++++ server/.bkp/models/minefield.go | 101 +++++++++++++++++++++++++ server/.bkp/models/models.go | 57 ++++++++++++++ server/.bkp/models/user.go | 14 ++++ server/connection.go | 25 ++++++ server/entrapped-cmd/main.go | 15 ++++ server/entrapped.go | 45 +++++++++++ server/hub.go | 51 +++++++++++++ server/minefields.go | 47 ++++++++++++ server/minefields_test.go | 18 +++++ server/troopers.go | 6 ++ server/utility.go | 34 +++++++++ 15 files changed, 437 insertions(+) create mode 100644 server/.bkp/controllers/controllers.go create mode 100644 server/.bkp/controllers/minefield.go create mode 100644 server/.bkp/models/README.md create mode 100644 server/.bkp/models/errors.go create mode 100644 server/.bkp/models/minefield.go create mode 100644 server/.bkp/models/models.go create mode 100644 server/.bkp/models/user.go create mode 100644 server/connection.go create mode 100644 server/entrapped-cmd/main.go create mode 100644 server/entrapped.go create mode 100644 server/hub.go create mode 100644 server/minefields.go create mode 100644 server/minefields_test.go create mode 100644 server/troopers.go create mode 100644 server/utility.go diff --git a/server/.bkp/controllers/controllers.go b/server/.bkp/controllers/controllers.go new file mode 100644 index 0000000..a057b93 --- /dev/null +++ b/server/.bkp/controllers/controllers.go @@ -0,0 +1,8 @@ +package controllers + +type Engine struct { +} + +func New() (*Engine, error) { + return &Engine{}, nil +} diff --git a/server/.bkp/controllers/minefield.go b/server/.bkp/controllers/minefield.go new file mode 100644 index 0000000..2d32936 --- /dev/null +++ b/server/.bkp/controllers/minefield.go @@ -0,0 +1 @@ +package controllers diff --git a/server/.bkp/models/README.md b/server/.bkp/models/README.md new file mode 100644 index 0000000..e104828 --- /dev/null +++ b/server/.bkp/models/README.md @@ -0,0 +1,2 @@ +# Not Used +#### Since heroku doesn't support rethinkdb diff --git a/server/.bkp/models/errors.go b/server/.bkp/models/errors.go new file mode 100644 index 0000000..231fd9a --- /dev/null +++ b/server/.bkp/models/errors.go @@ -0,0 +1,13 @@ +package models + +import ( + "errors" +) + +var ( + ErrInvalidDB = errors.New("invalid db name") + ErrInvalidAddress = errors.New("invalid db connection address") + ErrRethinkConn = errors.New("unable to connect to rethink") + ErrQueryFailed = errors.New("unable to query database") + ErrInvalidFieldID = errors.New("invalid minefield id") +) diff --git a/server/.bkp/models/minefield.go b/server/.bkp/models/minefield.go new file mode 100644 index 0000000..0307ce7 --- /dev/null +++ b/server/.bkp/models/minefield.go @@ -0,0 +1,101 @@ +package models + +import ( + r "github.com/dancannon/gorethink" + re "github.com/dancannon/gorethink/encoding" + "time" +) + +type MineField struct { + MatrixID string `gorethink:"id,omitempty"` + Matrix [][]int `gorethink:"matrix"` + CreatedAt time.Time `gorethink:"createdAt"` + CreatedBy string `gorethink:"createdBy"` +} + +func (e *Engine) SaveMineField(mat [][]int, userID string) (*MineField, error) { + mf := MineField{ + Matrix: mat, + CreatedAt: time.Now().UTC(), + CreatedBy: userID, + } + + insert, insertErr := e.term.Table(MineTB). + Insert(&mf, r.InsertOpts{ReturnChanges: true, Durability: "hard"}). + RunWrite(e.session) + if insertErr != nil { + e.log.Println(insertErr) + return nil, ErrQueryFailed + } + if insert.Inserted != 1 { + e.log.Println(insert.FirstError) + return nil, ErrQueryFailed + } + if scanErr := re.Decode(&mf, insert.Changes[0].NewValue); scanErr != nil { + e.log.Println(scanErr) + return nil, ErrQueryFailed + } + + return &mf, nil +} + +func (e *Engine) GetMineFields() ([]MineField, error) { + get, getErr := e.term.Table(MineTB). + Run(e.session) + if getErr != nil { + e.log.Println(getErr) + return nil, ErrQueryFailed + } + + fields := make([]MineField, 0) + if scanErr := get.All(&fields); scanErr != nil { + e.log.Println(scanErr) + return nil, ErrQueryFailed + } + + return fields, nil +} + +func (e *Engine) GetMineFieldByID(fieldID string) (*MineField, error) { + if len(fieldID) == 0 { + return nil, ErrInvalidFieldID + } + + get, getErr := e.term.Table(MineTB). + Get(fieldID). + Run(e.session) + if getErr != nil { + e.log.Println(getErr) + return nil, ErrQueryFailed + } + + var field MineField + if scanErr := get.One(&field); scanErr != nil { + e.log.Println(scanErr) + return nil, ErrQueryFailed + } + + return &field, nil +} + +func (e *Engine) GetMineFieldsByUserID(userID string) ([]MineField, error) { + if len(userID) == 0 { + return nil, ErrInvalidFieldID + } + + get, getErr := e.term.Table(MineTB). + GetAllByIndex(FieldCreatedBy, userID). + Run(e.session) + if getErr != nil { + e.log.Println(getErr) + return nil, ErrQueryFailed + } + + fields := make([]MineField, 0) + if scanErr := get.All(&fields); scanErr != nil { + e.log.Println(scanErr) + return nil, ErrQueryFailed + } + + return fields, nil +} diff --git a/server/.bkp/models/models.go b/server/.bkp/models/models.go new file mode 100644 index 0000000..ca47028 --- /dev/null +++ b/server/.bkp/models/models.go @@ -0,0 +1,57 @@ +package models + +import ( + r "github.com/dancannon/gorethink" + "log" + "os" + "time" +) + +const ( + UserTB string = "users" + MineTB string = "minefields" + + FieldCreatedBy string = "createdBy" +) + +type Conf struct { + DBAddress string + DBDatabase string + DBAuthKey string + DBMaxIdle int + DBMaxOpen int + DBTimeout time.Duration +} + +type Engine struct { + log *log.Logger + term r.Term + session *r.Session +} + +func New(conf Conf) (*Engine, error) { + if len(conf.DBAddress) == 0 { + return nil, ErrInvalidAddress + } + if len(conf.DBDatabase) == 0 { + return nil, ErrInvalidDB + } + + logger := log.New(os.Stdout, "[entrapped models]", log.Ldate|log.Ltime|log.Lshortfile) + + session, sessionErr := r.Connect(r.ConnectOpts{ + Address: conf.DBAddress, + Database: conf.DBDatabase, + AuthKey: conf.DBAuthKey, + Timeout: conf.DBTimeout, + MaxIdle: conf.DBMaxIdle, + MaxOpen: conf.DBMaxOpen, + }) + + if sessionErr != nil { + logger.Println(sessionErr) + return nil, ErrRethinkConn + } + + return &Engine{logger, r.DB(conf.DBDatabase), session}, nil +} diff --git a/server/.bkp/models/user.go b/server/.bkp/models/user.go new file mode 100644 index 0000000..dcfee1c --- /dev/null +++ b/server/.bkp/models/user.go @@ -0,0 +1,14 @@ +package models + +import ( + // r "github.com/dancannon/gorethink" + // re "github.com/dancannon/gorethink/encoding" + "time" +) + +type User struct { + UserID string + NickName string + Hash string + CreatedAt time.Time +} diff --git a/server/connection.go b/server/connection.go new file mode 100644 index 0000000..e334640 --- /dev/null +++ b/server/connection.go @@ -0,0 +1,25 @@ +package entrapped + +import ( + "github.com/gorilla/websocket" + "net/http" +) + +var upgrader = websocket.Upgrader{ + ReadBufferSize: 1024, + WriteBufferSize: 1024, +} + +type connection struct { + ws *websocket.Conn + data chan []byte +} + +func newConnection(rw http.ResponseWriter, req *http.Request) (*connection, error) { + ws, wsErr := upgrader.Upgrade(rw, req, nil) + if wsErr != nil { + return nil, wsErr + } + + return &connection{ws, make(chan []byte, 512)}, nil +} diff --git a/server/entrapped-cmd/main.go b/server/entrapped-cmd/main.go new file mode 100644 index 0000000..0357043 --- /dev/null +++ b/server/entrapped-cmd/main.go @@ -0,0 +1,15 @@ +package main + +import ( + "github.com/SKatiyar/entrapped/server" + "os" +) + +func main() { + envPort := os.Getenv("PORT") + if len(envPort) != 0 { + envPort = ":" + envPort + } + + entrapped.Start(envPort) +} diff --git a/server/entrapped.go b/server/entrapped.go new file mode 100644 index 0000000..61e7b70 --- /dev/null +++ b/server/entrapped.go @@ -0,0 +1,45 @@ +package entrapped + +import ( + "github.com/julienschmidt/httprouter" + "net/http" +) + +func Start(addr string) { + if len(addr) == 0 { + addr = ":7000" + } + + // initialize hunt + go hub.run() + + // initialize router + router := httprouter.New() + + // make routes + router.GET("/", home) + router.GET("/players/:id", addPlayer) + + listenErr := http.ListenAndServe(addr, router) + if listenErr != nil { + logger.Println(listenErr) + return + } +} + +func addPlayer(rw http.ResponseWriter, req *http.Request, params httprouter.Params) { + id := params.ByName("id") + + conn, connErr := newConnection(rw, req) + if connErr != nil { + error500(rw, connErr) + return + } + + hub.add(id, conn) +} + +func home(rw http.ResponseWriter, req *http.Request, _ httprouter.Params) { + rw.Header().Set("Content-Type", "text/html; charset=utf-8") + http.ServeFile(rw, req, "./home.html") +} diff --git a/server/hub.go b/server/hub.go new file mode 100644 index 0000000..dd67035 --- /dev/null +++ b/server/hub.go @@ -0,0 +1,51 @@ +package entrapped + +// centeral hub to manage all connections +type trap struct { + // registered connections + troopers map[string]*connection + // register requests + enter chan *trooper + // unregister requests + dead chan *trooper + // errors + errors chan string +} + +var hub = &trap{ + troopers: make(map[string]*connection), + enter: make(chan *trooper), + dead: make(chan *trooper), + errors: make(chan string), +} + +func (t *trap) run() { + for { + select { + case c := <-t.enter: + if _, ok := t.troopers[c.nickname]; ok { + t.errors <- "user exists" + } else { + t.troopers[c.nickname] = c.connection + } + case c := <-t.dead: + if _, ok := t.troopers[c.nickname]; ok { + delete(t.troopers, c.nickname) + close(c.connection.data) + } + } + } +} + +func (t *trap) add(name string, conn *connection) { + t.enter <- &trooper{name, conn} + + err := <-t.errors + if len(err) != 0 { + conn.ws.WriteJSON(err) + conn.ws.Close() + } + + for { + } +} diff --git a/server/minefields.go b/server/minefields.go new file mode 100644 index 0000000..9a21252 --- /dev/null +++ b/server/minefields.go @@ -0,0 +1,47 @@ +package entrapped + +const ( + minSize int = 7 + maxSize int = 10 +) + +const ( + covered int = 0 + empty int = 1 + mine int = -2 +) + +type mineField struct { + field []int + size int +} + +func createEmptyMineField(size int) *mineField { + if size < minSize { + size = minSize + } + if size > maxSize { + size = maxSize + } + + field := make([]int, (size * size)) + + return &mineField{field, size} +} + +func (m *mineField) addRandomBombs(numBombs int) *mineField { + size := len(m.field) + + for i := 0; i < numBombs; i++ { + x := randomInt(size - 1) + + val := m.field[x] + if val == 0 { + m.field[x] = -1 + } else { + i-- + } + } + + return m +} diff --git a/server/minefields_test.go b/server/minefields_test.go new file mode 100644 index 0000000..630779b --- /dev/null +++ b/server/minefields_test.go @@ -0,0 +1,18 @@ +package entrapped + +import ( + "testing" +) + +func TestCreateEmptyMineField(t *testing.T) { + field := createEmptyMineField(9) + + if field.size != 9 { + t.Error("wrong mine field size") + } +} + +func TestAddRandomBombs(t *testing.T) { + setField := createEmptyMineField(8).addRandomBombs(9) + t.Log(setField) +} diff --git a/server/troopers.go b/server/troopers.go new file mode 100644 index 0000000..236bbf4 --- /dev/null +++ b/server/troopers.go @@ -0,0 +1,6 @@ +package entrapped + +type trooper struct { + nickname string + connection *connection +} diff --git a/server/utility.go b/server/utility.go new file mode 100644 index 0000000..5e32736 --- /dev/null +++ b/server/utility.go @@ -0,0 +1,34 @@ +package entrapped + +import ( + "crypto/rand" + "encoding/json" + "log" + "math/big" + "net/http" + "os" +) + +var logger = log.New(os.Stdout, "[entrapped]", log.Ldate|log.Ltime|log.Llongfile) + +func randomInt(max int) int { + if max <= 0 { + max = 1 + } + + num, numErr := rand.Int(rand.Reader, big.NewInt(int64(max))) + if numErr != nil { + return 0 + } + + return int(num.Int64()) +} + +func decodeJSON(req *http.Request, dst interface{}) error { + return json.NewDecoder(req.Body).Decode(dst) +} + +func error500(rw http.ResponseWriter, err error) { + rw.WriteHeader(500) + rw.Write([]byte(err.Error())) +} From 48d8b4d355ad1465c221d512e8f4c6001c28938d Mon Sep 17 00:00:00 2001 From: ghome vic Date: Mon, 13 Jul 2015 19:03:51 +0530 Subject: [PATCH 10/49] Nickname in homepage --- client/src/components/Home.jsx | 7 ++++-- client/src/components/Minefield.jsx | 7 +++++- client/src/styles/main.css | 35 +++++++++++++++++++++++++++++ 3 files changed, 46 insertions(+), 3 deletions(-) diff --git a/client/src/components/Home.jsx b/client/src/components/Home.jsx index 1b55f29..7d18212 100644 --- a/client/src/components/Home.jsx +++ b/client/src/components/Home.jsx @@ -4,9 +4,12 @@ import { Router, Link } from 'react-router'; class Home extends React.Component { render() { return ( -
-

Entrapped v0.0

+
+

Entrapped v0.0

Tiny little minefield of our dreams.
+
+ +
Play
) diff --git a/client/src/components/Minefield.jsx b/client/src/components/Minefield.jsx index 31259ac..b459ba1 100644 --- a/client/src/components/Minefield.jsx +++ b/client/src/components/Minefield.jsx @@ -2,13 +2,18 @@ import React from 'react'; import Blocks from './Blocks.jsx'; import MinesStore from '../stores/minestore.js'; +import Api from '../api/api.js'; class Minefield extends React.Component { constructor() { super(); + this.state = { mines : MinesStore.getMines() - } + }; + + // connect + Api.connect(); } render() { diff --git a/client/src/styles/main.css b/client/src/styles/main.css index 474a7d3..4d01e37 100644 --- a/client/src/styles/main.css +++ b/client/src/styles/main.css @@ -20,6 +20,8 @@ background-color: #D36B6B; } + + /* field */ .minefield { width: 50%; @@ -36,6 +38,8 @@ float: right; } + + /* turn */ .turn { text-align: center; @@ -47,6 +51,8 @@ margin: 5px; } + + /* life */ .life-status { position: relative; @@ -58,3 +64,32 @@ color: #e74c3c; } +@font-face { + font-family: "1942 report"; + src: url(1942.ttf); +} + + +/* home */ +.home { + text-align: center; + font-family: "1942 report"; +} +.home__title { + margin-top: 5em; +} + +.nickname { + margin-top: 3em; + margin-bottom: 2em; +} +.nickname__input { + border: 0; + border-bottom: 1px solid; + text-align: center; + font-size: 1.5em; + line-height: 45px; + font-weight: 700; + letter-spacing: 3px; + outline: none; +} From 7db45eb8c74a98ecef1050b150e5cb94f1e7bee1 Mon Sep 17 00:00:00 2001 From: ghome vic Date: Mon, 13 Jul 2015 19:20:32 +0530 Subject: [PATCH 11/49] Username in Store --- client/src/components/Home.jsx | 8 +++++++- client/src/components/Minefield.jsx | 5 +++-- client/src/stores/minestore.js | 24 +++++++++++++++++------- 3 files changed, 27 insertions(+), 10 deletions(-) diff --git a/client/src/components/Home.jsx b/client/src/components/Home.jsx index 7d18212..184474f 100644 --- a/client/src/components/Home.jsx +++ b/client/src/components/Home.jsx @@ -1,14 +1,20 @@ import React from 'react'; import { Router, Link } from 'react-router'; +import MinesStore from '../stores/minestore.js'; + class Home extends React.Component { + handleChange(e) { + MinesStore.addUsername(e.target.value); + } + render() { return (

Entrapped v0.0

Tiny little minefield of our dreams.
- +
Play
diff --git a/client/src/components/Minefield.jsx b/client/src/components/Minefield.jsx index b459ba1..d602534 100644 --- a/client/src/components/Minefield.jsx +++ b/client/src/components/Minefield.jsx @@ -9,7 +9,8 @@ class Minefield extends React.Component { super(); this.state = { - mines : MinesStore.getMines() + mines : MinesStore.getMines(), + username: MinesStore.getUsername() }; // connect @@ -37,7 +38,7 @@ class Minefield extends React.Component {
-
Your Minefield.
+
{this.state.username}, Your Minefield.
diff --git a/client/src/stores/minestore.js b/client/src/stores/minestore.js index 331dd66..991876d 100644 --- a/client/src/stores/minestore.js +++ b/client/src/stores/minestore.js @@ -3,18 +3,18 @@ var assign = require('object-assign'); var EventEmitter = require('events').EventEmitter; var AppConstants = require('../constants/app_constants.js'); -/* +/* * Minesfield. * * Status: - * - * 0 : default, not clicked, - * -1 : visited, - * 2 : life, - * -2 : death + * + * 0 : default, not clicked, + * -1 : visited, + * 2 : life, + * -2 : death * * Size: 7 by 7 - * + * * Mines position (x, y) from array can be calculated by,: * x : index of an element / size of minesfield * y : index of an element % size of minesfield @@ -30,6 +30,8 @@ var mines = [ 0, 0, 0, 0, 0, 0, -1, ]; +/* username */ +var username = ''; var MinesStore = assign({}, EventEmitter.prototype, { emitChange: function() { @@ -47,6 +49,14 @@ var MinesStore = assign({}, EventEmitter.prototype, { 'getMines': function() { return mines; }, + + 'addUsername': function(name) { + username = name; + }, + + 'getUsername': function() { + return username; + } }); MinesStore.dispatchToken = AppDispatcher.register(function(payload) { From 59704da6805d91ba325804cc7beba35f65b7d714 Mon Sep 17 00:00:00 2001 From: ghome vic Date: Mon, 13 Jul 2015 19:23:27 +0530 Subject: [PATCH 12/49] 1942 font added --- client/src/public/font/1942.ttf | Bin 0 -> 52168 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100755 client/src/public/font/1942.ttf diff --git a/client/src/public/font/1942.ttf b/client/src/public/font/1942.ttf new file mode 100755 index 0000000000000000000000000000000000000000..951cf8977fee6b055ac108bad6a79d817cf93b69 GIT binary patch literal 52168 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 Date: Mon, 13 Jul 2015 19:55:31 +0530 Subject: [PATCH 13/49] Font in webpack --- client/webpack.config.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/client/webpack.config.js b/client/webpack.config.js index c292c55..11645be 100644 --- a/client/webpack.config.js +++ b/client/webpack.config.js @@ -7,7 +7,8 @@ module.exports = { 'webpack/hot/only-dev-server', './src/app.jsx', './src/templates/index.html', - './src/styles/main.css' + './src/styles/main.css', + './src/public/font/1942.ttf' ], output: { @@ -37,6 +38,10 @@ module.exports = { test: /\.css$/, loader: "file?name=[name].[ext]", }, + { + test: /\.ttf$/, + loader: "file?name=[name].[ext]", + } ] }, From 8cea32d5cc6237938d46e301891318637fac3763 Mon Sep 17 00:00:00 2001 From: ghome vic Date: Tue, 14 Jul 2015 01:06:20 +0530 Subject: [PATCH 14/49] Server Integrations --- client/src/api/api.js | 38 +++++++++++++++++++ client/src/components/Blocks.jsx | 12 +++--- client/src/components/Minefield.jsx | 2 +- client/src/stores/minestore.js | 23 ++++++++++-- client/src/utility/utils.js | 58 +++++++++++++++++++++++++++++ 5 files changed, 123 insertions(+), 10 deletions(-) create mode 100644 client/src/api/api.js create mode 100644 client/src/utility/utils.js diff --git a/client/src/api/api.js b/client/src/api/api.js new file mode 100644 index 0000000..851de92 --- /dev/null +++ b/client/src/api/api.js @@ -0,0 +1,38 @@ +'use strict'; + +var MinesStore = require('../../src/stores/minestore.js'); +var AppDispatcher = require('../dispatchers/app_dispatcher.js'); + +var _ = require('../../src/utility/utils.js'); + +var apiUrl = "ws://192.168.0.103:7000"; + +/* websocket reference */ +var conn = null; + +module.exports = { + connect: function(nickname) { + console.log('inside connect'); + if (window["WebSocket"]) { + conn = new WebSocket(apiUrl + '/players/' + nickname); + + conn.onclose = function(evt) { + console.log('connection closed.'); + }; + + conn.onmessage = function(evt) { + var data = _.getObject(evt.data); + + //console.log('data', data); + AppDispatcher.handleServerAction(data); + }; + } else { + console.log($("Your browser does not support WebSockets.")); + } + }, + + send: function(data) { + console.log('sending ', data); + conn.send(data); + } +}; diff --git a/client/src/components/Blocks.jsx b/client/src/components/Blocks.jsx index 095fc56..b4b5308 100644 --- a/client/src/components/Blocks.jsx +++ b/client/src/components/Blocks.jsx @@ -1,5 +1,6 @@ import React from 'react/addons'; +import Api from '../api/api.js'; /** * Returns a random integer between min (inclusive) and max (inclusive) * Using Math.round() will give you a non-uniform distribution! @@ -28,16 +29,16 @@ class Block extends React.Component { } handleClick() { - console.log('clicked block', this); + var msg = "data:open:[idx=" + this.props.index + "]:[help=9]"; + Api.send(msg); } }; -Block.propTypes = { status: React.PropTypes.number }; -Block.defaultProps = { status: 0 }; +Block.propTypes = { status: React.PropTypes.number, index: React.PropTypes.number }; +Block.defaultProps = { status: 0, index: 0 }; class Blocks extends React.Component { constructor(props) { super(props); - console.log('props', props); } render() { @@ -50,7 +51,8 @@ class Blocks extends React.Component { var _blocks = []; for (var j = 0; j < size; j++) { - _blocks.push(); + var index = i * size + j; + _blocks.push(); } nodes.push(({_blocks})); diff --git a/client/src/components/Minefield.jsx b/client/src/components/Minefield.jsx index d602534..f19013a 100644 --- a/client/src/components/Minefield.jsx +++ b/client/src/components/Minefield.jsx @@ -14,7 +14,7 @@ class Minefield extends React.Component { }; // connect - Api.connect(); + Api.connect(MinesStore.getUsername()); } render() { diff --git a/client/src/stores/minestore.js b/client/src/stores/minestore.js index 991876d..f438fd5 100644 --- a/client/src/stores/minestore.js +++ b/client/src/stores/minestore.js @@ -63,13 +63,28 @@ MinesStore.dispatchToken = AppDispatcher.register(function(payload) { var action = payload.action; switch(action.type) { - case ActionTypes.GET_MINES_SUCCESS: - console.log('mines', action); - MinesStore.emitChange(); + case 'registered': + console.log('user registered'); + break; + + case 'ready': + console.log('ready'); + break; + + case 'open': + console.log('open'); + break; + + case 'result': + console.log('result'); + break; + + case 'enemy': + console.log('enemy'); break; default: - // do nothing + // do nothing } }); diff --git a/client/src/utility/utils.js b/client/src/utility/utils.js new file mode 100644 index 0000000..36bd504 --- /dev/null +++ b/client/src/utility/utils.js @@ -0,0 +1,58 @@ +'use strict'; + +var assign = require('object-assign'); + +/* Utility function to parse server message and get key value pairs. + * @param msg string + * e.g. "data:registered:[size=7]:[life=5]" + * "error:some error msg" + * + * @return object + * { + * type: "registered", + * payload: { + * size: 7, + * life: 5 + * } + * } + * + * or, + * + * { + * error: "some error msg" + * } + */ + +exports.getObject = function(msg) { + + if (!msg || !msg.length) { + return null; + } + + var obj = {}; + + msg = msg.split(':'); + + /* parse error response */ + if (msg[0] === "error") { + obj[msg[0]] = msg[1]; + return obj; + } + + obj['type'] = msg[1]; + msg.shift(); + msg.shift(); + + obj.payload = {}; + + msg.forEach(function(e) { + e = e.replace(/(\[|\])/g, ''); + + var key = e.substr(0, e.indexOf('=')); + var value = e.substr(e.indexOf('=')+1, e.length); + + obj.payload[key] = value; + }); + + return obj; +} From 43c158d699990caa99227781ca3a9bce217c8032 Mon Sep 17 00:00:00 2001 From: SKatiyar Date: Tue, 14 Jul 2015 03:52:57 +0530 Subject: [PATCH 15/49] main stuff working --- server/.bkp/README.md | 2 + server/.bkp/models/README.md | 2 - server/connection.go | 25 -------- server/connectionhub.go | 114 +++++++++++++++++++++++++++++++++++ server/entrapped.go | 19 ++++-- server/hub.go | 51 ---------------- server/minefields.go | 16 +++-- server/trap.go | 31 ++++++++++ server/troopers.go | 100 +++++++++++++++++++++++++++++- server/utility.go | 56 ++++++++++++++++- 10 files changed, 325 insertions(+), 91 deletions(-) create mode 100644 server/.bkp/README.md delete mode 100644 server/.bkp/models/README.md delete mode 100644 server/connection.go create mode 100644 server/connectionhub.go delete mode 100644 server/hub.go create mode 100644 server/trap.go diff --git a/server/.bkp/README.md b/server/.bkp/README.md new file mode 100644 index 0000000..784a357 --- /dev/null +++ b/server/.bkp/README.md @@ -0,0 +1,2 @@ +# Not to see here +#### Move along now diff --git a/server/.bkp/models/README.md b/server/.bkp/models/README.md deleted file mode 100644 index e104828..0000000 --- a/server/.bkp/models/README.md +++ /dev/null @@ -1,2 +0,0 @@ -# Not Used -#### Since heroku doesn't support rethinkdb diff --git a/server/connection.go b/server/connection.go deleted file mode 100644 index e334640..0000000 --- a/server/connection.go +++ /dev/null @@ -1,25 +0,0 @@ -package entrapped - -import ( - "github.com/gorilla/websocket" - "net/http" -) - -var upgrader = websocket.Upgrader{ - ReadBufferSize: 1024, - WriteBufferSize: 1024, -} - -type connection struct { - ws *websocket.Conn - data chan []byte -} - -func newConnection(rw http.ResponseWriter, req *http.Request) (*connection, error) { - ws, wsErr := upgrader.Upgrade(rw, req, nil) - if wsErr != nil { - return nil, wsErr - } - - return &connection{ws, make(chan []byte, 512)}, nil -} diff --git a/server/connectionhub.go b/server/connectionhub.go new file mode 100644 index 0000000..faf334f --- /dev/null +++ b/server/connectionhub.go @@ -0,0 +1,114 @@ +package entrapped + +import ( + "strconv" +) + +// connectionhub to manage all connections +type connectionhub struct { + // registered connections + troopers map[*trooper]bool + // matches active + matches map[*trooper]*trooper + // register requests + enter chan *trooper + // unregister requests + dead chan *trooper + // errors + errors chan string + // message from requests + message chan *message +} + +var ch = &connectionhub{ + troopers: make(map[*trooper]bool), + matches: make(map[*trooper]*trooper), + enter: make(chan *trooper), + dead: make(chan *trooper), + message: make(chan *message), + errors: make(chan string), +} + +func (ch *connectionhub) run() { + readyState := "data:ready:" + + "[size=" + strconv.Itoa(size) + "]:" + + "[life=" + strconv.Itoa(lifes) + "]:" + resultState := "data:result:" + enemyState := "data:enemy:" + + for { + select { + case t := <-ch.enter: + ch.troopers[t] = false + for key, val := range ch.troopers { + if !val && key != t { + ch.matches[t] = key + ch.matches[key] = t + p1Tag := readyState + "[name=" + t.nickname + "]" + key.data <- []byte(p1Tag) + p2Tag := readyState + "[name=" + key.nickname + "]" + t.data <- []byte(p2Tag) + break + } + } + case t := <-ch.dead: + if _, ok := ch.troopers[t]; ok { + delete(ch.troopers, t) + } + if val, ok := ch.matches[t]; ok { + ch.troopers[val] = true + ch.matches[val] = nil + delete(ch.matches, t) + close(t.data) + } + case m := <-ch.message: + msg, msgErr := reqParser(m.msg) + if len(msgErr) != 0 { + m.t.data <- []byte(msgErr) + } else { + switch msg.command { + case cmdOpen: + id, idErr := strconv.Atoi(msg.params["idx"]) + if idErr != nil { + m.t.data <- []byte("error:invalid idx") + } else { + ele, life, err := m.t.trap.open(id) + if len(err) != 0 { + m.t.data <- []byte(err) + } else { + if life == 0 { + m.t.data <- []byte("error:game over") + } else { + if val, ok := ch.matches[m.t]; ok { + m.t.data <- []byte(resultState + + "[idx=" + msg.params["idx"] + "]:[type=" + strconv.Itoa(ele) + + "]:[life=" + strconv.Itoa(life) + "]") + if val != nil { + val.data <- []byte(enemyState + + "[idx=" + msg.params["idx"] + "]:[type=" + strconv.Itoa(ele) + + "]:[life=" + strconv.Itoa(life) + "]") + } else { + m.t.data <- []byte("data:result:[status:won]") + } + } else { + m.t.data <- []byte("error:no oponent") + } + } + } + } + default: + m.t.data <- []byte("error:unknown command") + } + } + } + } +} + +func (ch *connectionhub) add(ut *trooper) { + ch.enter <- ut + + ut.data <- []byte("data:registered:[size=" + strconv.Itoa(size) + "]:[life=" + strconv.Itoa(lifes) + "]") + + go ut.writePump() + ut.readPump() +} diff --git a/server/entrapped.go b/server/entrapped.go index 61e7b70..f428066 100644 --- a/server/entrapped.go +++ b/server/entrapped.go @@ -5,13 +5,19 @@ import ( "net/http" ) +const ( + size int = 7 + numBombs int = 10 + lifes int = 5 +) + func Start(addr string) { if len(addr) == 0 { addr = ":7000" } // initialize hunt - go hub.run() + go ch.run() // initialize router router := httprouter.New() @@ -20,6 +26,7 @@ func Start(addr string) { router.GET("/", home) router.GET("/players/:id", addPlayer) + // start listening to incoming connections listenErr := http.ListenAndServe(addr, router) if listenErr != nil { logger.Println(listenErr) @@ -30,13 +37,15 @@ func Start(addr string) { func addPlayer(rw http.ResponseWriter, req *http.Request, params httprouter.Params) { id := params.ByName("id") - conn, connErr := newConnection(rw, req) - if connErr != nil { - error500(rw, connErr) + ws, wsErr := upgrader.Upgrade(rw, req, nil) + if wsErr != nil { + logger.Println(wsErr) return } - hub.add(id, conn) + trap := makeTrap(size, numBombs, lifes) + + ch.add(&trooper{id, trap, ws, make(chan []byte, 512)}) } func home(rw http.ResponseWriter, req *http.Request, _ httprouter.Params) { diff --git a/server/hub.go b/server/hub.go deleted file mode 100644 index dd67035..0000000 --- a/server/hub.go +++ /dev/null @@ -1,51 +0,0 @@ -package entrapped - -// centeral hub to manage all connections -type trap struct { - // registered connections - troopers map[string]*connection - // register requests - enter chan *trooper - // unregister requests - dead chan *trooper - // errors - errors chan string -} - -var hub = &trap{ - troopers: make(map[string]*connection), - enter: make(chan *trooper), - dead: make(chan *trooper), - errors: make(chan string), -} - -func (t *trap) run() { - for { - select { - case c := <-t.enter: - if _, ok := t.troopers[c.nickname]; ok { - t.errors <- "user exists" - } else { - t.troopers[c.nickname] = c.connection - } - case c := <-t.dead: - if _, ok := t.troopers[c.nickname]; ok { - delete(t.troopers, c.nickname) - close(c.connection.data) - } - } - } -} - -func (t *trap) add(name string, conn *connection) { - t.enter <- &trooper{name, conn} - - err := <-t.errors - if len(err) != 0 { - conn.ws.WriteJSON(err) - conn.ws.Close() - } - - for { - } -} diff --git a/server/minefields.go b/server/minefields.go index 9a21252..6716804 100644 --- a/server/minefields.go +++ b/server/minefields.go @@ -6,9 +6,9 @@ const ( ) const ( - covered int = 0 - empty int = 1 - mine int = -2 + open int = 9 + empty int = 0 + mine int = -2 ) type mineField struct { @@ -36,8 +36,8 @@ func (m *mineField) addRandomBombs(numBombs int) *mineField { x := randomInt(size - 1) val := m.field[x] - if val == 0 { - m.field[x] = -1 + if val == empty { + m.field[x] = mine } else { i-- } @@ -45,3 +45,9 @@ func (m *mineField) addRandomBombs(numBombs int) *mineField { return m } + +func (m *mineField) checkIndex(idx int) int { + ele := m.field[idx] + m.field[idx] = open + return ele +} diff --git a/server/trap.go b/server/trap.go new file mode 100644 index 0000000..24e9a26 --- /dev/null +++ b/server/trap.go @@ -0,0 +1,31 @@ +package entrapped + +type trap struct { + trapMap *mineField + lifes int +} + +func makeTrap(size, numBombs, lifes int) *trap { + return &trap{ + trapMap: createEmptyMineField(size).addRandomBombs(numBombs), + lifes: lifes, + } +} + +func (t *trap) open(idx int) (int, int, string) { + if idx > (t.trapMap.size*t.trapMap.size)-1 { + return 0, 0, "error:invalid idx" + } + + if t.lifes > 0 { + ele := t.trapMap.checkIndex(idx) + if ele == mine { + t.lifes-- + return ele, t.lifes, "" + } else { + return ele, t.lifes, "" + } + } + + return 0, 0, "" +} diff --git a/server/troopers.go b/server/troopers.go index 236bbf4..210513f 100644 --- a/server/troopers.go +++ b/server/troopers.go @@ -1,6 +1,102 @@ package entrapped +import ( + "github.com/gorilla/websocket" + "net/http" + "time" +) + +const ( + // time allowed to write a message to the peer + writeWait = time.Second + // time allowed to read the next pong message from the peer + pongWait = 10 * time.Second + // send pings to peer with this period, must be less than pongWait + pingPeriod = (pongWait * 9) / 10 + // maximum message size allowed from peer + maxMessageSize = 512 +) + +var upgrader = websocket.Upgrader{ + ReadBufferSize: 512, + WriteBufferSize: 512, + CheckOrigin: checkOrigin, +} + +func checkOrigin(req *http.Request) bool { + return true +} + type trooper struct { - nickname string - connection *connection + nickname string + trap *trap + ws *websocket.Conn + data chan []byte +} + +type message struct { + t *trooper + msg string + msgType int +} + +func (t *trooper) readPump() { + defer func() { + t.dead() + t.ws.Close() + }() + + t.ws.SetReadLimit(maxMessageSize) + t.ws.SetReadDeadline(time.Now().Add(pongWait)) + t.ws.SetPongHandler(func(string) error { + t.ws.SetReadDeadline(time.Now().Add(pongWait)) + return nil + }) + + for { + msgType, msg, err := t.ws.ReadMessage() + if err != nil { + break + } + + ch.message <- &message{t, string(msg), msgType} + } +} + +// writePump pumps messages to connection +func (t *trooper) writePump() { + ticker := time.NewTicker(pingPeriod) + + defer func() { + ticker.Stop() + t.ws.Close() + }() + + for { + select { + case message, ok := <-t.data: + if !ok { + t.write(websocket.CloseMessage, []byte{}) + return + } + if err := t.write(websocket.TextMessage, message); err != nil { + return + } + case <-ticker.C: + if err := t.write(websocket.PingMessage, []byte{}); err != nil { + return + } + } + } +} + +// write payload to the connection +func (t *trooper) write(mt int, payload []byte) error { + t.ws.SetWriteDeadline(time.Now().Add(writeWait)) + return t.ws.WriteMessage(mt, payload) +} + +// dead used to send close signal +func (t *trooper) dead() { + ch.dead <- t } diff --git a/server/utility.go b/server/utility.go index 5e32736..c95f2f0 100644 --- a/server/utility.go +++ b/server/utility.go @@ -7,9 +7,28 @@ import ( "math/big" "net/http" "os" + "regexp" + "strings" ) -var logger = log.New(os.Stdout, "[entrapped]", log.Ldate|log.Ltime|log.Llongfile) +type command string + +const ( + typeData string = "data" + typeError string = "error" + cmdRegistered string = "registered" + cmdReady string = "ready" + cmdOpen string = "open" + cmdResult string = "result" + cmdEnemy string = "enemy" +) + +var dataRegex = regexp.MustCompile("^" + + "(" + typeData + "|" + typeError + "):" + + "(" + cmdRegistered + "|" + cmdReady + "|" + cmdOpen + "|" + cmdResult + "|" + cmdEnemy + ")" + + "(:.*)*$") + +var logger = log.New(os.Stdout, "[entrapped]", log.Ldate|log.Ltime|log.Lshortfile) func randomInt(max int) int { if max <= 0 { @@ -32,3 +51,38 @@ func error500(rw http.ResponseWriter, err error) { rw.WriteHeader(500) rw.Write([]byte(err.Error())) } + +type data struct { + dataType string + command string + params map[string]string +} + +func reqParser(msg string) (*data, string) { + valid := dataRegex.FindStringSubmatch(msg) + if len(valid) < 3 { + return nil, "error:invalid params" + } + + var params map[string]string + if len(valid) > 3 { + params = make(map[string]string) + vals := strings.Split(valid[3], ":") + for i := 1; i < len(vals); i++ { + valArr := strings.Split(strings.Replace(strings.Replace(vals[i], "[", "", 1), "]", "", 1), "=") + if len(valArr) != 2 { + return nil, "error:invalid params" + } + + params[valArr[0]] = valArr[1] + } + } else { + params = nil + } + + return &data{ + dataType: valid[1], + command: valid[2], + params: params, + }, "" +} From 6255e8f48433fa86010f7c5a4533ecc37f19229d Mon Sep 17 00:00:00 2001 From: SKatiyar Date: Tue, 14 Jul 2015 04:42:44 +0530 Subject: [PATCH 16/49] added godep for heroku --- server/Godeps/Godeps.json | 15 + server/Godeps/Readme | 5 + server/Godeps/_workspace/.gitignore | 2 + .../github.com/gorilla/websocket/.gitignore | 22 + .../github.com/gorilla/websocket/.travis.yml | 6 + .../src/github.com/gorilla/websocket/AUTHORS | 8 + .../src/github.com/gorilla/websocket/LICENSE | 22 + .../github.com/gorilla/websocket/README.md | 59 ++ .../gorilla/websocket/bench_test.go | 19 + .../github.com/gorilla/websocket/client.go | 269 ++++++ .../gorilla/websocket/client_server_test.go | 323 +++++++ .../gorilla/websocket/client_test.go | 64 ++ .../src/github.com/gorilla/websocket/conn.go | 825 ++++++++++++++++++ .../github.com/gorilla/websocket/conn_test.go | 238 +++++ .../src/github.com/gorilla/websocket/doc.go | 148 ++++ .../websocket/examples/autobahn/README.md | 13 + .../examples/autobahn/fuzzingclient.json | 14 + .../websocket/examples/autobahn/server.go | 246 ++++++ .../gorilla/websocket/examples/chat/README.md | 19 + .../gorilla/websocket/examples/chat/conn.go | 106 +++ .../gorilla/websocket/examples/chat/home.html | 92 ++ .../gorilla/websocket/examples/chat/hub.go | 51 ++ .../gorilla/websocket/examples/chat/main.go | 39 + .../websocket/examples/filewatch/README.md | 9 + .../websocket/examples/filewatch/main.go | 193 ++++ .../src/github.com/gorilla/websocket/json.go | 57 ++ .../github.com/gorilla/websocket/json_test.go | 119 +++ .../github.com/gorilla/websocket/server.go | 247 ++++++ .../gorilla/websocket/server_test.go | 33 + .../src/github.com/gorilla/websocket/util.go | 44 + .../github.com/gorilla/websocket/util_test.go | 34 + .../julienschmidt/httprouter/.travis.yml | 8 + .../julienschmidt/httprouter/LICENSE | 24 + .../julienschmidt/httprouter/README.md | 323 +++++++ .../julienschmidt/httprouter/path.go | 123 +++ .../julienschmidt/httprouter/path_test.go | 92 ++ .../julienschmidt/httprouter/router.go | 363 ++++++++ .../julienschmidt/httprouter/router_test.go | 420 +++++++++ .../julienschmidt/httprouter/tree.go | 555 ++++++++++++ .../julienschmidt/httprouter/tree_test.go | 611 +++++++++++++ server/connectionhub.go | 22 +- server/entrapped.go | 2 +- server/troopers.go | 2 +- 43 files changed, 5871 insertions(+), 15 deletions(-) create mode 100644 server/Godeps/Godeps.json create mode 100644 server/Godeps/Readme create mode 100644 server/Godeps/_workspace/.gitignore create mode 100644 server/Godeps/_workspace/src/github.com/gorilla/websocket/.gitignore create mode 100644 server/Godeps/_workspace/src/github.com/gorilla/websocket/.travis.yml create mode 100644 server/Godeps/_workspace/src/github.com/gorilla/websocket/AUTHORS create mode 100644 server/Godeps/_workspace/src/github.com/gorilla/websocket/LICENSE create mode 100644 server/Godeps/_workspace/src/github.com/gorilla/websocket/README.md create mode 100644 server/Godeps/_workspace/src/github.com/gorilla/websocket/bench_test.go create mode 100644 server/Godeps/_workspace/src/github.com/gorilla/websocket/client.go create mode 100644 server/Godeps/_workspace/src/github.com/gorilla/websocket/client_server_test.go create mode 100644 server/Godeps/_workspace/src/github.com/gorilla/websocket/client_test.go create mode 100644 server/Godeps/_workspace/src/github.com/gorilla/websocket/conn.go create mode 100644 server/Godeps/_workspace/src/github.com/gorilla/websocket/conn_test.go create mode 100644 server/Godeps/_workspace/src/github.com/gorilla/websocket/doc.go create mode 100644 server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/autobahn/README.md create mode 100644 server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/autobahn/fuzzingclient.json create mode 100644 server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/autobahn/server.go create mode 100644 server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/README.md create mode 100644 server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/conn.go create mode 100644 server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/home.html create mode 100644 server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/hub.go create mode 100644 server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/main.go create mode 100644 server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/filewatch/README.md create mode 100644 server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/filewatch/main.go create mode 100644 server/Godeps/_workspace/src/github.com/gorilla/websocket/json.go create mode 100644 server/Godeps/_workspace/src/github.com/gorilla/websocket/json_test.go create mode 100644 server/Godeps/_workspace/src/github.com/gorilla/websocket/server.go create mode 100644 server/Godeps/_workspace/src/github.com/gorilla/websocket/server_test.go create mode 100644 server/Godeps/_workspace/src/github.com/gorilla/websocket/util.go create mode 100644 server/Godeps/_workspace/src/github.com/gorilla/websocket/util_test.go create mode 100644 server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/.travis.yml create mode 100644 server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/LICENSE create mode 100644 server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/README.md create mode 100644 server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/path.go create mode 100644 server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/path_test.go create mode 100644 server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/router.go create mode 100644 server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/router_test.go create mode 100644 server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/tree.go create mode 100644 server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/tree_test.go diff --git a/server/Godeps/Godeps.json b/server/Godeps/Godeps.json new file mode 100644 index 0000000..0994362 --- /dev/null +++ b/server/Godeps/Godeps.json @@ -0,0 +1,15 @@ +{ + "ImportPath": "github.com/SKatiyar/entrapped/server", + "GoVersion": "go1.4", + "Deps": [ + { + "ImportPath": "github.com/gorilla/websocket", + "Rev": "a3ec486e6a7a41858210b0fc5d7b5df593b3c4a3" + }, + { + "ImportPath": "github.com/julienschmidt/httprouter", + "Comment": "v1.1-1-g70708e4", + "Rev": "70708e46004c7bcb09b70e685a8b74a690135387" + } + ] +} diff --git a/server/Godeps/Readme b/server/Godeps/Readme new file mode 100644 index 0000000..4cdaa53 --- /dev/null +++ b/server/Godeps/Readme @@ -0,0 +1,5 @@ +This directory tree is generated automatically by godep. + +Please do not edit. + +See https://github.com/tools/godep for more information. diff --git a/server/Godeps/_workspace/.gitignore b/server/Godeps/_workspace/.gitignore new file mode 100644 index 0000000..f037d68 --- /dev/null +++ b/server/Godeps/_workspace/.gitignore @@ -0,0 +1,2 @@ +/pkg +/bin diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/.gitignore b/server/Godeps/_workspace/src/github.com/gorilla/websocket/.gitignore new file mode 100644 index 0000000..0026861 --- /dev/null +++ b/server/Godeps/_workspace/src/github.com/gorilla/websocket/.gitignore @@ -0,0 +1,22 @@ +# Compiled Object files, Static and Dynamic libs (Shared Objects) +*.o +*.a +*.so + +# Folders +_obj +_test + +# Architecture specific extensions/prefixes +*.[568vq] +[568vq].out + +*.cgo1.go +*.cgo2.c +_cgo_defun.c +_cgo_gotypes.go +_cgo_export.* + +_testmain.go + +*.exe diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/.travis.yml b/server/Godeps/_workspace/src/github.com/gorilla/websocket/.travis.yml new file mode 100644 index 0000000..8687342 --- /dev/null +++ b/server/Godeps/_workspace/src/github.com/gorilla/websocket/.travis.yml @@ -0,0 +1,6 @@ +language: go + +go: + - 1.1 + - 1.2 + - tip diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/AUTHORS b/server/Godeps/_workspace/src/github.com/gorilla/websocket/AUTHORS new file mode 100644 index 0000000..b003eca --- /dev/null +++ b/server/Godeps/_workspace/src/github.com/gorilla/websocket/AUTHORS @@ -0,0 +1,8 @@ +# This is the official list of Gorilla WebSocket authors for copyright +# purposes. +# +# Please keep the list sorted. + +Gary Burd +Joachim Bauch + diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/LICENSE b/server/Godeps/_workspace/src/github.com/gorilla/websocket/LICENSE new file mode 100644 index 0000000..9171c97 --- /dev/null +++ b/server/Godeps/_workspace/src/github.com/gorilla/websocket/LICENSE @@ -0,0 +1,22 @@ +Copyright (c) 2013 The Gorilla WebSocket Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + + Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/README.md b/server/Godeps/_workspace/src/github.com/gorilla/websocket/README.md new file mode 100644 index 0000000..9ad75a0 --- /dev/null +++ b/server/Godeps/_workspace/src/github.com/gorilla/websocket/README.md @@ -0,0 +1,59 @@ +# Gorilla WebSocket + +Gorilla WebSocket is a [Go](http://golang.org/) implementation of the +[WebSocket](http://www.rfc-editor.org/rfc/rfc6455.txt) protocol. + +### Documentation + +* [API Reference](http://godoc.org/github.com/gorilla/websocket) +* [Chat example](https://github.com/gorilla/websocket/tree/master/examples/chat) +* [File watch example](https://github.com/gorilla/websocket/tree/master/examples/filewatch) + +### Status + +The Gorilla WebSocket package provides a complete and tested implementation of +the [WebSocket](http://www.rfc-editor.org/rfc/rfc6455.txt) protocol. The +package API is stable. + +### Installation + + go get github.com/gorilla/websocket + +### Protocol Compliance + +The Gorilla WebSocket package passes the server tests in the [Autobahn Test +Suite](http://autobahn.ws/testsuite) using the application in the [examples/autobahn +subdirectory](https://github.com/gorilla/websocket/tree/master/examples/autobahn). + +### Gorilla WebSocket compared with other packages + + + + + + + + + + + + + + + + + + +
github.com/gorillagolang.org/x/net
RFC 6455 Features
Passes Autobahn Test SuiteYesNo
Receive fragmented messageYesNo, see note 1
Send close messageYesNo
Send pings and receive pongsYesNo
Get the type of a received data messageYesYes, see note 2
Other Features
Limit size of received messageYesNo
Read message using io.ReaderYesNo, see note 3
Write message using io.WriteCloserYesNo, see note 3
+ +Notes: + +1. Large messages are fragmented in [Chrome's new WebSocket implementation](http://www.ietf.org/mail-archive/web/hybi/current/msg10503.html). +2. The application can get the type of a received data message by implementing + a [Codec marshal](http://godoc.org/golang.org/x/net/websocket#Codec.Marshal) + function. +3. The go.net io.Reader and io.Writer operate across WebSocket frame boundaries. + Read returns when the input buffer is full or a frame boundary is + encountered. Each call to Write sends a single frame message. The Gorilla + io.Reader and io.WriteCloser operate on a single WebSocket message. + diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/bench_test.go b/server/Godeps/_workspace/src/github.com/gorilla/websocket/bench_test.go new file mode 100644 index 0000000..f66fc36 --- /dev/null +++ b/server/Godeps/_workspace/src/github.com/gorilla/websocket/bench_test.go @@ -0,0 +1,19 @@ +// Copyright 2014 The Gorilla WebSocket Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package websocket + +import ( + "testing" +) + +func BenchmarkMaskBytes(b *testing.B) { + var key [4]byte + data := make([]byte, 1024) + pos := 0 + for i := 0; i < b.N; i++ { + pos = maskBytes(key, pos, data) + } + b.SetBytes(int64(len(data))) +} diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/client.go b/server/Godeps/_workspace/src/github.com/gorilla/websocket/client.go new file mode 100644 index 0000000..93db8dd --- /dev/null +++ b/server/Godeps/_workspace/src/github.com/gorilla/websocket/client.go @@ -0,0 +1,269 @@ +// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package websocket + +import ( + "bytes" + "crypto/tls" + "errors" + "io" + "io/ioutil" + "net" + "net/http" + "net/url" + "strings" + "time" +) + +// ErrBadHandshake is returned when the server response to opening handshake is +// invalid. +var ErrBadHandshake = errors.New("websocket: bad handshake") + +// NewClient creates a new client connection using the given net connection. +// The URL u specifies the host and request URI. Use requestHeader to specify +// the origin (Origin), subprotocols (Sec-WebSocket-Protocol) and cookies +// (Cookie). Use the response.Header to get the selected subprotocol +// (Sec-WebSocket-Protocol) and cookies (Set-Cookie). +// +// If the WebSocket handshake fails, ErrBadHandshake is returned along with a +// non-nil *http.Response so that callers can handle redirects, authentication, +// etc. +func NewClient(netConn net.Conn, u *url.URL, requestHeader http.Header, readBufSize, writeBufSize int) (c *Conn, response *http.Response, err error) { + challengeKey, err := generateChallengeKey() + if err != nil { + return nil, nil, err + } + acceptKey := computeAcceptKey(challengeKey) + + c = newConn(netConn, false, readBufSize, writeBufSize) + p := c.writeBuf[:0] + p = append(p, "GET "...) + p = append(p, u.RequestURI()...) + p = append(p, " HTTP/1.1\r\nHost: "...) + p = append(p, u.Host...) + // "Upgrade" is capitalized for servers that do not use case insensitive + // comparisons on header tokens. + p = append(p, "\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Version: 13\r\nSec-WebSocket-Key: "...) + p = append(p, challengeKey...) + p = append(p, "\r\n"...) + for k, vs := range requestHeader { + for _, v := range vs { + p = append(p, k...) + p = append(p, ": "...) + p = append(p, v...) + p = append(p, "\r\n"...) + } + } + p = append(p, "\r\n"...) + + if _, err := netConn.Write(p); err != nil { + return nil, nil, err + } + + resp, err := http.ReadResponse(c.br, &http.Request{Method: "GET", URL: u}) + if err != nil { + return nil, nil, err + } + if resp.StatusCode != 101 || + !strings.EqualFold(resp.Header.Get("Upgrade"), "websocket") || + !strings.EqualFold(resp.Header.Get("Connection"), "upgrade") || + resp.Header.Get("Sec-Websocket-Accept") != acceptKey { + return nil, resp, ErrBadHandshake + } + c.subprotocol = resp.Header.Get("Sec-Websocket-Protocol") + return c, resp, nil +} + +// A Dialer contains options for connecting to WebSocket server. +type Dialer struct { + // NetDial specifies the dial function for creating TCP connections. If + // NetDial is nil, net.Dial is used. + NetDial func(network, addr string) (net.Conn, error) + + // TLSClientConfig specifies the TLS configuration to use with tls.Client. + // If nil, the default configuration is used. + TLSClientConfig *tls.Config + + // HandshakeTimeout specifies the duration for the handshake to complete. + HandshakeTimeout time.Duration + + // Input and output buffer sizes. If the buffer size is zero, then a + // default value of 4096 is used. + ReadBufferSize, WriteBufferSize int + + // Subprotocols specifies the client's requested subprotocols. + Subprotocols []string +} + +var errMalformedURL = errors.New("malformed ws or wss URL") + +// parseURL parses the URL. The url.Parse function is not used here because +// url.Parse mangles the path. +func parseURL(s string) (*url.URL, error) { + // From the RFC: + // + // ws-URI = "ws:" "//" host [ ":" port ] path [ "?" query ] + // wss-URI = "wss:" "//" host [ ":" port ] path [ "?" query ] + // + // We don't use the net/url parser here because the dialer interface does + // not provide a way for applications to work around percent deocding in + // the net/url parser. + + var u url.URL + switch { + case strings.HasPrefix(s, "ws://"): + u.Scheme = "ws" + s = s[len("ws://"):] + case strings.HasPrefix(s, "wss://"): + u.Scheme = "wss" + s = s[len("wss://"):] + default: + return nil, errMalformedURL + } + + u.Host = s + u.Opaque = "/" + if i := strings.Index(s, "/"); i >= 0 { + u.Host = s[:i] + u.Opaque = s[i:] + } + + if strings.Contains(u.Host, "@") { + // WebSocket URIs do not contain user information. + return nil, errMalformedURL + } + + return &u, nil +} + +func hostPortNoPort(u *url.URL) (hostPort, hostNoPort string) { + hostPort = u.Host + hostNoPort = u.Host + if i := strings.LastIndex(u.Host, ":"); i > strings.LastIndex(u.Host, "]") { + hostNoPort = hostNoPort[:i] + } else { + if u.Scheme == "wss" { + hostPort += ":443" + } else { + hostPort += ":80" + } + } + return hostPort, hostNoPort +} + +// DefaultDialer is a dialer with all fields set to the default zero values. +var DefaultDialer *Dialer + +// Dial creates a new client connection. Use requestHeader to specify the +// origin (Origin), subprotocols (Sec-WebSocket-Protocol) and cookies (Cookie). +// Use the response.Header to get the selected subprotocol +// (Sec-WebSocket-Protocol) and cookies (Set-Cookie). +// +// If the WebSocket handshake fails, ErrBadHandshake is returned along with a +// non-nil *http.Response so that callers can handle redirects, authentication, +// etcetera. The response body may not contain the entire response and does not +// need to be closed by the application. +func (d *Dialer) Dial(urlStr string, requestHeader http.Header) (*Conn, *http.Response, error) { + u, err := parseURL(urlStr) + if err != nil { + return nil, nil, err + } + + hostPort, hostNoPort := hostPortNoPort(u) + + if d == nil { + d = &Dialer{} + } + + var deadline time.Time + if d.HandshakeTimeout != 0 { + deadline = time.Now().Add(d.HandshakeTimeout) + } + + netDial := d.NetDial + if netDial == nil { + netDialer := &net.Dialer{Deadline: deadline} + netDial = netDialer.Dial + } + + netConn, err := netDial("tcp", hostPort) + if err != nil { + return nil, nil, err + } + + defer func() { + if netConn != nil { + netConn.Close() + } + }() + + if err := netConn.SetDeadline(deadline); err != nil { + return nil, nil, err + } + + if u.Scheme == "wss" { + cfg := d.TLSClientConfig + if cfg == nil { + cfg = &tls.Config{ServerName: hostNoPort} + } else if cfg.ServerName == "" { + shallowCopy := *cfg + cfg = &shallowCopy + cfg.ServerName = hostNoPort + } + tlsConn := tls.Client(netConn, cfg) + netConn = tlsConn + if err := tlsConn.Handshake(); err != nil { + return nil, nil, err + } + if !cfg.InsecureSkipVerify { + if err := tlsConn.VerifyHostname(cfg.ServerName); err != nil { + return nil, nil, err + } + } + } + + if len(d.Subprotocols) > 0 { + h := http.Header{} + for k, v := range requestHeader { + h[k] = v + } + h.Set("Sec-Websocket-Protocol", strings.Join(d.Subprotocols, ", ")) + requestHeader = h + } + + if len(requestHeader["Host"]) > 0 { + // This can be used to supply a Host: header which is different from + // the dial address. + u.Host = requestHeader.Get("Host") + + // Drop "Host" header + h := http.Header{} + for k, v := range requestHeader { + if k == "Host" { + continue + } + h[k] = v + } + requestHeader = h + } + + conn, resp, err := NewClient(netConn, u, requestHeader, d.ReadBufferSize, d.WriteBufferSize) + + if err != nil { + if err == ErrBadHandshake { + // Before closing the network connection on return from this + // function, slurp up some of the response to aid application + // debugging. + buf := make([]byte, 1024) + n, _ := io.ReadFull(resp.Body, buf) + resp.Body = ioutil.NopCloser(bytes.NewReader(buf[:n])) + } + return nil, resp, err + } + + netConn.SetDeadline(time.Time{}) + netConn = nil // to avoid close in defer. + return conn, resp, nil +} diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/client_server_test.go b/server/Godeps/_workspace/src/github.com/gorilla/websocket/client_server_test.go new file mode 100644 index 0000000..749ef20 --- /dev/null +++ b/server/Godeps/_workspace/src/github.com/gorilla/websocket/client_server_test.go @@ -0,0 +1,323 @@ +// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package websocket + +import ( + "crypto/tls" + "crypto/x509" + "io" + "io/ioutil" + "net" + "net/http" + "net/http/httptest" + "net/url" + "reflect" + "strings" + "testing" + "time" +) + +var cstUpgrader = Upgrader{ + Subprotocols: []string{"p0", "p1"}, + ReadBufferSize: 1024, + WriteBufferSize: 1024, + Error: func(w http.ResponseWriter, r *http.Request, status int, reason error) { + http.Error(w, reason.Error(), status) + }, +} + +var cstDialer = Dialer{ + Subprotocols: []string{"p1", "p2"}, + ReadBufferSize: 1024, + WriteBufferSize: 1024, +} + +type cstHandler struct{ *testing.T } + +type cstServer struct { + *httptest.Server + URL string +} + +func newServer(t *testing.T) *cstServer { + var s cstServer + s.Server = httptest.NewServer(cstHandler{t}) + s.URL = makeWsProto(s.Server.URL) + return &s +} + +func newTLSServer(t *testing.T) *cstServer { + var s cstServer + s.Server = httptest.NewTLSServer(cstHandler{t}) + s.URL = makeWsProto(s.Server.URL) + return &s +} + +func (t cstHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + if r.Method != "GET" { + t.Logf("method %s not allowed", r.Method) + http.Error(w, "method not allowed", 405) + return + } + subprotos := Subprotocols(r) + if !reflect.DeepEqual(subprotos, cstDialer.Subprotocols) { + t.Logf("subprotols=%v, want %v", subprotos, cstDialer.Subprotocols) + http.Error(w, "bad protocol", 400) + return + } + ws, err := cstUpgrader.Upgrade(w, r, http.Header{"Set-Cookie": {"sessionID=1234"}}) + if err != nil { + t.Logf("Upgrade: %v", err) + return + } + defer ws.Close() + + if ws.Subprotocol() != "p1" { + t.Logf("Subprotocol() = %s, want p1", ws.Subprotocol()) + ws.Close() + return + } + op, rd, err := ws.NextReader() + if err != nil { + t.Logf("NextReader: %v", err) + return + } + wr, err := ws.NextWriter(op) + if err != nil { + t.Logf("NextWriter: %v", err) + return + } + if _, err = io.Copy(wr, rd); err != nil { + t.Logf("NextWriter: %v", err) + return + } + if err := wr.Close(); err != nil { + t.Logf("Close: %v", err) + return + } +} + +func makeWsProto(s string) string { + return "ws" + strings.TrimPrefix(s, "http") +} + +func sendRecv(t *testing.T, ws *Conn) { + const message = "Hello World!" + if err := ws.SetWriteDeadline(time.Now().Add(time.Second)); err != nil { + t.Fatalf("SetWriteDeadline: %v", err) + } + if err := ws.WriteMessage(TextMessage, []byte(message)); err != nil { + t.Fatalf("WriteMessage: %v", err) + } + if err := ws.SetReadDeadline(time.Now().Add(time.Second)); err != nil { + t.Fatalf("SetReadDeadline: %v", err) + } + _, p, err := ws.ReadMessage() + if err != nil { + t.Fatalf("ReadMessage: %v", err) + } + if string(p) != message { + t.Fatalf("message=%s, want %s", p, message) + } +} + +func TestDial(t *testing.T) { + s := newServer(t) + defer s.Close() + + ws, _, err := cstDialer.Dial(s.URL, nil) + if err != nil { + t.Fatalf("Dial: %v", err) + } + defer ws.Close() + sendRecv(t, ws) +} + +func TestDialTLS(t *testing.T) { + s := newTLSServer(t) + defer s.Close() + + certs := x509.NewCertPool() + for _, c := range s.TLS.Certificates { + roots, err := x509.ParseCertificates(c.Certificate[len(c.Certificate)-1]) + if err != nil { + t.Fatalf("error parsing server's root cert: %v", err) + } + for _, root := range roots { + certs.AddCert(root) + } + } + + u, _ := url.Parse(s.URL) + d := cstDialer + d.NetDial = func(network, addr string) (net.Conn, error) { return net.Dial(network, u.Host) } + d.TLSClientConfig = &tls.Config{RootCAs: certs} + ws, _, err := d.Dial("wss://example.com/", nil) + if err != nil { + t.Fatalf("Dial: %v", err) + } + defer ws.Close() + sendRecv(t, ws) +} + +func xTestDialTLSBadCert(t *testing.T) { + // This test is deactivated because of noisy logging from the net/http package. + s := newTLSServer(t) + defer s.Close() + + ws, _, err := cstDialer.Dial(s.URL, nil) + if err == nil { + ws.Close() + t.Fatalf("Dial: nil") + } +} + +func xTestDialTLSNoVerify(t *testing.T) { + s := newTLSServer(t) + defer s.Close() + + d := cstDialer + d.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} + ws, _, err := d.Dial(s.URL, nil) + if err != nil { + t.Fatalf("Dial: %v", err) + } + defer ws.Close() + sendRecv(t, ws) +} + +func TestDialTimeout(t *testing.T) { + s := newServer(t) + defer s.Close() + + d := cstDialer + d.HandshakeTimeout = -1 + ws, _, err := d.Dial(s.URL, nil) + if err == nil { + ws.Close() + t.Fatalf("Dial: nil") + } +} + +func TestDialBadScheme(t *testing.T) { + s := newServer(t) + defer s.Close() + + ws, _, err := cstDialer.Dial(s.Server.URL, nil) + if err == nil { + ws.Close() + t.Fatalf("Dial: nil") + } +} + +func TestDialBadOrigin(t *testing.T) { + s := newServer(t) + defer s.Close() + + ws, resp, err := cstDialer.Dial(s.URL, http.Header{"Origin": {"bad"}}) + if err == nil { + ws.Close() + t.Fatalf("Dial: nil") + } + if resp == nil { + t.Fatalf("resp=nil, err=%v", err) + } + if resp.StatusCode != http.StatusForbidden { + t.Fatalf("status=%d, want %d", resp.StatusCode, http.StatusForbidden) + } +} + +func TestHandshake(t *testing.T) { + s := newServer(t) + defer s.Close() + + ws, resp, err := cstDialer.Dial(s.URL, http.Header{"Origin": {s.URL}}) + if err != nil { + t.Fatalf("Dial: %v", err) + } + defer ws.Close() + + var sessionID string + for _, c := range resp.Cookies() { + if c.Name == "sessionID" { + sessionID = c.Value + } + } + if sessionID != "1234" { + t.Error("Set-Cookie not received from the server.") + } + + if ws.Subprotocol() != "p1" { + t.Errorf("ws.Subprotocol() = %s, want p1", ws.Subprotocol()) + } + sendRecv(t, ws) +} + +func TestRespOnBadHandshake(t *testing.T) { + const expectedStatus = http.StatusGone + const expectedBody = "This is the response body." + + s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(expectedStatus) + io.WriteString(w, expectedBody) + })) + defer s.Close() + + ws, resp, err := cstDialer.Dial(makeWsProto(s.URL), nil) + if err == nil { + ws.Close() + t.Fatalf("Dial: nil") + } + + if resp == nil { + t.Fatalf("resp=nil, err=%v", err) + } + + if resp.StatusCode != expectedStatus { + t.Errorf("resp.StatusCode=%d, want %d", resp.StatusCode, expectedStatus) + } + + p, err := ioutil.ReadAll(resp.Body) + if err != nil { + t.Fatalf("ReadFull(resp.Body) returned error %v", err) + } + + if string(p) != expectedBody { + t.Errorf("resp.Body=%s, want %s", p, expectedBody) + } +} + +// If the Host header is specified in `Dial()`, the server must receive it as +// the `Host:` header. +func TestHostHeader(t *testing.T) { + s := newServer(t) + defer s.Close() + + specifiedHost := make(chan string, 1) + origHandler := s.Server.Config.Handler + + // Capture the request Host header. + s.Server.Config.Handler = http.HandlerFunc( + func(w http.ResponseWriter, r *http.Request) { + specifiedHost <- r.Host + origHandler.ServeHTTP(w, r) + }) + + ws, resp, err := cstDialer.Dial(s.URL, http.Header{"Host": {"testhost"}}) + if err != nil { + t.Fatalf("Dial: %v", err) + } + defer ws.Close() + + if resp.StatusCode != http.StatusSwitchingProtocols { + t.Fatalf("resp.StatusCode = %v, want http.StatusSwitchingProtocols", resp.StatusCode) + } + + if gotHost := <-specifiedHost; gotHost != "testhost" { + t.Fatalf("gotHost = %q, want \"testhost\"", gotHost) + } + + sendRecv(t, ws) +} diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/client_test.go b/server/Godeps/_workspace/src/github.com/gorilla/websocket/client_test.go new file mode 100644 index 0000000..07a9cb4 --- /dev/null +++ b/server/Godeps/_workspace/src/github.com/gorilla/websocket/client_test.go @@ -0,0 +1,64 @@ +// Copyright 2014 The Gorilla WebSocket Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package websocket + +import ( + "net/url" + "reflect" + "testing" +) + +var parseURLTests = []struct { + s string + u *url.URL +}{ + {"ws://example.com/", &url.URL{Scheme: "ws", Host: "example.com", Opaque: "/"}}, + {"ws://example.com", &url.URL{Scheme: "ws", Host: "example.com", Opaque: "/"}}, + {"ws://example.com:7777/", &url.URL{Scheme: "ws", Host: "example.com:7777", Opaque: "/"}}, + {"wss://example.com/", &url.URL{Scheme: "wss", Host: "example.com", Opaque: "/"}}, + {"wss://example.com/a/b", &url.URL{Scheme: "wss", Host: "example.com", Opaque: "/a/b"}}, + {"ss://example.com/a/b", nil}, + {"ws://webmaster@example.com/", nil}, +} + +func TestParseURL(t *testing.T) { + for _, tt := range parseURLTests { + u, err := parseURL(tt.s) + if tt.u != nil && err != nil { + t.Errorf("parseURL(%q) returned error %v", tt.s, err) + continue + } + if tt.u == nil && err == nil { + t.Errorf("parseURL(%q) did not return error", tt.s) + continue + } + if !reflect.DeepEqual(u, tt.u) { + t.Errorf("parseURL(%q) returned %v, want %v", tt.s, u, tt.u) + continue + } + } +} + +var hostPortNoPortTests = []struct { + u *url.URL + hostPort, hostNoPort string +}{ + {&url.URL{Scheme: "ws", Host: "example.com"}, "example.com:80", "example.com"}, + {&url.URL{Scheme: "wss", Host: "example.com"}, "example.com:443", "example.com"}, + {&url.URL{Scheme: "ws", Host: "example.com:7777"}, "example.com:7777", "example.com"}, + {&url.URL{Scheme: "wss", Host: "example.com:7777"}, "example.com:7777", "example.com"}, +} + +func TestHostPortNoPort(t *testing.T) { + for _, tt := range hostPortNoPortTests { + hostPort, hostNoPort := hostPortNoPort(tt.u) + if hostPort != tt.hostPort { + t.Errorf("hostPortNoPort(%v) returned hostPort %q, want %q", tt.u, hostPort, tt.hostPort) + } + if hostNoPort != tt.hostNoPort { + t.Errorf("hostPortNoPort(%v) returned hostNoPort %q, want %q", tt.u, hostNoPort, tt.hostNoPort) + } + } +} diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/conn.go b/server/Godeps/_workspace/src/github.com/gorilla/websocket/conn.go new file mode 100644 index 0000000..e719f1c --- /dev/null +++ b/server/Godeps/_workspace/src/github.com/gorilla/websocket/conn.go @@ -0,0 +1,825 @@ +// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package websocket + +import ( + "bufio" + "encoding/binary" + "errors" + "io" + "io/ioutil" + "math/rand" + "net" + "strconv" + "time" +) + +const ( + maxFrameHeaderSize = 2 + 8 + 4 // Fixed header + length + mask + maxControlFramePayloadSize = 125 + finalBit = 1 << 7 + maskBit = 1 << 7 + writeWait = time.Second + + defaultReadBufferSize = 4096 + defaultWriteBufferSize = 4096 + + continuationFrame = 0 + noFrame = -1 +) + +// Close codes defined in RFC 6455, section 11.7. +const ( + CloseNormalClosure = 1000 + CloseGoingAway = 1001 + CloseProtocolError = 1002 + CloseUnsupportedData = 1003 + CloseNoStatusReceived = 1005 + CloseAbnormalClosure = 1006 + CloseInvalidFramePayloadData = 1007 + ClosePolicyViolation = 1008 + CloseMessageTooBig = 1009 + CloseMandatoryExtension = 1010 + CloseInternalServerErr = 1011 + CloseTLSHandshake = 1015 +) + +// The message types are defined in RFC 6455, section 11.8. +const ( + // TextMessage denotes a text data message. The text message payload is + // interpreted as UTF-8 encoded text data. + TextMessage = 1 + + // BinaryMessage denotes a binary data message. + BinaryMessage = 2 + + // CloseMessage denotes a close control message. The optional message + // payload contains a numeric code and text. Use the FormatCloseMessage + // function to format a close message payload. + CloseMessage = 8 + + // PingMessage denotes a ping control message. The optional message payload + // is UTF-8 encoded text. + PingMessage = 9 + + // PongMessage denotes a ping control message. The optional message payload + // is UTF-8 encoded text. + PongMessage = 10 +) + +// ErrCloseSent is returned when the application writes a message to the +// connection after sending a close message. +var ErrCloseSent = errors.New("websocket: close sent") + +// ErrReadLimit is returned when reading a message that is larger than the +// read limit set for the connection. +var ErrReadLimit = errors.New("websocket: read limit exceeded") + +// netError satisfies the net Error interface. +type netError struct { + msg string + temporary bool + timeout bool +} + +func (e *netError) Error() string { return e.msg } +func (e *netError) Temporary() bool { return e.temporary } +func (e *netError) Timeout() bool { return e.timeout } + +// closeError represents close frame. +type closeError struct { + code int + text string +} + +func (e *closeError) Error() string { + return "websocket: close " + strconv.Itoa(e.code) + " " + e.text +} + +var ( + errWriteTimeout = &netError{msg: "websocket: write timeout", timeout: true} + errUnexpectedEOF = &closeError{code: CloseAbnormalClosure, text: io.ErrUnexpectedEOF.Error()} + errBadWriteOpCode = errors.New("websocket: bad write message type") + errWriteClosed = errors.New("websocket: write closed") + errInvalidControlFrame = errors.New("websocket: invalid control frame") +) + +func hideTempErr(err error) error { + if e, ok := err.(net.Error); ok && e.Temporary() { + err = &netError{msg: e.Error(), timeout: e.Timeout()} + } + return err +} + +func isControl(frameType int) bool { + return frameType == CloseMessage || frameType == PingMessage || frameType == PongMessage +} + +func isData(frameType int) bool { + return frameType == TextMessage || frameType == BinaryMessage +} + +func maskBytes(key [4]byte, pos int, b []byte) int { + for i := range b { + b[i] ^= key[pos&3] + pos++ + } + return pos & 3 +} + +func newMaskKey() [4]byte { + n := rand.Uint32() + return [4]byte{byte(n), byte(n >> 8), byte(n >> 16), byte(n >> 24)} +} + +// Conn represents a WebSocket connection. +type Conn struct { + conn net.Conn + isServer bool + subprotocol string + + // Write fields + mu chan bool // used as mutex to protect write to conn and closeSent + closeSent bool // true if close message was sent + + // Message writer fields. + writeErr error + writeBuf []byte // frame is constructed in this buffer. + writePos int // end of data in writeBuf. + writeFrameType int // type of the current frame. + writeSeq int // incremented to invalidate message writers. + writeDeadline time.Time + + // Read fields + readErr error + br *bufio.Reader + readRemaining int64 // bytes remaining in current frame. + readFinal bool // true the current message has more frames. + readSeq int // incremented to invalidate message readers. + readLength int64 // Message size. + readLimit int64 // Maximum message size. + readMaskPos int + readMaskKey [4]byte + handlePong func(string) error + handlePing func(string) error +} + +func newConn(conn net.Conn, isServer bool, readBufferSize, writeBufferSize int) *Conn { + mu := make(chan bool, 1) + mu <- true + + if readBufferSize == 0 { + readBufferSize = defaultReadBufferSize + } + if writeBufferSize == 0 { + writeBufferSize = defaultWriteBufferSize + } + + c := &Conn{ + isServer: isServer, + br: bufio.NewReaderSize(conn, readBufferSize), + conn: conn, + mu: mu, + readFinal: true, + writeBuf: make([]byte, writeBufferSize+maxFrameHeaderSize), + writeFrameType: noFrame, + writePos: maxFrameHeaderSize, + } + c.SetPingHandler(nil) + c.SetPongHandler(nil) + return c +} + +// Subprotocol returns the negotiated protocol for the connection. +func (c *Conn) Subprotocol() string { + return c.subprotocol +} + +// Close closes the underlying network connection without sending or waiting for a close frame. +func (c *Conn) Close() error { + return c.conn.Close() +} + +// LocalAddr returns the local network address. +func (c *Conn) LocalAddr() net.Addr { + return c.conn.LocalAddr() +} + +// RemoteAddr returns the remote network address. +func (c *Conn) RemoteAddr() net.Addr { + return c.conn.RemoteAddr() +} + +// Write methods + +func (c *Conn) write(frameType int, deadline time.Time, bufs ...[]byte) error { + <-c.mu + defer func() { c.mu <- true }() + + if c.closeSent { + return ErrCloseSent + } else if frameType == CloseMessage { + c.closeSent = true + } + + c.conn.SetWriteDeadline(deadline) + for _, buf := range bufs { + if len(buf) > 0 { + n, err := c.conn.Write(buf) + if n != len(buf) { + // Close on partial write. + c.conn.Close() + } + if err != nil { + return err + } + } + } + return nil +} + +// WriteControl writes a control message with the given deadline. The allowed +// message types are CloseMessage, PingMessage and PongMessage. +func (c *Conn) WriteControl(messageType int, data []byte, deadline time.Time) error { + if !isControl(messageType) { + return errBadWriteOpCode + } + if len(data) > maxControlFramePayloadSize { + return errInvalidControlFrame + } + + b0 := byte(messageType) | finalBit + b1 := byte(len(data)) + if !c.isServer { + b1 |= maskBit + } + + buf := make([]byte, 0, maxFrameHeaderSize+maxControlFramePayloadSize) + buf = append(buf, b0, b1) + + if c.isServer { + buf = append(buf, data...) + } else { + key := newMaskKey() + buf = append(buf, key[:]...) + buf = append(buf, data...) + maskBytes(key, 0, buf[6:]) + } + + d := time.Hour * 1000 + if !deadline.IsZero() { + d = deadline.Sub(time.Now()) + if d < 0 { + return errWriteTimeout + } + } + + timer := time.NewTimer(d) + select { + case <-c.mu: + timer.Stop() + case <-timer.C: + return errWriteTimeout + } + defer func() { c.mu <- true }() + + if c.closeSent { + return ErrCloseSent + } else if messageType == CloseMessage { + c.closeSent = true + } + + c.conn.SetWriteDeadline(deadline) + n, err := c.conn.Write(buf) + if n != 0 && n != len(buf) { + c.conn.Close() + } + return err +} + +// NextWriter returns a writer for the next message to send. The writer's +// Close method flushes the complete message to the network. +// +// There can be at most one open writer on a connection. NextWriter closes the +// previous writer if the application has not already done so. +// +// The NextWriter method and the writers returned from the method cannot be +// accessed by more than one goroutine at a time. +func (c *Conn) NextWriter(messageType int) (io.WriteCloser, error) { + if c.writeErr != nil { + return nil, c.writeErr + } + + if c.writeFrameType != noFrame { + if err := c.flushFrame(true, nil); err != nil { + return nil, err + } + } + + if !isControl(messageType) && !isData(messageType) { + return nil, errBadWriteOpCode + } + + c.writeFrameType = messageType + return messageWriter{c, c.writeSeq}, nil +} + +func (c *Conn) flushFrame(final bool, extra []byte) error { + length := c.writePos - maxFrameHeaderSize + len(extra) + + // Check for invalid control frames. + if isControl(c.writeFrameType) && + (!final || length > maxControlFramePayloadSize) { + c.writeSeq++ + c.writeFrameType = noFrame + c.writePos = maxFrameHeaderSize + return errInvalidControlFrame + } + + b0 := byte(c.writeFrameType) + if final { + b0 |= finalBit + } + b1 := byte(0) + if !c.isServer { + b1 |= maskBit + } + + // Assume that the frame starts at beginning of c.writeBuf. + framePos := 0 + if c.isServer { + // Adjust up if mask not included in the header. + framePos = 4 + } + + switch { + case length >= 65536: + c.writeBuf[framePos] = b0 + c.writeBuf[framePos+1] = b1 | 127 + binary.BigEndian.PutUint64(c.writeBuf[framePos+2:], uint64(length)) + case length > 125: + framePos += 6 + c.writeBuf[framePos] = b0 + c.writeBuf[framePos+1] = b1 | 126 + binary.BigEndian.PutUint16(c.writeBuf[framePos+2:], uint16(length)) + default: + framePos += 8 + c.writeBuf[framePos] = b0 + c.writeBuf[framePos+1] = b1 | byte(length) + } + + if !c.isServer { + key := newMaskKey() + copy(c.writeBuf[maxFrameHeaderSize-4:], key[:]) + maskBytes(key, 0, c.writeBuf[maxFrameHeaderSize:c.writePos]) + if len(extra) > 0 { + c.writeErr = errors.New("websocket: internal error, extra used in client mode") + return c.writeErr + } + } + + // Write the buffers to the connection. + c.writeErr = c.write(c.writeFrameType, c.writeDeadline, c.writeBuf[framePos:c.writePos], extra) + + // Setup for next frame. + c.writePos = maxFrameHeaderSize + c.writeFrameType = continuationFrame + if final { + c.writeSeq++ + c.writeFrameType = noFrame + } + return c.writeErr +} + +type messageWriter struct { + c *Conn + seq int +} + +func (w messageWriter) err() error { + c := w.c + if c.writeSeq != w.seq { + return errWriteClosed + } + if c.writeErr != nil { + return c.writeErr + } + return nil +} + +func (w messageWriter) ncopy(max int) (int, error) { + n := len(w.c.writeBuf) - w.c.writePos + if n <= 0 { + if err := w.c.flushFrame(false, nil); err != nil { + return 0, err + } + n = len(w.c.writeBuf) - w.c.writePos + } + if n > max { + n = max + } + return n, nil +} + +func (w messageWriter) write(final bool, p []byte) (int, error) { + if err := w.err(); err != nil { + return 0, err + } + + if len(p) > 2*len(w.c.writeBuf) && w.c.isServer { + // Don't buffer large messages. + err := w.c.flushFrame(final, p) + if err != nil { + return 0, err + } + return len(p), nil + } + + nn := len(p) + for len(p) > 0 { + n, err := w.ncopy(len(p)) + if err != nil { + return 0, err + } + copy(w.c.writeBuf[w.c.writePos:], p[:n]) + w.c.writePos += n + p = p[n:] + } + return nn, nil +} + +func (w messageWriter) Write(p []byte) (int, error) { + return w.write(false, p) +} + +func (w messageWriter) WriteString(p string) (int, error) { + if err := w.err(); err != nil { + return 0, err + } + + nn := len(p) + for len(p) > 0 { + n, err := w.ncopy(len(p)) + if err != nil { + return 0, err + } + copy(w.c.writeBuf[w.c.writePos:], p[:n]) + w.c.writePos += n + p = p[n:] + } + return nn, nil +} + +func (w messageWriter) ReadFrom(r io.Reader) (nn int64, err error) { + if err := w.err(); err != nil { + return 0, err + } + for { + if w.c.writePos == len(w.c.writeBuf) { + err = w.c.flushFrame(false, nil) + if err != nil { + break + } + } + var n int + n, err = r.Read(w.c.writeBuf[w.c.writePos:]) + w.c.writePos += n + nn += int64(n) + if err != nil { + if err == io.EOF { + err = nil + } + break + } + } + return nn, err +} + +func (w messageWriter) Close() error { + if err := w.err(); err != nil { + return err + } + return w.c.flushFrame(true, nil) +} + +// WriteMessage is a helper method for getting a writer using NextWriter, +// writing the message and closing the writer. +func (c *Conn) WriteMessage(messageType int, data []byte) error { + wr, err := c.NextWriter(messageType) + if err != nil { + return err + } + w := wr.(messageWriter) + if _, err := w.write(true, data); err != nil { + return err + } + if c.writeSeq == w.seq { + if err := c.flushFrame(true, nil); err != nil { + return err + } + } + return nil +} + +// SetWriteDeadline sets the write deadline on the underlying network +// connection. After a write has timed out, the websocket state is corrupt and +// all future writes will return an error. A zero value for t means writes will +// not time out. +func (c *Conn) SetWriteDeadline(t time.Time) error { + c.writeDeadline = t + return nil +} + +// Read methods + +// readFull is like io.ReadFull except that io.EOF is never returned. +func (c *Conn) readFull(p []byte) (err error) { + var n int + for n < len(p) && err == nil { + var nn int + nn, err = c.br.Read(p[n:]) + n += nn + } + if n == len(p) { + err = nil + } else if err == io.EOF { + err = errUnexpectedEOF + } + return +} + +func (c *Conn) advanceFrame() (int, error) { + + // 1. Skip remainder of previous frame. + + if c.readRemaining > 0 { + if _, err := io.CopyN(ioutil.Discard, c.br, c.readRemaining); err != nil { + return noFrame, err + } + } + + // 2. Read and parse first two bytes of frame header. + + var b [8]byte + if err := c.readFull(b[:2]); err != nil { + return noFrame, err + } + + final := b[0]&finalBit != 0 + frameType := int(b[0] & 0xf) + reserved := int((b[0] >> 4) & 0x7) + mask := b[1]&maskBit != 0 + c.readRemaining = int64(b[1] & 0x7f) + + if reserved != 0 { + return noFrame, c.handleProtocolError("unexpected reserved bits " + strconv.Itoa(reserved)) + } + + switch frameType { + case CloseMessage, PingMessage, PongMessage: + if c.readRemaining > maxControlFramePayloadSize { + return noFrame, c.handleProtocolError("control frame length > 125") + } + if !final { + return noFrame, c.handleProtocolError("control frame not final") + } + case TextMessage, BinaryMessage: + if !c.readFinal { + return noFrame, c.handleProtocolError("message start before final message frame") + } + c.readFinal = final + case continuationFrame: + if c.readFinal { + return noFrame, c.handleProtocolError("continuation after final message frame") + } + c.readFinal = final + default: + return noFrame, c.handleProtocolError("unknown opcode " + strconv.Itoa(frameType)) + } + + // 3. Read and parse frame length. + + switch c.readRemaining { + case 126: + if err := c.readFull(b[:2]); err != nil { + return noFrame, err + } + c.readRemaining = int64(binary.BigEndian.Uint16(b[:2])) + case 127: + if err := c.readFull(b[:8]); err != nil { + return noFrame, err + } + c.readRemaining = int64(binary.BigEndian.Uint64(b[:8])) + } + + // 4. Handle frame masking. + + if mask != c.isServer { + return noFrame, c.handleProtocolError("incorrect mask flag") + } + + if mask { + c.readMaskPos = 0 + if err := c.readFull(c.readMaskKey[:]); err != nil { + return noFrame, err + } + } + + // 5. For text and binary messages, enforce read limit and return. + + if frameType == continuationFrame || frameType == TextMessage || frameType == BinaryMessage { + + c.readLength += c.readRemaining + if c.readLimit > 0 && c.readLength > c.readLimit { + c.WriteControl(CloseMessage, FormatCloseMessage(CloseMessageTooBig, ""), time.Now().Add(writeWait)) + return noFrame, ErrReadLimit + } + + return frameType, nil + } + + // 6. Read control frame payload. + + var payload []byte + if c.readRemaining > 0 { + payload = make([]byte, c.readRemaining) + c.readRemaining = 0 + if err := c.readFull(payload); err != nil { + return noFrame, err + } + if c.isServer { + maskBytes(c.readMaskKey, 0, payload) + } + } + + // 7. Process control frame payload. + + switch frameType { + case PongMessage: + if err := c.handlePong(string(payload)); err != nil { + return noFrame, err + } + case PingMessage: + if err := c.handlePing(string(payload)); err != nil { + return noFrame, err + } + case CloseMessage: + c.WriteControl(CloseMessage, []byte{}, time.Now().Add(writeWait)) + closeCode := CloseNoStatusReceived + closeText := "" + if len(payload) >= 2 { + closeCode = int(binary.BigEndian.Uint16(payload)) + closeText = string(payload[2:]) + } + switch closeCode { + case CloseNormalClosure, CloseGoingAway: + return noFrame, io.EOF + default: + return noFrame, &closeError{code: closeCode, text: closeText} + } + } + + return frameType, nil +} + +func (c *Conn) handleProtocolError(message string) error { + c.WriteControl(CloseMessage, FormatCloseMessage(CloseProtocolError, message), time.Now().Add(writeWait)) + return errors.New("websocket: " + message) +} + +// NextReader returns the next data message received from the peer. The +// returned messageType is either TextMessage or BinaryMessage. +// +// There can be at most one open reader on a connection. NextReader discards +// the previous message if the application has not already consumed it. +// +// The NextReader method and the readers returned from the method cannot be +// accessed by more than one goroutine at a time. +func (c *Conn) NextReader() (messageType int, r io.Reader, err error) { + + c.readSeq++ + c.readLength = 0 + + for c.readErr == nil { + frameType, err := c.advanceFrame() + if err != nil { + c.readErr = hideTempErr(err) + break + } + if frameType == TextMessage || frameType == BinaryMessage { + return frameType, messageReader{c, c.readSeq}, nil + } + } + return noFrame, nil, c.readErr +} + +type messageReader struct { + c *Conn + seq int +} + +func (r messageReader) Read(b []byte) (int, error) { + + if r.seq != r.c.readSeq { + return 0, io.EOF + } + + for r.c.readErr == nil { + + if r.c.readRemaining > 0 { + if int64(len(b)) > r.c.readRemaining { + b = b[:r.c.readRemaining] + } + n, err := r.c.br.Read(b) + r.c.readErr = hideTempErr(err) + if r.c.isServer { + r.c.readMaskPos = maskBytes(r.c.readMaskKey, r.c.readMaskPos, b[:n]) + } + r.c.readRemaining -= int64(n) + return n, r.c.readErr + } + + if r.c.readFinal { + r.c.readSeq++ + return 0, io.EOF + } + + frameType, err := r.c.advanceFrame() + switch { + case err != nil: + r.c.readErr = hideTempErr(err) + case frameType == TextMessage || frameType == BinaryMessage: + r.c.readErr = errors.New("websocket: internal error, unexpected text or binary in Reader") + } + } + + err := r.c.readErr + if err == io.EOF && r.seq == r.c.readSeq { + err = errUnexpectedEOF + } + return 0, err +} + +// ReadMessage is a helper method for getting a reader using NextReader and +// reading from that reader to a buffer. +func (c *Conn) ReadMessage() (messageType int, p []byte, err error) { + var r io.Reader + messageType, r, err = c.NextReader() + if err != nil { + return messageType, nil, err + } + p, err = ioutil.ReadAll(r) + return messageType, p, err +} + +// SetReadDeadline sets the read deadline on the underlying network connection. +// After a read has timed out, the websocket connection state is corrupt and +// all future reads will return an error. A zero value for t means reads will +// not time out. +func (c *Conn) SetReadDeadline(t time.Time) error { + return c.conn.SetReadDeadline(t) +} + +// SetReadLimit sets the maximum size for a message read from the peer. If a +// message exceeds the limit, the connection sends a close frame to the peer +// and returns ErrReadLimit to the application. +func (c *Conn) SetReadLimit(limit int64) { + c.readLimit = limit +} + +// SetPingHandler sets the handler for ping messages received from the peer. +// The default ping handler sends a pong to the peer. +func (c *Conn) SetPingHandler(h func(string) error) { + if h == nil { + h = func(message string) error { + c.WriteControl(PongMessage, []byte(message), time.Now().Add(writeWait)) + return nil + } + } + c.handlePing = h +} + +// SetPongHandler sets the handler for pong messages received from the peer. +// The default pong handler does nothing. +func (c *Conn) SetPongHandler(h func(string) error) { + if h == nil { + h = func(string) error { return nil } + } + c.handlePong = h +} + +// UnderlyingConn returns the internal net.Conn. This can be used to further +// modifications to connection specific flags. +func (c *Conn) UnderlyingConn() net.Conn { + return c.conn +} + +// FormatCloseMessage formats closeCode and text as a WebSocket close message. +func FormatCloseMessage(closeCode int, text string) []byte { + buf := make([]byte, 2+len(text)) + binary.BigEndian.PutUint16(buf, uint16(closeCode)) + copy(buf[2:], text) + return buf +} diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/conn_test.go b/server/Godeps/_workspace/src/github.com/gorilla/websocket/conn_test.go new file mode 100644 index 0000000..1f1197e --- /dev/null +++ b/server/Godeps/_workspace/src/github.com/gorilla/websocket/conn_test.go @@ -0,0 +1,238 @@ +// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package websocket + +import ( + "bytes" + "fmt" + "io" + "io/ioutil" + "net" + "testing" + "testing/iotest" + "time" +) + +var _ net.Error = errWriteTimeout + +type fakeNetConn struct { + io.Reader + io.Writer +} + +func (c fakeNetConn) Close() error { return nil } +func (c fakeNetConn) LocalAddr() net.Addr { return nil } +func (c fakeNetConn) RemoteAddr() net.Addr { return nil } +func (c fakeNetConn) SetDeadline(t time.Time) error { return nil } +func (c fakeNetConn) SetReadDeadline(t time.Time) error { return nil } +func (c fakeNetConn) SetWriteDeadline(t time.Time) error { return nil } + +func TestFraming(t *testing.T) { + frameSizes := []int{0, 1, 2, 124, 125, 126, 127, 128, 129, 65534, 65535, 65536, 65537} + var readChunkers = []struct { + name string + f func(io.Reader) io.Reader + }{ + {"half", iotest.HalfReader}, + {"one", iotest.OneByteReader}, + {"asis", func(r io.Reader) io.Reader { return r }}, + } + + writeBuf := make([]byte, 65537) + for i := range writeBuf { + writeBuf[i] = byte(i) + } + + for _, isServer := range []bool{true, false} { + for _, chunker := range readChunkers { + + var connBuf bytes.Buffer + wc := newConn(fakeNetConn{Reader: nil, Writer: &connBuf}, isServer, 1024, 1024) + rc := newConn(fakeNetConn{Reader: chunker.f(&connBuf), Writer: nil}, !isServer, 1024, 1024) + + for _, n := range frameSizes { + for _, iocopy := range []bool{true, false} { + name := fmt.Sprintf("s:%v, r:%s, n:%d c:%v", isServer, chunker.name, n, iocopy) + + w, err := wc.NextWriter(TextMessage) + if err != nil { + t.Errorf("%s: wc.NextWriter() returned %v", name, err) + continue + } + var nn int + if iocopy { + var n64 int64 + n64, err = io.Copy(w, bytes.NewReader(writeBuf[:n])) + nn = int(n64) + } else { + nn, err = w.Write(writeBuf[:n]) + } + if err != nil || nn != n { + t.Errorf("%s: w.Write(writeBuf[:n]) returned %d, %v", name, nn, err) + continue + } + err = w.Close() + if err != nil { + t.Errorf("%s: w.Close() returned %v", name, err) + continue + } + + opCode, r, err := rc.NextReader() + if err != nil || opCode != TextMessage { + t.Errorf("%s: NextReader() returned %d, r, %v", name, opCode, err) + continue + } + rbuf, err := ioutil.ReadAll(r) + if err != nil { + t.Errorf("%s: ReadFull() returned rbuf, %v", name, err) + continue + } + + if len(rbuf) != n { + t.Errorf("%s: len(rbuf) is %d, want %d", name, len(rbuf), n) + continue + } + + for i, b := range rbuf { + if byte(i) != b { + t.Errorf("%s: bad byte at offset %d", name, i) + break + } + } + } + } + } + } +} + +func TestControl(t *testing.T) { + const message = "this is a ping/pong messsage" + for _, isServer := range []bool{true, false} { + for _, isWriteControl := range []bool{true, false} { + name := fmt.Sprintf("s:%v, wc:%v", isServer, isWriteControl) + var connBuf bytes.Buffer + wc := newConn(fakeNetConn{Reader: nil, Writer: &connBuf}, isServer, 1024, 1024) + rc := newConn(fakeNetConn{Reader: &connBuf, Writer: nil}, !isServer, 1024, 1024) + if isWriteControl { + wc.WriteControl(PongMessage, []byte(message), time.Now().Add(time.Second)) + } else { + w, err := wc.NextWriter(PongMessage) + if err != nil { + t.Errorf("%s: wc.NextWriter() returned %v", name, err) + continue + } + if _, err := w.Write([]byte(message)); err != nil { + t.Errorf("%s: w.Write() returned %v", name, err) + continue + } + if err := w.Close(); err != nil { + t.Errorf("%s: w.Close() returned %v", name, err) + continue + } + var actualMessage string + rc.SetPongHandler(func(s string) error { actualMessage = s; return nil }) + rc.NextReader() + if actualMessage != message { + t.Errorf("%s: pong=%q, want %q", name, actualMessage, message) + continue + } + } + } + } +} + +func TestCloseBeforeFinalFrame(t *testing.T) { + const bufSize = 512 + + var b1, b2 bytes.Buffer + wc := newConn(fakeNetConn{Reader: nil, Writer: &b1}, false, 1024, bufSize) + rc := newConn(fakeNetConn{Reader: &b1, Writer: &b2}, true, 1024, 1024) + + w, _ := wc.NextWriter(BinaryMessage) + w.Write(make([]byte, bufSize+bufSize/2)) + wc.WriteControl(CloseMessage, FormatCloseMessage(CloseNormalClosure, ""), time.Now().Add(10*time.Second)) + w.Close() + + op, r, err := rc.NextReader() + if op != BinaryMessage || err != nil { + t.Fatalf("NextReader() returned %d, %v", op, err) + } + _, err = io.Copy(ioutil.Discard, r) + if err != errUnexpectedEOF { + t.Fatalf("io.Copy() returned %v, want %v", err, errUnexpectedEOF) + } + _, _, err = rc.NextReader() + if err != io.EOF { + t.Fatalf("NextReader() returned %v, want %v", err, io.EOF) + } +} + +func TestEOFBeforeFinalFrame(t *testing.T) { + const bufSize = 512 + + var b1, b2 bytes.Buffer + wc := newConn(fakeNetConn{Reader: nil, Writer: &b1}, false, 1024, bufSize) + rc := newConn(fakeNetConn{Reader: &b1, Writer: &b2}, true, 1024, 1024) + + w, _ := wc.NextWriter(BinaryMessage) + w.Write(make([]byte, bufSize+bufSize/2)) + + op, r, err := rc.NextReader() + if op != BinaryMessage || err != nil { + t.Fatalf("NextReader() returned %d, %v", op, err) + } + _, err = io.Copy(ioutil.Discard, r) + if err != errUnexpectedEOF { + t.Fatalf("io.Copy() returned %v, want %v", err, errUnexpectedEOF) + } + _, _, err = rc.NextReader() + if err != errUnexpectedEOF { + t.Fatalf("NextReader() returned %v, want %v", err, errUnexpectedEOF) + } +} + +func TestReadLimit(t *testing.T) { + + const readLimit = 512 + message := make([]byte, readLimit+1) + + var b1, b2 bytes.Buffer + wc := newConn(fakeNetConn{Reader: nil, Writer: &b1}, false, 1024, readLimit-2) + rc := newConn(fakeNetConn{Reader: &b1, Writer: &b2}, true, 1024, 1024) + rc.SetReadLimit(readLimit) + + // Send message at the limit with interleaved pong. + w, _ := wc.NextWriter(BinaryMessage) + w.Write(message[:readLimit-1]) + wc.WriteControl(PongMessage, []byte("this is a pong"), time.Now().Add(10*time.Second)) + w.Write(message[:1]) + w.Close() + + // Send message larger than the limit. + wc.WriteMessage(BinaryMessage, message[:readLimit+1]) + + op, _, err := rc.NextReader() + if op != BinaryMessage || err != nil { + t.Fatalf("1: NextReader() returned %d, %v", op, err) + } + op, r, err := rc.NextReader() + if op != BinaryMessage || err != nil { + t.Fatalf("2: NextReader() returned %d, %v", op, err) + } + _, err = io.Copy(ioutil.Discard, r) + if err != ErrReadLimit { + t.Fatalf("io.Copy() returned %v", err) + } +} + +func TestUnderlyingConn(t *testing.T) { + var b1, b2 bytes.Buffer + fc := fakeNetConn{Reader: &b1, Writer: &b2} + c := newConn(fc, true, 1024, 1024) + ul := c.UnderlyingConn() + if ul != fc { + t.Fatalf("Underlying conn is not what it should be.") + } +} diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/doc.go b/server/Godeps/_workspace/src/github.com/gorilla/websocket/doc.go new file mode 100644 index 0000000..f52925d --- /dev/null +++ b/server/Godeps/_workspace/src/github.com/gorilla/websocket/doc.go @@ -0,0 +1,148 @@ +// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Package websocket implements the WebSocket protocol defined in RFC 6455. +// +// Overview +// +// The Conn type represents a WebSocket connection. A server application uses +// the Upgrade function from an Upgrader object with a HTTP request handler +// to get a pointer to a Conn: +// +// var upgrader = websocket.Upgrader{ +// ReadBufferSize: 1024, +// WriteBufferSize: 1024, +// } +// +// func handler(w http.ResponseWriter, r *http.Request) { +// conn, err := upgrader.Upgrade(w, r, nil) +// if err != nil { +// log.Println(err) +// return +// } +// ... Use conn to send and receive messages. +// } +// +// Call the connection's WriteMessage and ReadMessage methods to send and +// receive messages as a slice of bytes. This snippet of code shows how to echo +// messages using these methods: +// +// for { +// messageType, p, err := conn.ReadMessage() +// if err != nil { +// return +// } +// if err = conn.WriteMessage(messageType, p); err != nil { +// return err +// } +// } +// +// In above snippet of code, p is a []byte and messageType is an int with value +// websocket.BinaryMessage or websocket.TextMessage. +// +// An application can also send and receive messages using the io.WriteCloser +// and io.Reader interfaces. To send a message, call the connection NextWriter +// method to get an io.WriteCloser, write the message to the writer and close +// the writer when done. To receive a message, call the connection NextReader +// method to get an io.Reader and read until io.EOF is returned. This snippet +// snippet shows how to echo messages using the NextWriter and NextReader +// methods: +// +// for { +// messageType, r, err := conn.NextReader() +// if err != nil { +// return +// } +// w, err := conn.NextWriter(messageType) +// if err != nil { +// return err +// } +// if _, err := io.Copy(w, r); err != nil { +// return err +// } +// if err := w.Close(); err != nil { +// return err +// } +// } +// +// Data Messages +// +// The WebSocket protocol distinguishes between text and binary data messages. +// Text messages are interpreted as UTF-8 encoded text. The interpretation of +// binary messages is left to the application. +// +// This package uses the TextMessage and BinaryMessage integer constants to +// identify the two data message types. The ReadMessage and NextReader methods +// return the type of the received message. The messageType argument to the +// WriteMessage and NextWriter methods specifies the type of a sent message. +// +// It is the application's responsibility to ensure that text messages are +// valid UTF-8 encoded text. +// +// Control Messages +// +// The WebSocket protocol defines three types of control messages: close, ping +// and pong. Call the connection WriteControl, WriteMessage or NextWriter +// methods to send a control message to the peer. +// +// Connections handle received ping and pong messages by invoking a callback +// function set with SetPingHandler and SetPongHandler methods. These callback +// functions can be invoked from the ReadMessage method, the NextReader method +// or from a call to the data message reader returned from NextReader. +// +// Connections handle received close messages by returning an error from the +// ReadMessage method, the NextReader method or from a call to the data message +// reader returned from NextReader. +// +// Concurrency +// +// Connections do not support concurrent calls to the write methods +// (NextWriter, SetWriteDeadline, WriteMessage) or concurrent calls to the read +// methods methods (NextReader, SetReadDeadline, ReadMessage). Connections do +// support a concurrent reader and writer. +// +// The Close and WriteControl methods can be called concurrently with all other +// methods. +// +// Read is Required +// +// The application must read the connection to process ping and close messages +// sent from the peer. If the application is not otherwise interested in +// messages from the peer, then the application should start a goroutine to read +// and discard messages from the peer. A simple example is: +// +// func readLoop(c *websocket.Conn) { +// for { +// if _, _, err := c.NextReader(); err != nil { +// c.Close() +// break +// } +// } +// } +// +// Origin Considerations +// +// Web browsers allow Javascript applications to open a WebSocket connection to +// any host. It's up to the server to enforce an origin policy using the Origin +// request header sent by the browser. +// +// The Upgrader calls the function specified in the CheckOrigin field to check +// the origin. If the CheckOrigin function returns false, then the Upgrade +// method fails the WebSocket handshake with HTTP status 403. +// +// If the CheckOrigin field is nil, then the Upgrader uses a safe default: fail +// the handshake if the Origin request header is present and not equal to the +// Host request header. +// +// An application can allow connections from any origin by specifying a +// function that always returns true: +// +// var upgrader = websocket.Upgrader{ +// CheckOrigin: func(r *http.Request) bool { return true }, +// } +// +// The deprecated Upgrade function does not enforce an origin policy. It's the +// application's responsibility to check the Origin header before calling +// Upgrade. +package websocket diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/autobahn/README.md b/server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/autobahn/README.md new file mode 100644 index 0000000..075ac15 --- /dev/null +++ b/server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/autobahn/README.md @@ -0,0 +1,13 @@ +# Test Server + +This package contains a server for the [Autobahn WebSockets Test Suite](http://autobahn.ws/testsuite). + +To test the server, run + + go run server.go + +and start the client test driver + + wstest -m fuzzingclient -s fuzzingclient.json + +When the client completes, it writes a report to reports/clients/index.html. diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/autobahn/fuzzingclient.json b/server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/autobahn/fuzzingclient.json new file mode 100644 index 0000000..27d5a5b --- /dev/null +++ b/server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/autobahn/fuzzingclient.json @@ -0,0 +1,14 @@ + +{ + "options": {"failByDrop": false}, + "outdir": "./reports/clients", + "servers": [ + {"agent": "ReadAllWriteMessage", "url": "ws://localhost:9000/m", "options": {"version": 18}}, + {"agent": "ReadAllWrite", "url": "ws://localhost:9000/r", "options": {"version": 18}}, + {"agent": "CopyFull", "url": "ws://localhost:9000/f", "options": {"version": 18}}, + {"agent": "CopyWriterOnly", "url": "ws://localhost:9000/c", "options": {"version": 18}} + ], + "cases": ["*"], + "exclude-cases": [], + "exclude-agent-cases": {} +} diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/autobahn/server.go b/server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/autobahn/server.go new file mode 100644 index 0000000..d96ac84 --- /dev/null +++ b/server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/autobahn/server.go @@ -0,0 +1,246 @@ +// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Command server is a test server for the Autobahn WebSockets Test Suite. +package main + +import ( + "errors" + "flag" + "github.com/gorilla/websocket" + "io" + "log" + "net/http" + "time" + "unicode/utf8" +) + +var upgrader = websocket.Upgrader{ + ReadBufferSize: 4096, + WriteBufferSize: 4096, + CheckOrigin: func(r *http.Request) bool { + return true + }, +} + +// echoCopy echoes messages from the client using io.Copy. +func echoCopy(w http.ResponseWriter, r *http.Request, writerOnly bool) { + conn, err := upgrader.Upgrade(w, r, nil) + if err != nil { + log.Println("Upgrade:", err) + return + } + defer conn.Close() + for { + mt, r, err := conn.NextReader() + if err != nil { + if err != io.EOF { + log.Println("NextReader:", err) + } + return + } + if mt == websocket.TextMessage { + r = &validator{r: r} + } + w, err := conn.NextWriter(mt) + if err != nil { + log.Println("NextWriter:", err) + return + } + if mt == websocket.TextMessage { + r = &validator{r: r} + } + if writerOnly { + _, err = io.Copy(struct{ io.Writer }{w}, r) + } else { + _, err = io.Copy(w, r) + } + if err != nil { + if err == errInvalidUTF8 { + conn.WriteControl(websocket.CloseMessage, + websocket.FormatCloseMessage(websocket.CloseInvalidFramePayloadData, ""), + time.Time{}) + } + log.Println("Copy:", err) + return + } + err = w.Close() + if err != nil { + log.Println("Close:", err) + return + } + } +} + +func echoCopyWriterOnly(w http.ResponseWriter, r *http.Request) { + echoCopy(w, r, true) +} + +func echoCopyFull(w http.ResponseWriter, r *http.Request) { + echoCopy(w, r, false) +} + +// echoReadAll echoes messages from the client by reading the entire message +// with ioutil.ReadAll. +func echoReadAll(w http.ResponseWriter, r *http.Request, writeMessage bool) { + conn, err := upgrader.Upgrade(w, r, nil) + if err != nil { + log.Println("Upgrade:", err) + return + } + defer conn.Close() + for { + mt, b, err := conn.ReadMessage() + if err != nil { + if err != io.EOF { + log.Println("NextReader:", err) + } + return + } + if mt == websocket.TextMessage { + if !utf8.Valid(b) { + conn.WriteControl(websocket.CloseMessage, + websocket.FormatCloseMessage(websocket.CloseInvalidFramePayloadData, ""), + time.Time{}) + log.Println("ReadAll: invalid utf8") + } + } + if writeMessage { + err = conn.WriteMessage(mt, b) + if err != nil { + log.Println("WriteMessage:", err) + } + } else { + w, err := conn.NextWriter(mt) + if err != nil { + log.Println("NextWriter:", err) + return + } + if _, err := w.Write(b); err != nil { + log.Println("Writer:", err) + return + } + if err := w.Close(); err != nil { + log.Println("Close:", err) + return + } + } + } +} + +func echoReadAllWriter(w http.ResponseWriter, r *http.Request) { + echoReadAll(w, r, false) +} + +func echoReadAllWriteMessage(w http.ResponseWriter, r *http.Request) { + echoReadAll(w, r, true) +} + +func serveHome(w http.ResponseWriter, r *http.Request) { + if r.URL.Path != "/" { + http.Error(w, "Not found.", 404) + return + } + if r.Method != "GET" { + http.Error(w, "Method not allowed", 405) + return + } + w.Header().Set("Content-Type", "text/html; charset=utf-8") + io.WriteString(w, "Echo Server") +} + +var addr = flag.String("addr", ":9000", "http service address") + +func main() { + flag.Parse() + http.HandleFunc("/", serveHome) + http.HandleFunc("/c", echoCopyWriterOnly) + http.HandleFunc("/f", echoCopyFull) + http.HandleFunc("/r", echoReadAllWriter) + http.HandleFunc("/m", echoReadAllWriteMessage) + err := http.ListenAndServe(*addr, nil) + if err != nil { + log.Fatal("ListenAndServe: ", err) + } +} + +type validator struct { + state int + x rune + r io.Reader +} + +var errInvalidUTF8 = errors.New("invalid utf8") + +func (r *validator) Read(p []byte) (int, error) { + n, err := r.r.Read(p) + state := r.state + x := r.x + for _, b := range p[:n] { + state, x = decode(state, x, b) + if state == utf8Reject { + break + } + } + r.state = state + r.x = x + if state == utf8Reject || (err == io.EOF && state != utf8Accept) { + return n, errInvalidUTF8 + } + return n, err +} + +// UTF-8 decoder from http://bjoern.hoehrmann.de/utf-8/decoder/dfa/ +// +// Copyright (c) 2008-2009 Bjoern Hoehrmann +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to +// deal in the Software without restriction, including without limitation the +// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or +// sell copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +// IN THE SOFTWARE. +var utf8d = [...]byte{ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 00..1f + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20..3f + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40..5f + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60..7f + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, // 80..9f + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, // a0..bf + 8, 8, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // c0..df + 0xa, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x3, 0x3, // e0..ef + 0xb, 0x6, 0x6, 0x6, 0x5, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, // f0..ff + 0x0, 0x1, 0x2, 0x3, 0x5, 0x8, 0x7, 0x1, 0x1, 0x1, 0x4, 0x6, 0x1, 0x1, 0x1, 0x1, // s0..s0 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 1, 1, 1, 1, 0, 1, 0, 1, 1, 1, 1, 1, 1, // s1..s2 + 1, 2, 1, 1, 1, 1, 1, 2, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, // s3..s4 + 1, 2, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, // s5..s6 + 1, 3, 1, 1, 1, 1, 1, 3, 1, 3, 1, 1, 1, 1, 1, 1, 1, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // s7..s8 +} + +const ( + utf8Accept = 0 + utf8Reject = 1 +) + +func decode(state int, x rune, b byte) (int, rune) { + t := utf8d[b] + if state != utf8Accept { + x = rune(b&0x3f) | (x << 6) + } else { + x = rune((0xff >> t) & b) + } + state = int(utf8d[256+state*16+int(t)]) + return state, x +} diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/README.md b/server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/README.md new file mode 100644 index 0000000..08fc3e6 --- /dev/null +++ b/server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/README.md @@ -0,0 +1,19 @@ +# Chat Example + +This application shows how to use use the +[websocket](https://github.com/gorilla/websocket) package and +[jQuery](http://jquery.com) to implement a simple web chat application. + +## Running the example + +The example requires a working Go development environment. The [Getting +Started](http://golang.org/doc/install) page describes how to install the +development environment. + +Once you have Go up and running, you can download, build and run the example +using the following commands. + + $ go get github.com/gorilla/websocket + $ cd `go list -f '{{.Dir}}' github.com/gorilla/websocket/examples/chat` + $ go run *.go + diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/conn.go b/server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/conn.go new file mode 100644 index 0000000..7cc0496 --- /dev/null +++ b/server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/conn.go @@ -0,0 +1,106 @@ +// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "github.com/gorilla/websocket" + "log" + "net/http" + "time" +) + +const ( + // Time allowed to write a message to the peer. + writeWait = 10 * time.Second + + // Time allowed to read the next pong message from the peer. + pongWait = 60 * time.Second + + // Send pings to peer with this period. Must be less than pongWait. + pingPeriod = (pongWait * 9) / 10 + + // Maximum message size allowed from peer. + maxMessageSize = 512 +) + +var upgrader = websocket.Upgrader{ + ReadBufferSize: 1024, + WriteBufferSize: 1024, +} + +// connection is an middleman between the websocket connection and the hub. +type connection struct { + // The websocket connection. + ws *websocket.Conn + + // Buffered channel of outbound messages. + send chan []byte +} + +// readPump pumps messages from the websocket connection to the hub. +func (c *connection) readPump() { + defer func() { + h.unregister <- c + c.ws.Close() + }() + c.ws.SetReadLimit(maxMessageSize) + c.ws.SetReadDeadline(time.Now().Add(pongWait)) + c.ws.SetPongHandler(func(string) error { c.ws.SetReadDeadline(time.Now().Add(pongWait)); return nil }) + for { + _, message, err := c.ws.ReadMessage() + if err != nil { + break + } + h.broadcast <- message + } +} + +// write writes a message with the given message type and payload. +func (c *connection) write(mt int, payload []byte) error { + c.ws.SetWriteDeadline(time.Now().Add(writeWait)) + return c.ws.WriteMessage(mt, payload) +} + +// writePump pumps messages from the hub to the websocket connection. +func (c *connection) writePump() { + ticker := time.NewTicker(pingPeriod) + defer func() { + ticker.Stop() + c.ws.Close() + }() + for { + select { + case message, ok := <-c.send: + if !ok { + c.write(websocket.CloseMessage, []byte{}) + return + } + if err := c.write(websocket.TextMessage, message); err != nil { + return + } + case <-ticker.C: + if err := c.write(websocket.PingMessage, []byte{}); err != nil { + return + } + } + } +} + +// serverWs handles websocket requests from the peer. +func serveWs(w http.ResponseWriter, r *http.Request) { + if r.Method != "GET" { + http.Error(w, "Method not allowed", 405) + return + } + ws, err := upgrader.Upgrade(w, r, nil) + if err != nil { + log.Println(err) + return + } + c := &connection{send: make(chan []byte, 256), ws: ws} + h.register <- c + go c.writePump() + c.readPump() +} diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/home.html b/server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/home.html new file mode 100644 index 0000000..2959922 --- /dev/null +++ b/server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/home.html @@ -0,0 +1,92 @@ + + + +Chat Example + + + + + +
+
+ + +
+ + diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/hub.go b/server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/hub.go new file mode 100644 index 0000000..449ba75 --- /dev/null +++ b/server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/hub.go @@ -0,0 +1,51 @@ +// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +// hub maintains the set of active connections and broadcasts messages to the +// connections. +type hub struct { + // Registered connections. + connections map[*connection]bool + + // Inbound messages from the connections. + broadcast chan []byte + + // Register requests from the connections. + register chan *connection + + // Unregister requests from connections. + unregister chan *connection +} + +var h = hub{ + broadcast: make(chan []byte), + register: make(chan *connection), + unregister: make(chan *connection), + connections: make(map[*connection]bool), +} + +func (h *hub) run() { + for { + select { + case c := <-h.register: + h.connections[c] = true + case c := <-h.unregister: + if _, ok := h.connections[c]; ok { + delete(h.connections, c) + close(c.send) + } + case m := <-h.broadcast: + for c := range h.connections { + select { + case c.send <- m: + default: + close(c.send) + delete(h.connections, c) + } + } + } + } +} diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/main.go b/server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/main.go new file mode 100644 index 0000000..3c4448d --- /dev/null +++ b/server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/main.go @@ -0,0 +1,39 @@ +// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "flag" + "log" + "net/http" + "text/template" +) + +var addr = flag.String("addr", ":8080", "http service address") +var homeTempl = template.Must(template.ParseFiles("home.html")) + +func serveHome(w http.ResponseWriter, r *http.Request) { + if r.URL.Path != "/" { + http.Error(w, "Not found", 404) + return + } + if r.Method != "GET" { + http.Error(w, "Method not allowed", 405) + return + } + w.Header().Set("Content-Type", "text/html; charset=utf-8") + homeTempl.Execute(w, r.Host) +} + +func main() { + flag.Parse() + go h.run() + http.HandleFunc("/", serveHome) + http.HandleFunc("/ws", serveWs) + err := http.ListenAndServe(*addr, nil) + if err != nil { + log.Fatal("ListenAndServe: ", err) + } +} diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/filewatch/README.md b/server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/filewatch/README.md new file mode 100644 index 0000000..ca4931f --- /dev/null +++ b/server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/filewatch/README.md @@ -0,0 +1,9 @@ +# File Watch example. + +This example sends a file to the browser client for display whenever the file is modified. + + $ go get github.com/gorilla/websocket + $ cd `go list -f '{{.Dir}}' github.com/gorilla/websocket/examples/filewatch` + $ go run main.go + # Open http://localhost:8080/ . + # Modify the file to see it update in the browser. diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/filewatch/main.go b/server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/filewatch/main.go new file mode 100644 index 0000000..a2c7b85 --- /dev/null +++ b/server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/filewatch/main.go @@ -0,0 +1,193 @@ +// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package main + +import ( + "flag" + "io/ioutil" + "log" + "net/http" + "os" + "strconv" + "text/template" + "time" + + "github.com/gorilla/websocket" +) + +const ( + // Time allowed to write the file to the client. + writeWait = 10 * time.Second + + // Time allowed to read the next pong message from the client. + pongWait = 60 * time.Second + + // Send pings to client with this period. Must be less than pongWait. + pingPeriod = (pongWait * 9) / 10 + + // Poll file for changes with this period. + filePeriod = 10 * time.Second +) + +var ( + addr = flag.String("addr", ":8080", "http service address") + homeTempl = template.Must(template.New("").Parse(homeHTML)) + filename string + upgrader = websocket.Upgrader{ + ReadBufferSize: 1024, + WriteBufferSize: 1024, + } +) + +func readFileIfModified(lastMod time.Time) ([]byte, time.Time, error) { + fi, err := os.Stat(filename) + if err != nil { + return nil, lastMod, err + } + if !fi.ModTime().After(lastMod) { + return nil, lastMod, nil + } + p, err := ioutil.ReadFile(filename) + if err != nil { + return nil, fi.ModTime(), err + } + return p, fi.ModTime(), nil +} + +func reader(ws *websocket.Conn) { + defer ws.Close() + ws.SetReadLimit(512) + ws.SetReadDeadline(time.Now().Add(pongWait)) + ws.SetPongHandler(func(string) error { ws.SetReadDeadline(time.Now().Add(pongWait)); return nil }) + for { + _, _, err := ws.ReadMessage() + if err != nil { + break + } + } +} + +func writer(ws *websocket.Conn, lastMod time.Time) { + lastError := "" + pingTicker := time.NewTicker(pingPeriod) + fileTicker := time.NewTicker(filePeriod) + defer func() { + pingTicker.Stop() + fileTicker.Stop() + ws.Close() + }() + for { + select { + case <-fileTicker.C: + var p []byte + var err error + + p, lastMod, err = readFileIfModified(lastMod) + + if err != nil { + if s := err.Error(); s != lastError { + lastError = s + p = []byte(lastError) + } + } else { + lastError = "" + } + + if p != nil { + ws.SetWriteDeadline(time.Now().Add(writeWait)) + if err := ws.WriteMessage(websocket.TextMessage, p); err != nil { + return + } + } + case <-pingTicker.C: + ws.SetWriteDeadline(time.Now().Add(writeWait)) + if err := ws.WriteMessage(websocket.PingMessage, []byte{}); err != nil { + return + } + } + } +} + +func serveWs(w http.ResponseWriter, r *http.Request) { + ws, err := upgrader.Upgrade(w, r, nil) + if err != nil { + if _, ok := err.(websocket.HandshakeError); !ok { + log.Println(err) + } + return + } + + var lastMod time.Time + if n, err := strconv.ParseInt(r.FormValue("lastMod"), 16, 64); err != nil { + lastMod = time.Unix(0, n) + } + + go writer(ws, lastMod) + reader(ws) +} + +func serveHome(w http.ResponseWriter, r *http.Request) { + if r.URL.Path != "/" { + http.Error(w, "Not found", 404) + return + } + if r.Method != "GET" { + http.Error(w, "Method not allowed", 405) + return + } + w.Header().Set("Content-Type", "text/html; charset=utf-8") + p, lastMod, err := readFileIfModified(time.Time{}) + if err != nil { + p = []byte(err.Error()) + lastMod = time.Unix(0, 0) + } + var v = struct { + Host string + Data string + LastMod string + }{ + r.Host, + string(p), + strconv.FormatInt(lastMod.UnixNano(), 16), + } + homeTempl.Execute(w, &v) +} + +func main() { + flag.Parse() + if flag.NArg() != 1 { + log.Fatal("filename not specified") + } + filename = flag.Args()[0] + http.HandleFunc("/", serveHome) + http.HandleFunc("/ws", serveWs) + if err := http.ListenAndServe(*addr, nil); err != nil { + log.Fatal(err) + } +} + +const homeHTML = ` + + + WebSocket Example + + +
{{.Data}}
+ + + +` diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/json.go b/server/Godeps/_workspace/src/github.com/gorilla/websocket/json.go new file mode 100644 index 0000000..18e62f2 --- /dev/null +++ b/server/Godeps/_workspace/src/github.com/gorilla/websocket/json.go @@ -0,0 +1,57 @@ +// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package websocket + +import ( + "encoding/json" + "io" +) + +// WriteJSON is deprecated, use c.WriteJSON instead. +func WriteJSON(c *Conn, v interface{}) error { + return c.WriteJSON(v) +} + +// WriteJSON writes the JSON encoding of v to the connection. +// +// See the documentation for encoding/json Marshal for details about the +// conversion of Go values to JSON. +func (c *Conn) WriteJSON(v interface{}) error { + w, err := c.NextWriter(TextMessage) + if err != nil { + return err + } + err1 := json.NewEncoder(w).Encode(v) + err2 := w.Close() + if err1 != nil { + return err1 + } + return err2 +} + +// ReadJSON is deprecated, use c.ReadJSON instead. +func ReadJSON(c *Conn, v interface{}) error { + return c.ReadJSON(v) +} + +// ReadJSON reads the next JSON-encoded message from the connection and stores +// it in the value pointed to by v. +// +// See the documentation for the encoding/json Unmarshal function for details +// about the conversion of JSON to a Go value. +func (c *Conn) ReadJSON(v interface{}) error { + _, r, err := c.NextReader() + if err != nil { + return err + } + err = json.NewDecoder(r).Decode(v) + if err == io.EOF { + // Decode returns io.EOF when the message is empty or all whitespace. + // Convert to io.ErrUnexpectedEOF so that application can distinguish + // between an error reading the JSON value and the connection closing. + err = io.ErrUnexpectedEOF + } + return err +} diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/json_test.go b/server/Godeps/_workspace/src/github.com/gorilla/websocket/json_test.go new file mode 100644 index 0000000..1b7a5ec --- /dev/null +++ b/server/Godeps/_workspace/src/github.com/gorilla/websocket/json_test.go @@ -0,0 +1,119 @@ +// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package websocket + +import ( + "bytes" + "encoding/json" + "io" + "reflect" + "testing" +) + +func TestJSON(t *testing.T) { + var buf bytes.Buffer + c := fakeNetConn{&buf, &buf} + wc := newConn(c, true, 1024, 1024) + rc := newConn(c, false, 1024, 1024) + + var actual, expect struct { + A int + B string + } + expect.A = 1 + expect.B = "hello" + + if err := wc.WriteJSON(&expect); err != nil { + t.Fatal("write", err) + } + + if err := rc.ReadJSON(&actual); err != nil { + t.Fatal("read", err) + } + + if !reflect.DeepEqual(&actual, &expect) { + t.Fatal("equal", actual, expect) + } +} + +func TestPartialJsonRead(t *testing.T) { + var buf bytes.Buffer + c := fakeNetConn{&buf, &buf} + wc := newConn(c, true, 1024, 1024) + rc := newConn(c, false, 1024, 1024) + + var v struct { + A int + B string + } + v.A = 1 + v.B = "hello" + + messageCount := 0 + + // Partial JSON values. + + data, err := json.Marshal(v) + if err != nil { + t.Fatal(err) + } + for i := len(data) - 1; i >= 0; i-- { + if err := wc.WriteMessage(TextMessage, data[:i]); err != nil { + t.Fatal(err) + } + messageCount++ + } + + // Whitespace. + + if err := wc.WriteMessage(TextMessage, []byte(" ")); err != nil { + t.Fatal(err) + } + messageCount++ + + // Close. + + if err := wc.WriteMessage(CloseMessage, FormatCloseMessage(CloseNormalClosure, "")); err != nil { + t.Fatal(err) + } + + for i := 0; i < messageCount; i++ { + err := rc.ReadJSON(&v) + if err != io.ErrUnexpectedEOF { + t.Error("read", i, err) + } + } + + err = rc.ReadJSON(&v) + if err != io.EOF { + t.Error("final", err) + } +} + +func TestDeprecatedJSON(t *testing.T) { + var buf bytes.Buffer + c := fakeNetConn{&buf, &buf} + wc := newConn(c, true, 1024, 1024) + rc := newConn(c, false, 1024, 1024) + + var actual, expect struct { + A int + B string + } + expect.A = 1 + expect.B = "hello" + + if err := WriteJSON(wc, &expect); err != nil { + t.Fatal("write", err) + } + + if err := ReadJSON(rc, &actual); err != nil { + t.Fatal("read", err) + } + + if !reflect.DeepEqual(&actual, &expect) { + t.Fatal("equal", actual, expect) + } +} diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/server.go b/server/Godeps/_workspace/src/github.com/gorilla/websocket/server.go new file mode 100644 index 0000000..e56a004 --- /dev/null +++ b/server/Godeps/_workspace/src/github.com/gorilla/websocket/server.go @@ -0,0 +1,247 @@ +// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package websocket + +import ( + "bufio" + "errors" + "net" + "net/http" + "net/url" + "strings" + "time" +) + +// HandshakeError describes an error with the handshake from the peer. +type HandshakeError struct { + message string +} + +func (e HandshakeError) Error() string { return e.message } + +// Upgrader specifies parameters for upgrading an HTTP connection to a +// WebSocket connection. +type Upgrader struct { + // HandshakeTimeout specifies the duration for the handshake to complete. + HandshakeTimeout time.Duration + + // ReadBufferSize and WriteBufferSize specify I/O buffer sizes. If a buffer + // size is zero, then a default value of 4096 is used. The I/O buffer sizes + // do not limit the size of the messages that can be sent or received. + ReadBufferSize, WriteBufferSize int + + // Subprotocols specifies the server's supported protocols in order of + // preference. If this field is set, then the Upgrade method negotiates a + // subprotocol by selecting the first match in this list with a protocol + // requested by the client. + Subprotocols []string + + // Error specifies the function for generating HTTP error responses. If Error + // is nil, then http.Error is used to generate the HTTP response. + Error func(w http.ResponseWriter, r *http.Request, status int, reason error) + + // CheckOrigin returns true if the request Origin header is acceptable. If + // CheckOrigin is nil, the host in the Origin header must not be set or + // must match the host of the request. + CheckOrigin func(r *http.Request) bool +} + +func (u *Upgrader) returnError(w http.ResponseWriter, r *http.Request, status int, reason string) (*Conn, error) { + err := HandshakeError{reason} + if u.Error != nil { + u.Error(w, r, status, err) + } else { + http.Error(w, http.StatusText(status), status) + } + return nil, err +} + +// checkSameOrigin returns true if the origin is not set or is equal to the request host. +func checkSameOrigin(r *http.Request) bool { + origin := r.Header["Origin"] + if len(origin) == 0 { + return true + } + u, err := url.Parse(origin[0]) + if err != nil { + return false + } + return u.Host == r.Host +} + +func (u *Upgrader) selectSubprotocol(r *http.Request, responseHeader http.Header) string { + if u.Subprotocols != nil { + clientProtocols := Subprotocols(r) + for _, serverProtocol := range u.Subprotocols { + for _, clientProtocol := range clientProtocols { + if clientProtocol == serverProtocol { + return clientProtocol + } + } + } + } else if responseHeader != nil { + return responseHeader.Get("Sec-Websocket-Protocol") + } + return "" +} + +// Upgrade upgrades the HTTP server connection to the WebSocket protocol. +// +// The responseHeader is included in the response to the client's upgrade +// request. Use the responseHeader to specify cookies (Set-Cookie) and the +// application negotiated subprotocol (Sec-Websocket-Protocol). +func (u *Upgrader) Upgrade(w http.ResponseWriter, r *http.Request, responseHeader http.Header) (*Conn, error) { + if values := r.Header["Sec-Websocket-Version"]; len(values) == 0 || values[0] != "13" { + return u.returnError(w, r, http.StatusBadRequest, "websocket: version != 13") + } + + if !tokenListContainsValue(r.Header, "Connection", "upgrade") { + return u.returnError(w, r, http.StatusBadRequest, "websocket: could not find connection header with token 'upgrade'") + } + + if !tokenListContainsValue(r.Header, "Upgrade", "websocket") { + return u.returnError(w, r, http.StatusBadRequest, "websocket: could not find upgrade header with token 'websocket'") + } + + checkOrigin := u.CheckOrigin + if checkOrigin == nil { + checkOrigin = checkSameOrigin + } + if !checkOrigin(r) { + return u.returnError(w, r, http.StatusForbidden, "websocket: origin not allowed") + } + + challengeKey := r.Header.Get("Sec-Websocket-Key") + if challengeKey == "" { + return u.returnError(w, r, http.StatusBadRequest, "websocket: key missing or blank") + } + + subprotocol := u.selectSubprotocol(r, responseHeader) + + var ( + netConn net.Conn + br *bufio.Reader + err error + ) + + h, ok := w.(http.Hijacker) + if !ok { + return u.returnError(w, r, http.StatusInternalServerError, "websocket: response does not implement http.Hijacker") + } + var rw *bufio.ReadWriter + netConn, rw, err = h.Hijack() + if err != nil { + return u.returnError(w, r, http.StatusInternalServerError, err.Error()) + } + br = rw.Reader + + if br.Buffered() > 0 { + netConn.Close() + return nil, errors.New("websocket: client sent data before handshake is complete") + } + + c := newConn(netConn, true, u.ReadBufferSize, u.WriteBufferSize) + c.subprotocol = subprotocol + + p := c.writeBuf[:0] + p = append(p, "HTTP/1.1 101 Switching Protocols\r\nUpgrade: websocket\r\nConnection: Upgrade\r\nSec-WebSocket-Accept: "...) + p = append(p, computeAcceptKey(challengeKey)...) + p = append(p, "\r\n"...) + if c.subprotocol != "" { + p = append(p, "Sec-Websocket-Protocol: "...) + p = append(p, c.subprotocol...) + p = append(p, "\r\n"...) + } + for k, vs := range responseHeader { + if k == "Sec-Websocket-Protocol" { + continue + } + for _, v := range vs { + p = append(p, k...) + p = append(p, ": "...) + for i := 0; i < len(v); i++ { + b := v[i] + if b <= 31 { + // prevent response splitting. + b = ' ' + } + p = append(p, b) + } + p = append(p, "\r\n"...) + } + } + p = append(p, "\r\n"...) + + // Clear deadlines set by HTTP server. + netConn.SetDeadline(time.Time{}) + + if u.HandshakeTimeout > 0 { + netConn.SetWriteDeadline(time.Now().Add(u.HandshakeTimeout)) + } + if _, err = netConn.Write(p); err != nil { + netConn.Close() + return nil, err + } + if u.HandshakeTimeout > 0 { + netConn.SetWriteDeadline(time.Time{}) + } + + return c, nil +} + +// Upgrade upgrades the HTTP server connection to the WebSocket protocol. +// +// This function is deprecated, use websocket.Upgrader instead. +// +// The application is responsible for checking the request origin before +// calling Upgrade. An example implementation of the same origin policy is: +// +// if req.Header.Get("Origin") != "http://"+req.Host { +// http.Error(w, "Origin not allowed", 403) +// return +// } +// +// If the endpoint supports subprotocols, then the application is responsible +// for negotiating the protocol used on the connection. Use the Subprotocols() +// function to get the subprotocols requested by the client. Use the +// Sec-Websocket-Protocol response header to specify the subprotocol selected +// by the application. +// +// The responseHeader is included in the response to the client's upgrade +// request. Use the responseHeader to specify cookies (Set-Cookie) and the +// negotiated subprotocol (Sec-Websocket-Protocol). +// +// The connection buffers IO to the underlying network connection. The +// readBufSize and writeBufSize parameters specify the size of the buffers to +// use. Messages can be larger than the buffers. +// +// If the request is not a valid WebSocket handshake, then Upgrade returns an +// error of type HandshakeError. Applications should handle this error by +// replying to the client with an HTTP error response. +func Upgrade(w http.ResponseWriter, r *http.Request, responseHeader http.Header, readBufSize, writeBufSize int) (*Conn, error) { + u := Upgrader{ReadBufferSize: readBufSize, WriteBufferSize: writeBufSize} + u.Error = func(w http.ResponseWriter, r *http.Request, status int, reason error) { + // don't return errors to maintain backwards compatibility + } + u.CheckOrigin = func(r *http.Request) bool { + // allow all connections by default + return true + } + return u.Upgrade(w, r, responseHeader) +} + +// Subprotocols returns the subprotocols requested by the client in the +// Sec-Websocket-Protocol header. +func Subprotocols(r *http.Request) []string { + h := strings.TrimSpace(r.Header.Get("Sec-Websocket-Protocol")) + if h == "" { + return nil + } + protocols := strings.Split(h, ",") + for i := range protocols { + protocols[i] = strings.TrimSpace(protocols[i]) + } + return protocols +} diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/server_test.go b/server/Godeps/_workspace/src/github.com/gorilla/websocket/server_test.go new file mode 100644 index 0000000..ead0776 --- /dev/null +++ b/server/Godeps/_workspace/src/github.com/gorilla/websocket/server_test.go @@ -0,0 +1,33 @@ +// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package websocket + +import ( + "net/http" + "reflect" + "testing" +) + +var subprotocolTests = []struct { + h string + protocols []string +}{ + {"", nil}, + {"foo", []string{"foo"}}, + {"foo,bar", []string{"foo", "bar"}}, + {"foo, bar", []string{"foo", "bar"}}, + {" foo, bar", []string{"foo", "bar"}}, + {" foo, bar ", []string{"foo", "bar"}}, +} + +func TestSubprotocols(t *testing.T) { + for _, st := range subprotocolTests { + r := http.Request{Header: http.Header{"Sec-Websocket-Protocol": {st.h}}} + protocols := Subprotocols(&r) + if !reflect.DeepEqual(st.protocols, protocols) { + t.Errorf("SubProtocols(%q) returned %#v, want %#v", st.h, protocols, st.protocols) + } + } +} diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/util.go b/server/Godeps/_workspace/src/github.com/gorilla/websocket/util.go new file mode 100644 index 0000000..ffdc265 --- /dev/null +++ b/server/Godeps/_workspace/src/github.com/gorilla/websocket/util.go @@ -0,0 +1,44 @@ +// Copyright 2013 The Gorilla WebSocket Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package websocket + +import ( + "crypto/rand" + "crypto/sha1" + "encoding/base64" + "io" + "net/http" + "strings" +) + +// tokenListContainsValue returns true if the 1#token header with the given +// name contains token. +func tokenListContainsValue(header http.Header, name string, value string) bool { + for _, v := range header[name] { + for _, s := range strings.Split(v, ",") { + if strings.EqualFold(value, strings.TrimSpace(s)) { + return true + } + } + } + return false +} + +var keyGUID = []byte("258EAFA5-E914-47DA-95CA-C5AB0DC85B11") + +func computeAcceptKey(challengeKey string) string { + h := sha1.New() + h.Write([]byte(challengeKey)) + h.Write(keyGUID) + return base64.StdEncoding.EncodeToString(h.Sum(nil)) +} + +func generateChallengeKey() (string, error) { + p := make([]byte, 16) + if _, err := io.ReadFull(rand.Reader, p); err != nil { + return "", err + } + return base64.StdEncoding.EncodeToString(p), nil +} diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/util_test.go b/server/Godeps/_workspace/src/github.com/gorilla/websocket/util_test.go new file mode 100644 index 0000000..91f70ce --- /dev/null +++ b/server/Godeps/_workspace/src/github.com/gorilla/websocket/util_test.go @@ -0,0 +1,34 @@ +// Copyright 2014 The Gorilla WebSocket Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package websocket + +import ( + "net/http" + "testing" +) + +var tokenListContainsValueTests = []struct { + value string + ok bool +}{ + {"WebSocket", true}, + {"WEBSOCKET", true}, + {"websocket", true}, + {"websockets", false}, + {"x websocket", false}, + {"websocket x", false}, + {"other,websocket,more", true}, + {"other, websocket, more", true}, +} + +func TestTokenListContainsValue(t *testing.T) { + for _, tt := range tokenListContainsValueTests { + h := http.Header{"Upgrade": {tt.value}} + ok := tokenListContainsValue(h, "Upgrade", "websocket") + if ok != tt.ok { + t.Errorf("tokenListContainsValue(h, n, %q) = %v, want %v", tt.value, ok, tt.ok) + } + } +} diff --git a/server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/.travis.yml b/server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/.travis.yml new file mode 100644 index 0000000..a4d6cc5 --- /dev/null +++ b/server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/.travis.yml @@ -0,0 +1,8 @@ +sudo: false +language: go +go: + - 1.1 + - 1.2 + - 1.3 + - 1.4 + - tip diff --git a/server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/LICENSE b/server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/LICENSE new file mode 100644 index 0000000..b829abc --- /dev/null +++ b/server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/LICENSE @@ -0,0 +1,24 @@ +Copyright (c) 2013 Julien Schmidt. All rights reserved. + + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * The names of the contributors may not be used to endorse or promote + products derived from this software without specific prior written + permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL JULIEN SCHMIDT BE LIABLE FOR ANY +DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/README.md b/server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/README.md new file mode 100644 index 0000000..785a108 --- /dev/null +++ b/server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/README.md @@ -0,0 +1,323 @@ +# HttpRouter [![Build Status](https://travis-ci.org/julienschmidt/httprouter.png?branch=master)](https://travis-ci.org/julienschmidt/httprouter) [![Coverage](http://gocover.io/_badge/github.com/julienschmidt/httprouter?0)](http://gocover.io/github.com/julienschmidt/httprouter) [![GoDoc](http://godoc.org/github.com/julienschmidt/httprouter?status.png)](http://godoc.org/github.com/julienschmidt/httprouter) + +HttpRouter is a lightweight high performance HTTP request router +(also called *multiplexer* or just *mux* for short) for [Go](http://golang.org/). + +In contrast to the [default mux](http://golang.org/pkg/net/http/#ServeMux) of Go's net/http package, this router supports +variables in the routing pattern and matches against the request method. +It also scales better. + +The router is optimized for high performance and a small memory footprint. +It scales well even with very long paths and a large number of routes. +A compressing dynamic trie (radix tree) structure is used for efficient matching. + +## Features +**Only explicit matches:** With other routers, like [http.ServeMux](http://golang.org/pkg/net/http/#ServeMux), +a requested URL path could match multiple patterns. Therefore they have some +awkward pattern priority rules, like *longest match* or *first registered, +first matched*. By design of this router, a request can only match exactly one +or no route. As a result, there are also no unintended matches, which makes it +great for SEO and improves the user experience. + +**Stop caring about trailing slashes:** Choose the URL style you like, the +router automatically redirects the client if a trailing slash is missing or if +there is one extra. Of course it only does so, if the new path has a handler. +If you don't like it, you can [turn off this behavior](http://godoc.org/github.com/julienschmidt/httprouter#Router.RedirectTrailingSlash). + +**Path auto-correction:** Besides detecting the missing or additional trailing +slash at no extra cost, the router can also fix wrong cases and remove +superfluous path elements (like `../` or `//`). +Is [CAPTAIN CAPS LOCK](http://www.urbandictionary.com/define.php?term=Captain+Caps+Lock) one of your users? +HttpRouter can help him by making a case-insensitive look-up and redirecting him +to the correct URL. + +**Parameters in your routing pattern:** Stop parsing the requested URL path, +just give the path segment a name and the router delivers the dynamic value to +you. Because of the design of the router, path parameters are very cheap. + +**Zero Garbage:** The matching and dispatching process generates zero bytes of +garbage. In fact, the only heap allocations that are made, is by building the +slice of the key-value pairs for path parameters. If the request path contains +no parameters, not a single heap allocation is necessary. + +**Best Performance:** [Benchmarks speak for themselves](https://github.com/julienschmidt/go-http-routing-benchmark). +See below for technical details of the implementation. + +**No more server crashes:** You can set a [Panic handler](http://godoc.org/github.com/julienschmidt/httprouter#Router.PanicHandler) to deal with panics +occurring during handling a HTTP request. The router then recovers and lets the +PanicHandler log what happened and deliver a nice error page. + +Of course you can also set **custom [NotFound](http://godoc.org/github.com/julienschmidt/httprouter#Router.NotFound) and [MethodNotAllowed](http://godoc.org/github.com/julienschmidt/httprouter#Router.MethodNotAllowed) handlers** and [**serve static files**](http://godoc.org/github.com/julienschmidt/httprouter#Router.ServeFiles). + +## Usage +This is just a quick introduction, view the [GoDoc](http://godoc.org/github.com/julienschmidt/httprouter) for details. + +Let's start with a trivial example: +```go +package main + +import ( + "fmt" + "github.com/julienschmidt/httprouter" + "net/http" + "log" +) + +func Index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { + fmt.Fprint(w, "Welcome!\n") +} + +func Hello(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { + fmt.Fprintf(w, "hello, %s!\n", ps.ByName("name")) +} + +func main() { + router := httprouter.New() + router.GET("/", Index) + router.GET("/hello/:name", Hello) + + log.Fatal(http.ListenAndServe(":8080", router)) +} +``` + +### Named parameters +As you can see, `:name` is a *named parameter*. +The values are accessible via `httprouter.Params`, which is just a slice of `httprouter.Param`s. +You can get the value of a parameter either by its index in the slice, or by using the `ByName(name)` method: +`:name` can be retrived by `ByName("name")`. + +Named parameters only match a single path segment: +``` +Pattern: /user/:user + + /user/gordon match + /user/you match + /user/gordon/profile no match + /user/ no match +``` + +**Note:** Since this router has only explicit matches, you can not register static routes and parameters for the same path segment. For example you can not register the patterns `/user/new` and `/user/:user` for the same request method at the same time. The routing of different request methods is independent from each other. + +### Catch-All parameters +The second type are *catch-all* parameters and have the form `*name`. +Like the name suggests, they match everything. +Therefore they must always be at the **end** of the pattern: +``` +Pattern: /src/*filepath + + /src/ match + /src/somefile.go match + /src/subdir/somefile.go match +``` + +## How does it work? +The router relies on a tree structure which makes heavy use of *common prefixes*, +it is basically a *compact* [*prefix tree*](http://en.wikipedia.org/wiki/Trie) +(or just [*Radix tree*](http://en.wikipedia.org/wiki/Radix_tree)). +Nodes with a common prefix also share a common parent. Here is a short example +what the routing tree for the `GET` request method could look like: + +``` +Priority Path Handle +9 \ *<1> +3 ├s nil +2 |├earch\ *<2> +1 |└upport\ *<3> +2 ├blog\ *<4> +1 | └:post nil +1 | └\ *<5> +2 ├about-us\ *<6> +1 | └team\ *<7> +1 └contact\ *<8> +``` +Every `*` represents the memory address of a handler function (a pointer). +If you follow a path trough the tree from the root to the leaf, you get the +complete route path, e.g `\blog\:post\`, where `:post` is just a placeholder +([*parameter*](#named-parameters)) for an actual post name. Unlike hash-maps, a +tree structure also allows us to use dynamic parts like the `:post` parameter, +since we actually match against the routing patterns instead of just comparing +hashes. [As benchmarks show](https://github.com/julienschmidt/go-http-routing-benchmark), +this works very well and efficient. + +Since URL paths have a hierarchical structure and make use only of a limited set +of characters (byte values), it is very likely that there are a lot of common +prefixes. This allows us to easily reduce the routing into ever smaller problems. +Moreover the router manages a separate tree for every request method. +For one thing it is more space efficient than holding a method->handle map in +every single node, for another thing is also allows us to greatly reduce the +routing problem before even starting the look-up in the prefix-tree. + +For even better scalability, the child nodes on each tree level are ordered by +priority, where the priority is just the number of handles registered in sub +nodes (children, grandchildren, and so on..). +This helps in two ways: + +1. Nodes which are part of the most routing paths are evaluated first. This +helps to make as much routes as possible to be reachable as fast as possible. +2. It is some sort of cost compensation. The longest reachable path (highest +cost) can always be evaluated first. The following scheme visualizes the tree +structure. Nodes are evaluated from top to bottom and from left to right. + +``` +├------------ +├--------- +├----- +├---- +├-- +├-- +└- +``` + + +## Why doesn't this work with http.Handler? +**It does!** The router itself implements the http.Handler interface. +Moreover the router provides convenient [adapters for http.Handler](http://godoc.org/github.com/julienschmidt/httprouter#Router.Handler)s and [http.HandlerFunc](http://godoc.org/github.com/julienschmidt/httprouter#Router.HandlerFunc)s +which allows them to be used as a [httprouter.Handle](http://godoc.org/github.com/julienschmidt/httprouter#Router.Handle) when registering a route. +The only disadvantage is, that no parameter values can be retrieved when a +http.Handler or http.HandlerFunc is used, since there is no efficient way to +pass the values with the existing function parameters. +Therefore [httprouter.Handle](http://godoc.org/github.com/julienschmidt/httprouter#Router.Handle) has a third function parameter. + +Just try it out for yourself, the usage of HttpRouter is very straightforward. The package is compact and minimalistic, but also probably one of the easiest routers to set up. + + +## Where can I find Middleware *X*? +This package just provides a very efficient request router with a few extra +features. The router is just a [http.Handler](http://golang.org/pkg/net/http/#Handler), +you can chain any http.Handler compatible middleware before the router, +for example the [Gorilla handlers](http://www.gorillatoolkit.org/pkg/handlers). +Or you could [just write your own](http://justinas.org/writing-http-middleware-in-go/), +it's very easy! + +Alternatively, you could try [a web framework based on HttpRouter](#web-frameworks-based-on-httprouter). + +### Multi-domain / Sub-domains +Here is a quick example: Does your server serve multiple domains / hosts? +You want to use sub-domains? +Define a router per host! +```go +// We need an object that implements the http.Handler interface. +// Therefore we need a type for which we implement the ServeHTTP method. +// We just use a map here, in which we map host names (with port) to http.Handlers +type HostSwitch map[string]http.Handler + +// Implement the ServerHTTP method on our new type +func (hs HostSwitch) ServeHTTP(w http.ResponseWriter, r *http.Request) { + // Check if a http.Handler is registered for the given host. + // If yes, use it to handle the request. + if handler := hs[r.Host]; handler != nil { + handler.ServeHTTP(w, r) + } else { + // Handle host names for wich no handler is registered + http.Error(w, "Forbidden", 403) // Or Redirect? + } +} + +func main() { + // Initialize a router as usual + router := httprouter.New() + router.GET("/", Index) + router.GET("/hello/:name", Hello) + + // Make a new HostSwitch and insert the router (our http handler) + // for example.com and port 12345 + hs := make(HostSwitch) + hs["example.com:12345"] = router + + // Use the HostSwitch to listen and serve on port 12345 + log.Fatal(http.ListenAndServe(":12345", hs)) +} +``` + +### Basic Authentication +Another quick example: Basic Authentification (RFC 2617) for handles: + +```go +package main + +import ( + "bytes" + "encoding/base64" + "fmt" + "github.com/julienschmidt/httprouter" + "net/http" + "log" + "strings" +) + +func BasicAuth(h httprouter.Handle, user, pass []byte) httprouter.Handle { + return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { + const basicAuthPrefix string = "Basic " + + // Get the Basic Authentication credentials + auth := r.Header.Get("Authorization") + if strings.HasPrefix(auth, basicAuthPrefix) { + // Check credentials + payload, err := base64.StdEncoding.DecodeString(auth[len(basicAuthPrefix):]) + if err == nil { + pair := bytes.SplitN(payload, []byte(":"), 2) + if len(pair) == 2 && + bytes.Equal(pair[0], user) && + bytes.Equal(pair[1], pass) { + + // Delegate request to the given handle + h(w, r, ps) + return + } + } + } + + // Request Basic Authentication otherwise + w.Header().Set("WWW-Authenticate", "Basic realm=Restricted") + http.Error(w, http.StatusText(http.StatusUnauthorized), http.StatusUnauthorized) + } +} + +func Index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { + fmt.Fprint(w, "Not protected!\n") +} + +func Protected(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { + fmt.Fprint(w, "Protected!\n") +} + +func main() { + user := []byte("gordon") + pass := []byte("secret!") + + router := httprouter.New() + router.GET("/", Index) + router.GET("/protected/", BasicAuth(Protected, user, pass)) + + log.Fatal(http.ListenAndServe(":8080", router)) +} +``` + +## Chaining with the NotFound handler + +**NOTE: It might be required to set [Router.HandleMethodNotAllowed](http://godoc.org/github.com/julienschmidt/httprouter#Router.HandleMethodNotAllowed) to `false` to avoid problems.** + +You can use another [http.Handler](http://golang.org/pkg/net/http/#Handler), for example another router, to handle requests which could not be matched by this router by using the [Router.NotFound](http://godoc.org/github.com/julienschmidt/httprouter#Router.NotFound) handler. This allows chaining. + +### Static files +The `NotFound` handler can for example be used to serve static files from the root path `/` (like an index.html file along with other assets): +```go +// Serve static files from the ./public directory +router.NotFound = http.FileServer(http.Dir("public")).ServeHTTP +``` + +But this approach sidesteps the strict core rules of this router to avoid routing problems. A cleaner approach is to use a distinct sub-path for serving files, like `/static/*filepath` or `/files/*filepath`. + +## Web Frameworks based on HttpRouter +If the HttpRouter is a bit too minimalistic for you, you might try one of the following more high-level 3rd-party web frameworks building upon the HttpRouter package: +* [Ace](https://github.com/plimble/ace): Blazing fast Go Web Framework +* [api2go](https://github.com/univedo/api2go): A JSON API Implementation for Go +* [Gin](https://github.com/gin-gonic/gin): Features a martini-like API with much better performance +* [Goat](https://github.com/bahlo/goat): A minimalistic REST API server in Go +* [Hikaru](https://github.com/najeira/hikaru): Supports standalone and Google AppEngine +* [Hitch](https://github.com/nbio/hitch): Hitch ties httprouter, [httpcontext](https://github.com/nbio/httpcontext), and middleware up in a bow +* [kami](https://github.com/guregu/kami): A tiny web framework using x/net/context +* [Medeina](https://github.com/imdario/medeina): Inspired by Ruby's Roda and Cuba +* [Neko](https://github.com/rocwong/neko): A lightweight web application framework for Golang +* [Roxanna](https://github.com/iamthemuffinman/Roxanna): An amalgamation of httprouter, better logging, and hot reload +* [siesta](https://github.com/VividCortex/siesta): Composable HTTP handlers with contexts diff --git a/server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/path.go b/server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/path.go new file mode 100644 index 0000000..486134d --- /dev/null +++ b/server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/path.go @@ -0,0 +1,123 @@ +// Copyright 2013 Julien Schmidt. All rights reserved. +// Based on the path package, Copyright 2009 The Go Authors. +// Use of this source code is governed by a BSD-style license that can be found +// in the LICENSE file. + +package httprouter + +// CleanPath is the URL version of path.Clean, it returns a canonical URL path +// for p, eliminating . and .. elements. +// +// The following rules are applied iteratively until no further processing can +// be done: +// 1. Replace multiple slashes with a single slash. +// 2. Eliminate each . path name element (the current directory). +// 3. Eliminate each inner .. path name element (the parent directory) +// along with the non-.. element that precedes it. +// 4. Eliminate .. elements that begin a rooted path: +// that is, replace "/.." by "/" at the beginning of a path. +// +// If the result of this process is an empty string, "/" is returned +func CleanPath(p string) string { + // Turn empty string into "/" + if p == "" { + return "/" + } + + n := len(p) + var buf []byte + + // Invariants: + // reading from path; r is index of next byte to process. + // writing to buf; w is index of next byte to write. + + // path must start with '/' + r := 1 + w := 1 + + if p[0] != '/' { + r = 0 + buf = make([]byte, n+1) + buf[0] = '/' + } + + trailing := n > 2 && p[n-1] == '/' + + // A bit more clunky without a 'lazybuf' like the path package, but the loop + // gets completely inlined (bufApp). So in contrast to the path package this + // loop has no expensive function calls (except 1x make) + + for r < n { + switch { + case p[r] == '/': + // empty path element, trailing slash is added after the end + r++ + + case p[r] == '.' && r+1 == n: + trailing = true + r++ + + case p[r] == '.' && p[r+1] == '/': + // . element + r++ + + case p[r] == '.' && p[r+1] == '.' && (r+2 == n || p[r+2] == '/'): + // .. element: remove to last / + r += 2 + + if w > 1 { + // can backtrack + w-- + + if buf == nil { + for w > 1 && p[w] != '/' { + w-- + } + } else { + for w > 1 && buf[w] != '/' { + w-- + } + } + } + + default: + // real path element. + // add slash if needed + if w > 1 { + bufApp(&buf, p, w, '/') + w++ + } + + // copy element + for r < n && p[r] != '/' { + bufApp(&buf, p, w, p[r]) + w++ + r++ + } + } + } + + // re-append trailing slash + if trailing && w > 1 { + bufApp(&buf, p, w, '/') + w++ + } + + if buf == nil { + return p[:w] + } + return string(buf[:w]) +} + +// internal helper to lazily create a buffer if necessary +func bufApp(buf *[]byte, s string, w int, c byte) { + if *buf == nil { + if s[w] == c { + return + } + + *buf = make([]byte, len(s)) + copy(*buf, s[:w]) + } + (*buf)[w] = c +} diff --git a/server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/path_test.go b/server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/path_test.go new file mode 100644 index 0000000..c4ceda5 --- /dev/null +++ b/server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/path_test.go @@ -0,0 +1,92 @@ +// Copyright 2013 Julien Schmidt. All rights reserved. +// Based on the path package, Copyright 2009 The Go Authors. +// Use of this source code is governed by a BSD-style license that can be found +// in the LICENSE file. + +package httprouter + +import ( + "runtime" + "testing" +) + +var cleanTests = []struct { + path, result string +}{ + // Already clean + {"/", "/"}, + {"/abc", "/abc"}, + {"/a/b/c", "/a/b/c"}, + {"/abc/", "/abc/"}, + {"/a/b/c/", "/a/b/c/"}, + + // missing root + {"", "/"}, + {"abc", "/abc"}, + {"abc/def", "/abc/def"}, + {"a/b/c", "/a/b/c"}, + + // Remove doubled slash + {"//", "/"}, + {"/abc//", "/abc/"}, + {"/abc/def//", "/abc/def/"}, + {"/a/b/c//", "/a/b/c/"}, + {"/abc//def//ghi", "/abc/def/ghi"}, + {"//abc", "/abc"}, + {"///abc", "/abc"}, + {"//abc//", "/abc/"}, + + // Remove . elements + {".", "/"}, + {"./", "/"}, + {"/abc/./def", "/abc/def"}, + {"/./abc/def", "/abc/def"}, + {"/abc/.", "/abc/"}, + + // Remove .. elements + {"..", "/"}, + {"../", "/"}, + {"../../", "/"}, + {"../..", "/"}, + {"../../abc", "/abc"}, + {"/abc/def/ghi/../jkl", "/abc/def/jkl"}, + {"/abc/def/../ghi/../jkl", "/abc/jkl"}, + {"/abc/def/..", "/abc"}, + {"/abc/def/../..", "/"}, + {"/abc/def/../../..", "/"}, + {"/abc/def/../../..", "/"}, + {"/abc/def/../../../ghi/jkl/../../../mno", "/mno"}, + + // Combinations + {"abc/./../def", "/def"}, + {"abc//./../def", "/def"}, + {"abc/../../././../def", "/def"}, +} + +func TestPathClean(t *testing.T) { + for _, test := range cleanTests { + if s := CleanPath(test.path); s != test.result { + t.Errorf("CleanPath(%q) = %q, want %q", test.path, s, test.result) + } + if s := CleanPath(test.result); s != test.result { + t.Errorf("CleanPath(%q) = %q, want %q", test.result, s, test.result) + } + } +} + +func TestPathCleanMallocs(t *testing.T) { + if testing.Short() { + t.Skip("skipping malloc count in short mode") + } + if runtime.GOMAXPROCS(0) > 1 { + t.Log("skipping AllocsPerRun checks; GOMAXPROCS>1") + return + } + + for _, test := range cleanTests { + allocs := testing.AllocsPerRun(100, func() { CleanPath(test.result) }) + if allocs > 0 { + t.Errorf("CleanPath(%q): %v allocs, want zero", test.result, allocs) + } + } +} diff --git a/server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/router.go b/server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/router.go new file mode 100644 index 0000000..83e86fd --- /dev/null +++ b/server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/router.go @@ -0,0 +1,363 @@ +// Copyright 2013 Julien Schmidt. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be found +// in the LICENSE file. + +// Package httprouter is a trie based high performance HTTP request router. +// +// A trivial example is: +// +// package main +// +// import ( +// "fmt" +// "github.com/julienschmidt/httprouter" +// "net/http" +// "log" +// ) +// +// func Index(w http.ResponseWriter, r *http.Request, _ httprouter.Params) { +// fmt.Fprint(w, "Welcome!\n") +// } +// +// func Hello(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { +// fmt.Fprintf(w, "hello, %s!\n", ps.ByName("name")) +// } +// +// func main() { +// router := httprouter.New() +// router.GET("/", Index) +// router.GET("/hello/:name", Hello) +// +// log.Fatal(http.ListenAndServe(":8080", router)) +// } +// +// The router matches incoming requests by the request method and the path. +// If a handle is registered for this path and method, the router delegates the +// request to that function. +// For the methods GET, POST, PUT, PATCH and DELETE shortcut functions exist to +// register handles, for all other methods router.Handle can be used. +// +// The registered path, against which the router matches incoming requests, can +// contain two types of parameters: +// Syntax Type +// :name named parameter +// *name catch-all parameter +// +// Named parameters are dynamic path segments. They match anything until the +// next '/' or the path end: +// Path: /blog/:category/:post +// +// Requests: +// /blog/go/request-routers match: category="go", post="request-routers" +// /blog/go/request-routers/ no match, but the router would redirect +// /blog/go/ no match +// /blog/go/request-routers/comments no match +// +// Catch-all parameters match anything until the path end, including the +// directory index (the '/' before the catch-all). Since they match anything +// until the end, catch-all paramerters must always be the final path element. +// Path: /files/*filepath +// +// Requests: +// /files/ match: filepath="/" +// /files/LICENSE match: filepath="/LICENSE" +// /files/templates/article.html match: filepath="/templates/article.html" +// /files no match, but the router would redirect +// +// The value of parameters is saved as a slice of the Param struct, consisting +// each of a key and a value. The slice is passed to the Handle func as a third +// parameter. +// There are two ways to retrieve the value of a parameter: +// // by the name of the parameter +// user := ps.ByName("user") // defined by :user or *user +// +// // by the index of the parameter. This way you can also get the name (key) +// thirdKey := ps[2].Key // the name of the 3rd parameter +// thirdValue := ps[2].Value // the value of the 3rd parameter +package httprouter + +import ( + "net/http" +) + +// Handle is a function that can be registered to a route to handle HTTP +// requests. Like http.HandlerFunc, but has a third parameter for the values of +// wildcards (variables). +type Handle func(http.ResponseWriter, *http.Request, Params) + +// Param is a single URL parameter, consisting of a key and a value. +type Param struct { + Key string + Value string +} + +// Params is a Param-slice, as returned by the router. +// The slice is ordered, the first URL parameter is also the first slice value. +// It is therefore safe to read values by the index. +type Params []Param + +// ByName returns the value of the first Param which key matches the given name. +// If no matching Param is found, an empty string is returned. +func (ps Params) ByName(name string) string { + for i := range ps { + if ps[i].Key == name { + return ps[i].Value + } + } + return "" +} + +// Router is a http.Handler which can be used to dispatch requests to different +// handler functions via configurable routes +type Router struct { + trees map[string]*node + + // Enables automatic redirection if the current route can't be matched but a + // handler for the path with (without) the trailing slash exists. + // For example if /foo/ is requested but a route only exists for /foo, the + // client is redirected to /foo with http status code 301 for GET requests + // and 307 for all other request methods. + RedirectTrailingSlash bool + + // If enabled, the router tries to fix the current request path, if no + // handle is registered for it. + // First superfluous path elements like ../ or // are removed. + // Afterwards the router does a case-insensitive lookup of the cleaned path. + // If a handle can be found for this route, the router makes a redirection + // to the corrected path with status code 301 for GET requests and 307 for + // all other request methods. + // For example /FOO and /..//Foo could be redirected to /foo. + // RedirectTrailingSlash is independent of this option. + RedirectFixedPath bool + + // If enabled, the router checks if another method is allowed for the + // current route, if the current request can not be routed. + // If this is the case, the request is answered with 'Method Not Allowed' + // and HTTP status code 405. + // If no other Method is allowed, the request is delegated to the NotFound + // handler. + HandleMethodNotAllowed bool + + // Configurable http.Handler which is called when no matching route is + // found. If it is not set, http.NotFound is used. + NotFound http.Handler + + // Configurable http.Handler which is called when a request + // cannot be routed and HandleMethodNotAllowed is true. + // If it is not set, http.Error with http.StatusMethodNotAllowed is used. + MethodNotAllowed http.Handler + + // Function to handle panics recovered from http handlers. + // It should be used to generate a error page and return the http error code + // 500 (Internal Server Error). + // The handler can be used to keep your server from crashing because of + // unrecovered panics. + PanicHandler func(http.ResponseWriter, *http.Request, interface{}) +} + +// Make sure the Router conforms with the http.Handler interface +var _ http.Handler = New() + +// New returns a new initialized Router. +// Path auto-correction, including trailing slashes, is enabled by default. +func New() *Router { + return &Router{ + RedirectTrailingSlash: true, + RedirectFixedPath: true, + HandleMethodNotAllowed: true, + } +} + +// GET is a shortcut for router.Handle("GET", path, handle) +func (r *Router) GET(path string, handle Handle) { + r.Handle("GET", path, handle) +} + +// HEAD is a shortcut for router.Handle("HEAD", path, handle) +func (r *Router) HEAD(path string, handle Handle) { + r.Handle("HEAD", path, handle) +} + +// OPTIONS is a shortcut for router.Handle("OPTIONS", path, handle) +func (r *Router) OPTIONS(path string, handle Handle) { + r.Handle("OPTIONS", path, handle) +} + +// POST is a shortcut for router.Handle("POST", path, handle) +func (r *Router) POST(path string, handle Handle) { + r.Handle("POST", path, handle) +} + +// PUT is a shortcut for router.Handle("PUT", path, handle) +func (r *Router) PUT(path string, handle Handle) { + r.Handle("PUT", path, handle) +} + +// PATCH is a shortcut for router.Handle("PATCH", path, handle) +func (r *Router) PATCH(path string, handle Handle) { + r.Handle("PATCH", path, handle) +} + +// DELETE is a shortcut for router.Handle("DELETE", path, handle) +func (r *Router) DELETE(path string, handle Handle) { + r.Handle("DELETE", path, handle) +} + +// Handle registers a new request handle with the given path and method. +// +// For GET, POST, PUT, PATCH and DELETE requests the respective shortcut +// functions can be used. +// +// This function is intended for bulk loading and to allow the usage of less +// frequently used, non-standardized or custom methods (e.g. for internal +// communication with a proxy). +func (r *Router) Handle(method, path string, handle Handle) { + if path[0] != '/' { + panic("path must begin with '/' in path '" + path + "'") + } + + if r.trees == nil { + r.trees = make(map[string]*node) + } + + root := r.trees[method] + if root == nil { + root = new(node) + r.trees[method] = root + } + + root.addRoute(path, handle) +} + +// Handler is an adapter which allows the usage of an http.Handler as a +// request handle. +func (r *Router) Handler(method, path string, handler http.Handler) { + r.Handle(method, path, + func(w http.ResponseWriter, req *http.Request, _ Params) { + handler.ServeHTTP(w, req) + }, + ) +} + +// HandlerFunc is an adapter which allows the usage of an http.HandlerFunc as a +// request handle. +func (r *Router) HandlerFunc(method, path string, handler http.HandlerFunc) { + r.Handler(method, path, handler) +} + +// ServeFiles serves files from the given file system root. +// The path must end with "/*filepath", files are then served from the local +// path /defined/root/dir/*filepath. +// For example if root is "/etc" and *filepath is "passwd", the local file +// "/etc/passwd" would be served. +// Internally a http.FileServer is used, therefore http.NotFound is used instead +// of the Router's NotFound handler. +// To use the operating system's file system implementation, +// use http.Dir: +// router.ServeFiles("/src/*filepath", http.Dir("/var/www")) +func (r *Router) ServeFiles(path string, root http.FileSystem) { + if len(path) < 10 || path[len(path)-10:] != "/*filepath" { + panic("path must end with /*filepath in path '" + path + "'") + } + + fileServer := http.FileServer(root) + + r.GET(path, func(w http.ResponseWriter, req *http.Request, ps Params) { + req.URL.Path = ps.ByName("filepath") + fileServer.ServeHTTP(w, req) + }) +} + +func (r *Router) recv(w http.ResponseWriter, req *http.Request) { + if rcv := recover(); rcv != nil { + r.PanicHandler(w, req, rcv) + } +} + +// Lookup allows the manual lookup of a method + path combo. +// This is e.g. useful to build a framework around this router. +// If the path was found, it returns the handle function and the path parameter +// values. Otherwise the third return value indicates whether a redirection to +// the same path with an extra / without the trailing slash should be performed. +func (r *Router) Lookup(method, path string) (Handle, Params, bool) { + if root := r.trees[method]; root != nil { + return root.getValue(path) + } + return nil, nil, false +} + +// ServeHTTP makes the router implement the http.Handler interface. +func (r *Router) ServeHTTP(w http.ResponseWriter, req *http.Request) { + if r.PanicHandler != nil { + defer r.recv(w, req) + } + + if root := r.trees[req.Method]; root != nil { + path := req.URL.Path + + if handle, ps, tsr := root.getValue(path); handle != nil { + handle(w, req, ps) + return + } else if req.Method != "CONNECT" && path != "/" { + code := 301 // Permanent redirect, request with GET method + if req.Method != "GET" { + // Temporary redirect, request with same method + // As of Go 1.3, Go does not support status code 308. + code = 307 + } + + if tsr && r.RedirectTrailingSlash { + if len(path) > 1 && path[len(path)-1] == '/' { + req.URL.Path = path[:len(path)-1] + } else { + req.URL.Path = path + "/" + } + http.Redirect(w, req, req.URL.String(), code) + return + } + + // Try to fix the request path + if r.RedirectFixedPath { + fixedPath, found := root.findCaseInsensitivePath( + CleanPath(path), + r.RedirectTrailingSlash, + ) + if found { + req.URL.Path = string(fixedPath) + http.Redirect(w, req, req.URL.String(), code) + return + } + } + } + } + + // Handle 405 + if r.HandleMethodNotAllowed { + for method := range r.trees { + // Skip the requested method - we already tried this one + if method == req.Method { + continue + } + + handle, _, _ := r.trees[method].getValue(req.URL.Path) + if handle != nil { + if r.MethodNotAllowed != nil { + r.MethodNotAllowed.ServeHTTP(w, req) + } else { + http.Error(w, + http.StatusText(http.StatusMethodNotAllowed), + http.StatusMethodNotAllowed, + ) + } + return + } + } + } + + // Handle 404 + if r.NotFound != nil { + r.NotFound.ServeHTTP(w, req) + } else { + http.NotFound(w, req) + } +} diff --git a/server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/router_test.go b/server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/router_test.go new file mode 100644 index 0000000..e3141bd --- /dev/null +++ b/server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/router_test.go @@ -0,0 +1,420 @@ +// Copyright 2013 Julien Schmidt. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be found +// in the LICENSE file. + +package httprouter + +import ( + "errors" + "fmt" + "net/http" + "net/http/httptest" + "reflect" + "testing" +) + +type mockResponseWriter struct{} + +func (m *mockResponseWriter) Header() (h http.Header) { + return http.Header{} +} + +func (m *mockResponseWriter) Write(p []byte) (n int, err error) { + return len(p), nil +} + +func (m *mockResponseWriter) WriteString(s string) (n int, err error) { + return len(s), nil +} + +func (m *mockResponseWriter) WriteHeader(int) {} + +func TestParams(t *testing.T) { + ps := Params{ + Param{"param1", "value1"}, + Param{"param2", "value2"}, + Param{"param3", "value3"}, + } + for i := range ps { + if val := ps.ByName(ps[i].Key); val != ps[i].Value { + t.Errorf("Wrong value for %s: Got %s; Want %s", ps[i].Key, val, ps[i].Value) + } + } + if val := ps.ByName("noKey"); val != "" { + t.Errorf("Expected empty string for not found key; got: %s", val) + } +} + +func TestRouter(t *testing.T) { + router := New() + + routed := false + router.Handle("GET", "/user/:name", func(w http.ResponseWriter, r *http.Request, ps Params) { + routed = true + want := Params{Param{"name", "gopher"}} + if !reflect.DeepEqual(ps, want) { + t.Fatalf("wrong wildcard values: want %v, got %v", want, ps) + } + }) + + w := new(mockResponseWriter) + + req, _ := http.NewRequest("GET", "/user/gopher", nil) + router.ServeHTTP(w, req) + + if !routed { + t.Fatal("routing failed") + } +} + +type handlerStruct struct { + handeled *bool +} + +func (h handlerStruct) ServeHTTP(w http.ResponseWriter, r *http.Request) { + *h.handeled = true +} + +func TestRouterAPI(t *testing.T) { + var get, head, options, post, put, patch, delete, handler, handlerFunc bool + + httpHandler := handlerStruct{&handler} + + router := New() + router.GET("/GET", func(w http.ResponseWriter, r *http.Request, _ Params) { + get = true + }) + router.HEAD("/GET", func(w http.ResponseWriter, r *http.Request, _ Params) { + head = true + }) + router.OPTIONS("/GET", func(w http.ResponseWriter, r *http.Request, _ Params) { + options = true + }) + router.POST("/POST", func(w http.ResponseWriter, r *http.Request, _ Params) { + post = true + }) + router.PUT("/PUT", func(w http.ResponseWriter, r *http.Request, _ Params) { + put = true + }) + router.PATCH("/PATCH", func(w http.ResponseWriter, r *http.Request, _ Params) { + patch = true + }) + router.DELETE("/DELETE", func(w http.ResponseWriter, r *http.Request, _ Params) { + delete = true + }) + router.Handler("GET", "/Handler", httpHandler) + router.HandlerFunc("GET", "/HandlerFunc", func(w http.ResponseWriter, r *http.Request) { + handlerFunc = true + }) + + w := new(mockResponseWriter) + + r, _ := http.NewRequest("GET", "/GET", nil) + router.ServeHTTP(w, r) + if !get { + t.Error("routing GET failed") + } + + r, _ = http.NewRequest("HEAD", "/GET", nil) + router.ServeHTTP(w, r) + if !head { + t.Error("routing HEAD failed") + } + + r, _ = http.NewRequest("OPTIONS", "/GET", nil) + router.ServeHTTP(w, r) + if !options { + t.Error("routing OPTIONS failed") + } + + r, _ = http.NewRequest("POST", "/POST", nil) + router.ServeHTTP(w, r) + if !post { + t.Error("routing POST failed") + } + + r, _ = http.NewRequest("PUT", "/PUT", nil) + router.ServeHTTP(w, r) + if !put { + t.Error("routing PUT failed") + } + + r, _ = http.NewRequest("PATCH", "/PATCH", nil) + router.ServeHTTP(w, r) + if !patch { + t.Error("routing PATCH failed") + } + + r, _ = http.NewRequest("DELETE", "/DELETE", nil) + router.ServeHTTP(w, r) + if !delete { + t.Error("routing DELETE failed") + } + + r, _ = http.NewRequest("GET", "/Handler", nil) + router.ServeHTTP(w, r) + if !handler { + t.Error("routing Handler failed") + } + + r, _ = http.NewRequest("GET", "/HandlerFunc", nil) + router.ServeHTTP(w, r) + if !handlerFunc { + t.Error("routing HandlerFunc failed") + } +} + +func TestRouterRoot(t *testing.T) { + router := New() + recv := catchPanic(func() { + router.GET("noSlashRoot", nil) + }) + if recv == nil { + t.Fatal("registering path not beginning with '/' did not panic") + } +} + +func TestRouterChaining(t *testing.T) { + router1 := New() + router2 := New() + router1.NotFound = router2 + + fooHit := false + router1.POST("/foo", func(w http.ResponseWriter, req *http.Request, _ Params) { + fooHit = true + w.WriteHeader(http.StatusOK) + }) + + barHit := false + router2.POST("/bar", func(w http.ResponseWriter, req *http.Request, _ Params) { + barHit = true + w.WriteHeader(http.StatusOK) + }) + + r, _ := http.NewRequest("POST", "/foo", nil) + w := httptest.NewRecorder() + router1.ServeHTTP(w, r) + if !(w.Code == http.StatusOK && fooHit) { + t.Errorf("Regular routing failed with router chaining.") + t.FailNow() + } + + r, _ = http.NewRequest("POST", "/bar", nil) + w = httptest.NewRecorder() + router1.ServeHTTP(w, r) + if !(w.Code == http.StatusOK && barHit) { + t.Errorf("Chained routing failed with router chaining.") + t.FailNow() + } + + r, _ = http.NewRequest("POST", "/qax", nil) + w = httptest.NewRecorder() + router1.ServeHTTP(w, r) + if !(w.Code == http.StatusNotFound) { + t.Errorf("NotFound behavior failed with router chaining.") + t.FailNow() + } +} + +func TestRouterNotAllowed(t *testing.T) { + handlerFunc := func(_ http.ResponseWriter, _ *http.Request, _ Params) {} + + router := New() + router.POST("/path", handlerFunc) + + // Test not allowed + r, _ := http.NewRequest("GET", "/path", nil) + w := httptest.NewRecorder() + router.ServeHTTP(w, r) + if !(w.Code == http.StatusMethodNotAllowed) { + t.Errorf("NotAllowed handling failed: Code=%d, Header=%v", w.Code, w.Header()) + } + + w = httptest.NewRecorder() + responseText := "custom method" + router.MethodNotAllowed = http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) { + w.WriteHeader(http.StatusTeapot) + w.Write([]byte(responseText)) + }) + router.ServeHTTP(w, r) + if got := w.Body.String(); !(got == responseText) { + t.Errorf("unexpected response got %q want %q", got, responseText) + } + if w.Code != http.StatusTeapot { + t.Errorf("unexpected response code %d want %d", w.Code, http.StatusTeapot) + } +} + +func TestRouterNotFound(t *testing.T) { + handlerFunc := func(_ http.ResponseWriter, _ *http.Request, _ Params) {} + + router := New() + router.GET("/path", handlerFunc) + router.GET("/dir/", handlerFunc) + router.GET("/", handlerFunc) + + testRoutes := []struct { + route string + code int + header string + }{ + {"/path/", 301, "map[Location:[/path]]"}, // TSR -/ + {"/dir", 301, "map[Location:[/dir/]]"}, // TSR +/ + {"", 301, "map[Location:[/]]"}, // TSR +/ + {"/PATH", 301, "map[Location:[/path]]"}, // Fixed Case + {"/DIR/", 301, "map[Location:[/dir/]]"}, // Fixed Case + {"/PATH/", 301, "map[Location:[/path]]"}, // Fixed Case -/ + {"/DIR", 301, "map[Location:[/dir/]]"}, // Fixed Case +/ + {"/../path", 301, "map[Location:[/path]]"}, // CleanPath + {"/nope", 404, ""}, // NotFound + } + for _, tr := range testRoutes { + r, _ := http.NewRequest("GET", tr.route, nil) + w := httptest.NewRecorder() + router.ServeHTTP(w, r) + if !(w.Code == tr.code && (w.Code == 404 || fmt.Sprint(w.Header()) == tr.header)) { + t.Errorf("NotFound handling route %s failed: Code=%d, Header=%v", tr.route, w.Code, w.Header()) + } + } + + // Test custom not found handler + var notFound bool + router.NotFound = http.HandlerFunc(func(rw http.ResponseWriter, r *http.Request) { + rw.WriteHeader(404) + notFound = true + }) + r, _ := http.NewRequest("GET", "/nope", nil) + w := httptest.NewRecorder() + router.ServeHTTP(w, r) + if !(w.Code == 404 && notFound == true) { + t.Errorf("Custom NotFound handler failed: Code=%d, Header=%v", w.Code, w.Header()) + } + + // Test other method than GET (want 307 instead of 301) + router.PATCH("/path", handlerFunc) + r, _ = http.NewRequest("PATCH", "/path/", nil) + w = httptest.NewRecorder() + router.ServeHTTP(w, r) + if !(w.Code == 307 && fmt.Sprint(w.Header()) == "map[Location:[/path]]") { + t.Errorf("Custom NotFound handler failed: Code=%d, Header=%v", w.Code, w.Header()) + } + + // Test special case where no node for the prefix "/" exists + router = New() + router.GET("/a", handlerFunc) + r, _ = http.NewRequest("GET", "/", nil) + w = httptest.NewRecorder() + router.ServeHTTP(w, r) + if !(w.Code == 404) { + t.Errorf("NotFound handling route / failed: Code=%d", w.Code) + } +} + +func TestRouterPanicHandler(t *testing.T) { + router := New() + panicHandled := false + + router.PanicHandler = func(rw http.ResponseWriter, r *http.Request, p interface{}) { + panicHandled = true + } + + router.Handle("PUT", "/user/:name", func(_ http.ResponseWriter, _ *http.Request, _ Params) { + panic("oops!") + }) + + w := new(mockResponseWriter) + req, _ := http.NewRequest("PUT", "/user/gopher", nil) + + defer func() { + if rcv := recover(); rcv != nil { + t.Fatal("handling panic failed") + } + }() + + router.ServeHTTP(w, req) + + if !panicHandled { + t.Fatal("simulating failed") + } +} + +func TestRouterLookup(t *testing.T) { + routed := false + wantHandle := func(_ http.ResponseWriter, _ *http.Request, _ Params) { + routed = true + } + wantParams := Params{Param{"name", "gopher"}} + + router := New() + + // try empty router first + handle, _, tsr := router.Lookup("GET", "/nope") + if handle != nil { + t.Fatalf("Got handle for unregistered pattern: %v", handle) + } + if tsr { + t.Error("Got wrong TSR recommendation!") + } + + // insert route and try again + router.GET("/user/:name", wantHandle) + + handle, params, tsr := router.Lookup("GET", "/user/gopher") + if handle == nil { + t.Fatal("Got no handle!") + } else { + handle(nil, nil, nil) + if !routed { + t.Fatal("Routing failed!") + } + } + + if !reflect.DeepEqual(params, wantParams) { + t.Fatalf("Wrong parameter values: want %v, got %v", wantParams, params) + } + + handle, _, tsr = router.Lookup("GET", "/user/gopher/") + if handle != nil { + t.Fatalf("Got handle for unregistered pattern: %v", handle) + } + if !tsr { + t.Error("Got no TSR recommendation!") + } + + handle, _, tsr = router.Lookup("GET", "/nope") + if handle != nil { + t.Fatalf("Got handle for unregistered pattern: %v", handle) + } + if tsr { + t.Error("Got wrong TSR recommendation!") + } +} + +type mockFileSystem struct { + opened bool +} + +func (mfs *mockFileSystem) Open(name string) (http.File, error) { + mfs.opened = true + return nil, errors.New("this is just a mock") +} + +func TestRouterServeFiles(t *testing.T) { + router := New() + mfs := &mockFileSystem{} + + recv := catchPanic(func() { + router.ServeFiles("/noFilepath", mfs) + }) + if recv == nil { + t.Fatal("registering path not ending with '*filepath' did not panic") + } + + router.ServeFiles("/*filepath", mfs) + w := new(mockResponseWriter) + r, _ := http.NewRequest("GET", "/favicon.ico", nil) + router.ServeHTTP(w, r) + if !mfs.opened { + t.Error("serving file failed") + } +} diff --git a/server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/tree.go b/server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/tree.go new file mode 100644 index 0000000..a15bc2c --- /dev/null +++ b/server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/tree.go @@ -0,0 +1,555 @@ +// Copyright 2013 Julien Schmidt. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be found +// in the LICENSE file. + +package httprouter + +import ( + "strings" + "unicode" +) + +func min(a, b int) int { + if a <= b { + return a + } + return b +} + +func countParams(path string) uint8 { + var n uint + for i := 0; i < len(path); i++ { + if path[i] != ':' && path[i] != '*' { + continue + } + n++ + } + if n >= 255 { + return 255 + } + return uint8(n) +} + +type nodeType uint8 + +const ( + static nodeType = 0 + param nodeType = 1 + catchAll nodeType = 2 +) + +type node struct { + path string + wildChild bool + nType nodeType + maxParams uint8 + indices string + children []*node + handle Handle + priority uint32 +} + +// increments priority of the given child and reorders if necessary +func (n *node) incrementChildPrio(pos int) int { + n.children[pos].priority++ + prio := n.children[pos].priority + + // adjust position (move to front) + newPos := pos + for newPos > 0 && n.children[newPos-1].priority < prio { + // swap node positions + tmpN := n.children[newPos-1] + n.children[newPos-1] = n.children[newPos] + n.children[newPos] = tmpN + + newPos-- + } + + // build new index char string + if newPos != pos { + n.indices = n.indices[:newPos] + // unchanged prefix, might be empty + n.indices[pos:pos+1] + // the index char we move + n.indices[newPos:pos] + n.indices[pos+1:] // rest without char at 'pos' + } + + return newPos +} + +// addRoute adds a node with the given handle to the path. +// Not concurrency-safe! +func (n *node) addRoute(path string, handle Handle) { + fullPath := path + n.priority++ + numParams := countParams(path) + + // non-empty tree + if len(n.path) > 0 || len(n.children) > 0 { + walk: + for { + // Update maxParams of the current node + if numParams > n.maxParams { + n.maxParams = numParams + } + + // Find the longest common prefix. + // This also implies that the common prefix contains no ':' or '*' + // since the existing key can't contain those chars. + i := 0 + max := min(len(path), len(n.path)) + for i < max && path[i] == n.path[i] { + i++ + } + + // Split edge + if i < len(n.path) { + child := node{ + path: n.path[i:], + wildChild: n.wildChild, + indices: n.indices, + children: n.children, + handle: n.handle, + priority: n.priority - 1, + } + + // Update maxParams (max of all children) + for i := range child.children { + if child.children[i].maxParams > child.maxParams { + child.maxParams = child.children[i].maxParams + } + } + + n.children = []*node{&child} + // []byte for proper unicode char conversion, see #65 + n.indices = string([]byte{n.path[i]}) + n.path = path[:i] + n.handle = nil + n.wildChild = false + } + + // Make new node a child of this node + if i < len(path) { + path = path[i:] + + if n.wildChild { + n = n.children[0] + n.priority++ + + // Update maxParams of the child node + if numParams > n.maxParams { + n.maxParams = numParams + } + numParams-- + + // Check if the wildcard matches + if len(path) >= len(n.path) && n.path == path[:len(n.path)] { + // check for longer wildcard, e.g. :name and :names + if len(n.path) >= len(path) || path[len(n.path)] == '/' { + continue walk + } + } + + panic("path segment '" + path + + "' conflicts with existing wildcard '" + n.path + + "' in path '" + fullPath + "'") + } + + c := path[0] + + // slash after param + if n.nType == param && c == '/' && len(n.children) == 1 { + n = n.children[0] + n.priority++ + continue walk + } + + // Check if a child with the next path byte exists + for i := 0; i < len(n.indices); i++ { + if c == n.indices[i] { + i = n.incrementChildPrio(i) + n = n.children[i] + continue walk + } + } + + // Otherwise insert it + if c != ':' && c != '*' { + // []byte for proper unicode char conversion, see #65 + n.indices += string([]byte{c}) + child := &node{ + maxParams: numParams, + } + n.children = append(n.children, child) + n.incrementChildPrio(len(n.indices) - 1) + n = child + } + n.insertChild(numParams, path, fullPath, handle) + return + + } else if i == len(path) { // Make node a (in-path) leaf + if n.handle != nil { + panic("a handle is already registered for path ''" + fullPath + "'") + } + n.handle = handle + } + return + } + } else { // Empty tree + n.insertChild(numParams, path, fullPath, handle) + } +} + +func (n *node) insertChild(numParams uint8, path, fullPath string, handle Handle) { + var offset int // already handled bytes of the path + + // find prefix until first wildcard (beginning with ':'' or '*'') + for i, max := 0, len(path); numParams > 0; i++ { + c := path[i] + if c != ':' && c != '*' { + continue + } + + // find wildcard end (either '/' or path end) + end := i + 1 + for end < max && path[end] != '/' { + switch path[end] { + // the wildcard name must not contain ':' and '*' + case ':', '*': + panic("only one wildcard per path segment is allowed, has: '" + + path[i:] + "' in path '" + fullPath + "'") + default: + end++ + } + } + + // check if this Node existing children which would be + // unreachable if we insert the wildcard here + if len(n.children) > 0 { + panic("wildcard route '" + path[i:end] + + "' conflicts with existing children in path '" + fullPath + "'") + } + + // check if the wildcard has a name + if end-i < 2 { + panic("wildcards must be named with a non-empty name in path '" + fullPath + "'") + } + + if c == ':' { // param + // split path at the beginning of the wildcard + if i > 0 { + n.path = path[offset:i] + offset = i + } + + child := &node{ + nType: param, + maxParams: numParams, + } + n.children = []*node{child} + n.wildChild = true + n = child + n.priority++ + numParams-- + + // if the path doesn't end with the wildcard, then there + // will be another non-wildcard subpath starting with '/' + if end < max { + n.path = path[offset:end] + offset = end + + child := &node{ + maxParams: numParams, + priority: 1, + } + n.children = []*node{child} + n = child + } + + } else { // catchAll + if end != max || numParams > 1 { + panic("catch-all routes are only allowed at the end of the path in path '" + fullPath + "'") + } + + if len(n.path) > 0 && n.path[len(n.path)-1] == '/' { + panic("catch-all conflicts with existing handle for the path segment root in path '" + fullPath + "'") + } + + // currently fixed width 1 for '/' + i-- + if path[i] != '/' { + panic("no / before catch-all in path '" + fullPath + "'") + } + + n.path = path[offset:i] + + // first node: catchAll node with empty path + child := &node{ + wildChild: true, + nType: catchAll, + maxParams: 1, + } + n.children = []*node{child} + n.indices = string(path[i]) + n = child + n.priority++ + + // second node: node holding the variable + child = &node{ + path: path[i:], + nType: catchAll, + maxParams: 1, + handle: handle, + priority: 1, + } + n.children = []*node{child} + + return + } + } + + // insert remaining path part and handle to the leaf + n.path = path[offset:] + n.handle = handle +} + +// Returns the handle registered with the given path (key). The values of +// wildcards are saved to a map. +// If no handle can be found, a TSR (trailing slash redirect) recommendation is +// made if a handle exists with an extra (without the) trailing slash for the +// given path. +func (n *node) getValue(path string) (handle Handle, p Params, tsr bool) { +walk: // Outer loop for walking the tree + for { + if len(path) > len(n.path) { + if path[:len(n.path)] == n.path { + path = path[len(n.path):] + // If this node does not have a wildcard (param or catchAll) + // child, we can just look up the next child node and continue + // to walk down the tree + if !n.wildChild { + c := path[0] + for i := 0; i < len(n.indices); i++ { + if c == n.indices[i] { + n = n.children[i] + continue walk + } + } + + // Nothing found. + // We can recommend to redirect to the same URL without a + // trailing slash if a leaf exists for that path. + tsr = (path == "/" && n.handle != nil) + return + + } + + // handle wildcard child + n = n.children[0] + switch n.nType { + case param: + // find param end (either '/' or path end) + end := 0 + for end < len(path) && path[end] != '/' { + end++ + } + + // save param value + if p == nil { + // lazy allocation + p = make(Params, 0, n.maxParams) + } + i := len(p) + p = p[:i+1] // expand slice within preallocated capacity + p[i].Key = n.path[1:] + p[i].Value = path[:end] + + // we need to go deeper! + if end < len(path) { + if len(n.children) > 0 { + path = path[end:] + n = n.children[0] + continue walk + } + + // ... but we can't + tsr = (len(path) == end+1) + return + } + + if handle = n.handle; handle != nil { + return + } else if len(n.children) == 1 { + // No handle found. Check if a handle for this path + a + // trailing slash exists for TSR recommendation + n = n.children[0] + tsr = (n.path == "/" && n.handle != nil) + } + + return + + case catchAll: + // save param value + if p == nil { + // lazy allocation + p = make(Params, 0, n.maxParams) + } + i := len(p) + p = p[:i+1] // expand slice within preallocated capacity + p[i].Key = n.path[2:] + p[i].Value = path + + handle = n.handle + return + + default: + panic("invalid node type") + } + } + } else if path == n.path { + // We should have reached the node containing the handle. + // Check if this node has a handle registered. + if handle = n.handle; handle != nil { + return + } + + // No handle found. Check if a handle for this path + a + // trailing slash exists for trailing slash recommendation + for i := 0; i < len(n.indices); i++ { + if n.indices[i] == '/' { + n = n.children[i] + tsr = (len(n.path) == 1 && n.handle != nil) || + (n.nType == catchAll && n.children[0].handle != nil) + return + } + } + + return + } + + // Nothing found. We can recommend to redirect to the same URL with an + // extra trailing slash if a leaf exists for that path + tsr = (path == "/") || + (len(n.path) == len(path)+1 && n.path[len(path)] == '/' && + path == n.path[:len(n.path)-1] && n.handle != nil) + return + } +} + +// Makes a case-insensitive lookup of the given path and tries to find a handler. +// It can optionally also fix trailing slashes. +// It returns the case-corrected path and a bool indicating whether the lookup +// was successful. +func (n *node) findCaseInsensitivePath(path string, fixTrailingSlash bool) (ciPath []byte, found bool) { + ciPath = make([]byte, 0, len(path)+1) // preallocate enough memory + + // Outer loop for walking the tree + for len(path) >= len(n.path) && strings.ToLower(path[:len(n.path)]) == strings.ToLower(n.path) { + path = path[len(n.path):] + ciPath = append(ciPath, n.path...) + + if len(path) > 0 { + // If this node does not have a wildcard (param or catchAll) child, + // we can just look up the next child node and continue to walk down + // the tree + if !n.wildChild { + r := unicode.ToLower(rune(path[0])) + for i, index := range n.indices { + // must use recursive approach since both index and + // ToLower(index) could exist. We must check both. + if r == unicode.ToLower(index) { + out, found := n.children[i].findCaseInsensitivePath(path, fixTrailingSlash) + if found { + return append(ciPath, out...), true + } + } + } + + // Nothing found. We can recommend to redirect to the same URL + // without a trailing slash if a leaf exists for that path + found = (fixTrailingSlash && path == "/" && n.handle != nil) + return + } + + n = n.children[0] + switch n.nType { + case param: + // find param end (either '/' or path end) + k := 0 + for k < len(path) && path[k] != '/' { + k++ + } + + // add param value to case insensitive path + ciPath = append(ciPath, path[:k]...) + + // we need to go deeper! + if k < len(path) { + if len(n.children) > 0 { + path = path[k:] + n = n.children[0] + continue + } + + // ... but we can't + if fixTrailingSlash && len(path) == k+1 { + return ciPath, true + } + return + } + + if n.handle != nil { + return ciPath, true + } else if fixTrailingSlash && len(n.children) == 1 { + // No handle found. Check if a handle for this path + a + // trailing slash exists + n = n.children[0] + if n.path == "/" && n.handle != nil { + return append(ciPath, '/'), true + } + } + return + + case catchAll: + return append(ciPath, path...), true + + default: + panic("invalid node type") + } + } else { + // We should have reached the node containing the handle. + // Check if this node has a handle registered. + if n.handle != nil { + return ciPath, true + } + + // No handle found. + // Try to fix the path by adding a trailing slash + if fixTrailingSlash { + for i := 0; i < len(n.indices); i++ { + if n.indices[i] == '/' { + n = n.children[i] + if (len(n.path) == 1 && n.handle != nil) || + (n.nType == catchAll && n.children[0].handle != nil) { + return append(ciPath, '/'), true + } + return + } + } + } + return + } + } + + // Nothing found. + // Try to fix the path by adding / removing a trailing slash + if fixTrailingSlash { + if path == "/" { + return ciPath, true + } + if len(path)+1 == len(n.path) && n.path[len(path)] == '/' && + strings.ToLower(path) == strings.ToLower(n.path[:len(path)]) && + n.handle != nil { + return append(ciPath, n.path...), true + } + } + return +} diff --git a/server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/tree_test.go b/server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/tree_test.go new file mode 100644 index 0000000..64f26d1 --- /dev/null +++ b/server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/tree_test.go @@ -0,0 +1,611 @@ +// Copyright 2013 Julien Schmidt. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be found +// in the LICENSE file. + +package httprouter + +import ( + "fmt" + "net/http" + "reflect" + "strings" + "testing" +) + +func printChildren(n *node, prefix string) { + fmt.Printf(" %02d:%02d %s%s[%d] %v %t %d \r\n", n.priority, n.maxParams, prefix, n.path, len(n.children), n.handle, n.wildChild, n.nType) + for l := len(n.path); l > 0; l-- { + prefix += " " + } + for _, child := range n.children { + printChildren(child, prefix) + } +} + +// Used as a workaround since we can't compare functions or their adresses +var fakeHandlerValue string + +func fakeHandler(val string) Handle { + return func(http.ResponseWriter, *http.Request, Params) { + fakeHandlerValue = val + } +} + +type testRequests []struct { + path string + nilHandler bool + route string + ps Params +} + +func checkRequests(t *testing.T, tree *node, requests testRequests) { + for _, request := range requests { + handler, ps, _ := tree.getValue(request.path) + + if handler == nil { + if !request.nilHandler { + t.Errorf("handle mismatch for route '%s': Expected non-nil handle", request.path) + } + } else if request.nilHandler { + t.Errorf("handle mismatch for route '%s': Expected nil handle", request.path) + } else { + handler(nil, nil, nil) + if fakeHandlerValue != request.route { + t.Errorf("handle mismatch for route '%s': Wrong handle (%s != %s)", request.path, fakeHandlerValue, request.route) + } + } + + if !reflect.DeepEqual(ps, request.ps) { + t.Errorf("Params mismatch for route '%s'", request.path) + } + } +} + +func checkPriorities(t *testing.T, n *node) uint32 { + var prio uint32 + for i := range n.children { + prio += checkPriorities(t, n.children[i]) + } + + if n.handle != nil { + prio++ + } + + if n.priority != prio { + t.Errorf( + "priority mismatch for node '%s': is %d, should be %d", + n.path, n.priority, prio, + ) + } + + return prio +} + +func checkMaxParams(t *testing.T, n *node) uint8 { + var maxParams uint8 + for i := range n.children { + params := checkMaxParams(t, n.children[i]) + if params > maxParams { + maxParams = params + } + } + if n.nType != static && !n.wildChild { + maxParams++ + } + + if n.maxParams != maxParams { + t.Errorf( + "maxParams mismatch for node '%s': is %d, should be %d", + n.path, n.maxParams, maxParams, + ) + } + + return maxParams +} + +func TestCountParams(t *testing.T) { + if countParams("/path/:param1/static/*catch-all") != 2 { + t.Fail() + } + if countParams(strings.Repeat("/:param", 256)) != 255 { + t.Fail() + } +} + +func TestTreeAddAndGet(t *testing.T) { + tree := &node{} + + routes := [...]string{ + "/hi", + "/contact", + "/co", + "/c", + "/a", + "/ab", + "/doc/", + "/doc/go_faq.html", + "/doc/go1.html", + "/α", + "/β", + } + for _, route := range routes { + tree.addRoute(route, fakeHandler(route)) + } + + //printChildren(tree, "") + + checkRequests(t, tree, testRequests{ + {"/a", false, "/a", nil}, + {"/", true, "", nil}, + {"/hi", false, "/hi", nil}, + {"/contact", false, "/contact", nil}, + {"/co", false, "/co", nil}, + {"/con", true, "", nil}, // key mismatch + {"/cona", true, "", nil}, // key mismatch + {"/no", true, "", nil}, // no matching child + {"/ab", false, "/ab", nil}, + {"/α", false, "/α", nil}, + {"/β", false, "/β", nil}, + }) + + checkPriorities(t, tree) + checkMaxParams(t, tree) +} + +func TestTreeWildcard(t *testing.T) { + tree := &node{} + + routes := [...]string{ + "/", + "/cmd/:tool/:sub", + "/cmd/:tool/", + "/src/*filepath", + "/search/", + "/search/:query", + "/user_:name", + "/user_:name/about", + "/files/:dir/*filepath", + "/doc/", + "/doc/go_faq.html", + "/doc/go1.html", + "/info/:user/public", + "/info/:user/project/:project", + } + for _, route := range routes { + tree.addRoute(route, fakeHandler(route)) + } + + //printChildren(tree, "") + + checkRequests(t, tree, testRequests{ + {"/", false, "/", nil}, + {"/cmd/test/", false, "/cmd/:tool/", Params{Param{"tool", "test"}}}, + {"/cmd/test", true, "", Params{Param{"tool", "test"}}}, + {"/cmd/test/3", false, "/cmd/:tool/:sub", Params{Param{"tool", "test"}, Param{"sub", "3"}}}, + {"/src/", false, "/src/*filepath", Params{Param{"filepath", "/"}}}, + {"/src/some/file.png", false, "/src/*filepath", Params{Param{"filepath", "/some/file.png"}}}, + {"/search/", false, "/search/", nil}, + {"/search/someth!ng+in+ünìcodé", false, "/search/:query", Params{Param{"query", "someth!ng+in+ünìcodé"}}}, + {"/search/someth!ng+in+ünìcodé/", true, "", Params{Param{"query", "someth!ng+in+ünìcodé"}}}, + {"/user_gopher", false, "/user_:name", Params{Param{"name", "gopher"}}}, + {"/user_gopher/about", false, "/user_:name/about", Params{Param{"name", "gopher"}}}, + {"/files/js/inc/framework.js", false, "/files/:dir/*filepath", Params{Param{"dir", "js"}, Param{"filepath", "/inc/framework.js"}}}, + {"/info/gordon/public", false, "/info/:user/public", Params{Param{"user", "gordon"}}}, + {"/info/gordon/project/go", false, "/info/:user/project/:project", Params{Param{"user", "gordon"}, Param{"project", "go"}}}, + }) + + checkPriorities(t, tree) + checkMaxParams(t, tree) +} + +func catchPanic(testFunc func()) (recv interface{}) { + defer func() { + recv = recover() + }() + + testFunc() + return +} + +type testRoute struct { + path string + conflict bool +} + +func testRoutes(t *testing.T, routes []testRoute) { + tree := &node{} + + for _, route := range routes { + recv := catchPanic(func() { + tree.addRoute(route.path, nil) + }) + + if route.conflict { + if recv == nil { + t.Errorf("no panic for conflicting route '%s'", route.path) + } + } else if recv != nil { + t.Errorf("unexpected panic for route '%s': %v", route.path, recv) + } + } + + //printChildren(tree, "") +} + +func TestTreeWildcardConflict(t *testing.T) { + routes := []testRoute{ + {"/cmd/:tool/:sub", false}, + {"/cmd/vet", true}, + {"/src/*filepath", false}, + {"/src/*filepathx", true}, + {"/src/", true}, + {"/src1/", false}, + {"/src1/*filepath", true}, + {"/src2*filepath", true}, + {"/search/:query", false}, + {"/search/invalid", true}, + {"/user_:name", false}, + {"/user_x", true}, + {"/user_:name", false}, + {"/id:id", false}, + {"/id/:id", true}, + } + testRoutes(t, routes) +} + +func TestTreeChildConflict(t *testing.T) { + routes := []testRoute{ + {"/cmd/vet", false}, + {"/cmd/:tool/:sub", true}, + {"/src/AUTHORS", false}, + {"/src/*filepath", true}, + {"/user_x", false}, + {"/user_:name", true}, + {"/id/:id", false}, + {"/id:id", true}, + {"/:id", true}, + {"/*filepath", true}, + } + testRoutes(t, routes) +} + +func TestTreeDupliatePath(t *testing.T) { + tree := &node{} + + routes := [...]string{ + "/", + "/doc/", + "/src/*filepath", + "/search/:query", + "/user_:name", + } + for _, route := range routes { + recv := catchPanic(func() { + tree.addRoute(route, fakeHandler(route)) + }) + if recv != nil { + t.Fatalf("panic inserting route '%s': %v", route, recv) + } + + // Add again + recv = catchPanic(func() { + tree.addRoute(route, nil) + }) + if recv == nil { + t.Fatalf("no panic while inserting duplicate route '%s", route) + } + } + + //printChildren(tree, "") + + checkRequests(t, tree, testRequests{ + {"/", false, "/", nil}, + {"/doc/", false, "/doc/", nil}, + {"/src/some/file.png", false, "/src/*filepath", Params{Param{"filepath", "/some/file.png"}}}, + {"/search/someth!ng+in+ünìcodé", false, "/search/:query", Params{Param{"query", "someth!ng+in+ünìcodé"}}}, + {"/user_gopher", false, "/user_:name", Params{Param{"name", "gopher"}}}, + }) +} + +func TestEmptyWildcardName(t *testing.T) { + tree := &node{} + + routes := [...]string{ + "/user:", + "/user:/", + "/cmd/:/", + "/src/*", + } + for _, route := range routes { + recv := catchPanic(func() { + tree.addRoute(route, nil) + }) + if recv == nil { + t.Fatalf("no panic while inserting route with empty wildcard name '%s", route) + } + } +} + +func TestTreeCatchAllConflict(t *testing.T) { + routes := []testRoute{ + {"/src/*filepath/x", true}, + {"/src2/", false}, + {"/src2/*filepath/x", true}, + } + testRoutes(t, routes) +} + +func TestTreeCatchAllConflictRoot(t *testing.T) { + routes := []testRoute{ + {"/", false}, + {"/*filepath", true}, + } + testRoutes(t, routes) +} + +func TestTreeDoubleWildcard(t *testing.T) { + const panicMsg = "only one wildcard per path segment is allowed" + + routes := [...]string{ + "/:foo:bar", + "/:foo:bar/", + "/:foo*bar", + } + + for _, route := range routes { + tree := &node{} + recv := catchPanic(func() { + tree.addRoute(route, nil) + }) + + if rs, ok := recv.(string); !ok || !strings.HasPrefix(rs, panicMsg) { + t.Fatalf(`"Expected panic "%s" for route '%s', got "%v"`, panicMsg, route, recv) + } + } +} + +/*func TestTreeDuplicateWildcard(t *testing.T) { + tree := &node{} + + routes := [...]string{ + "/:id/:name/:id", + } + for _, route := range routes { + ... + } +}*/ + +func TestTreeTrailingSlashRedirect(t *testing.T) { + tree := &node{} + + routes := [...]string{ + "/hi", + "/b/", + "/search/:query", + "/cmd/:tool/", + "/src/*filepath", + "/x", + "/x/y", + "/y/", + "/y/z", + "/0/:id", + "/0/:id/1", + "/1/:id/", + "/1/:id/2", + "/aa", + "/a/", + "/doc", + "/doc/go_faq.html", + "/doc/go1.html", + "/no/a", + "/no/b", + "/api/hello/:name", + } + for _, route := range routes { + recv := catchPanic(func() { + tree.addRoute(route, fakeHandler(route)) + }) + if recv != nil { + t.Fatalf("panic inserting route '%s': %v", route, recv) + } + } + + //printChildren(tree, "") + + tsrRoutes := [...]string{ + "/hi/", + "/b", + "/search/gopher/", + "/cmd/vet", + "/src", + "/x/", + "/y", + "/0/go/", + "/1/go", + "/a", + "/doc/", + } + for _, route := range tsrRoutes { + handler, _, tsr := tree.getValue(route) + if handler != nil { + t.Fatalf("non-nil handler for TSR route '%s", route) + } else if !tsr { + t.Errorf("expected TSR recommendation for route '%s'", route) + } + } + + noTsrRoutes := [...]string{ + "/", + "/no", + "/no/", + "/_", + "/_/", + "/api/world/abc", + } + for _, route := range noTsrRoutes { + handler, _, tsr := tree.getValue(route) + if handler != nil { + t.Fatalf("non-nil handler for No-TSR route '%s", route) + } else if tsr { + t.Errorf("expected no TSR recommendation for route '%s'", route) + } + } +} + +func TestTreeFindCaseInsensitivePath(t *testing.T) { + tree := &node{} + + routes := [...]string{ + "/hi", + "/b/", + "/ABC/", + "/search/:query", + "/cmd/:tool/", + "/src/*filepath", + "/x", + "/x/y", + "/y/", + "/y/z", + "/0/:id", + "/0/:id/1", + "/1/:id/", + "/1/:id/2", + "/aa", + "/a/", + "/doc", + "/doc/go_faq.html", + "/doc/go1.html", + "/doc/go/away", + "/no/a", + "/no/b", + } + + for _, route := range routes { + recv := catchPanic(func() { + tree.addRoute(route, fakeHandler(route)) + }) + if recv != nil { + t.Fatalf("panic inserting route '%s': %v", route, recv) + } + } + + // Check out == in for all registered routes + // With fixTrailingSlash = true + for _, route := range routes { + out, found := tree.findCaseInsensitivePath(route, true) + if !found { + t.Errorf("Route '%s' not found!", route) + } else if string(out) != route { + t.Errorf("Wrong result for route '%s': %s", route, string(out)) + } + } + // With fixTrailingSlash = false + for _, route := range routes { + out, found := tree.findCaseInsensitivePath(route, false) + if !found { + t.Errorf("Route '%s' not found!", route) + } else if string(out) != route { + t.Errorf("Wrong result for route '%s': %s", route, string(out)) + } + } + + tests := []struct { + in string + out string + found bool + slash bool + }{ + {"/HI", "/hi", true, false}, + {"/HI/", "/hi", true, true}, + {"/B", "/b/", true, true}, + {"/B/", "/b/", true, false}, + {"/abc", "/ABC/", true, true}, + {"/abc/", "/ABC/", true, false}, + {"/aBc", "/ABC/", true, true}, + {"/aBc/", "/ABC/", true, false}, + {"/abC", "/ABC/", true, true}, + {"/abC/", "/ABC/", true, false}, + {"/SEARCH/QUERY", "/search/QUERY", true, false}, + {"/SEARCH/QUERY/", "/search/QUERY", true, true}, + {"/CMD/TOOL/", "/cmd/TOOL/", true, false}, + {"/CMD/TOOL", "/cmd/TOOL/", true, true}, + {"/SRC/FILE/PATH", "/src/FILE/PATH", true, false}, + {"/x/Y", "/x/y", true, false}, + {"/x/Y/", "/x/y", true, true}, + {"/X/y", "/x/y", true, false}, + {"/X/y/", "/x/y", true, true}, + {"/X/Y", "/x/y", true, false}, + {"/X/Y/", "/x/y", true, true}, + {"/Y/", "/y/", true, false}, + {"/Y", "/y/", true, true}, + {"/Y/z", "/y/z", true, false}, + {"/Y/z/", "/y/z", true, true}, + {"/Y/Z", "/y/z", true, false}, + {"/Y/Z/", "/y/z", true, true}, + {"/y/Z", "/y/z", true, false}, + {"/y/Z/", "/y/z", true, true}, + {"/Aa", "/aa", true, false}, + {"/Aa/", "/aa", true, true}, + {"/AA", "/aa", true, false}, + {"/AA/", "/aa", true, true}, + {"/aA", "/aa", true, false}, + {"/aA/", "/aa", true, true}, + {"/A/", "/a/", true, false}, + {"/A", "/a/", true, true}, + {"/DOC", "/doc", true, false}, + {"/DOC/", "/doc", true, true}, + {"/NO", "", false, true}, + {"/DOC/GO", "", false, true}, + } + // With fixTrailingSlash = true + for _, test := range tests { + out, found := tree.findCaseInsensitivePath(test.in, true) + if found != test.found || (found && (string(out) != test.out)) { + t.Errorf("Wrong result for '%s': got %s, %t; want %s, %t", + test.in, string(out), found, test.out, test.found) + return + } + } + // With fixTrailingSlash = false + for _, test := range tests { + out, found := tree.findCaseInsensitivePath(test.in, false) + if test.slash { + if found { // test needs a trailingSlash fix. It must not be found! + t.Errorf("Found without fixTrailingSlash: %s; got %s", test.in, string(out)) + } + } else { + if found != test.found || (found && (string(out) != test.out)) { + t.Errorf("Wrong result for '%s': got %s, %t; want %s, %t", + test.in, string(out), found, test.out, test.found) + return + } + } + } +} + +func TestTreeInvalidNodeType(t *testing.T) { + const panicMsg = "invalid node type" + + tree := &node{} + tree.addRoute("/", fakeHandler("/")) + tree.addRoute("/:page", fakeHandler("/:page")) + + // set invalid node type + tree.children[0].nType = 42 + + // normal lookup + recv := catchPanic(func() { + tree.getValue("/test") + }) + if rs, ok := recv.(string); !ok || rs != panicMsg { + t.Fatalf("Expected panic '"+panicMsg+"', got '%v'", recv) + } + + // case-insensitive lookup + recv = catchPanic(func() { + tree.findCaseInsensitivePath("/test", true) + }) + if rs, ok := recv.(string); !ok || rs != panicMsg { + t.Fatalf("Expected panic '"+panicMsg+"', got '%v'", recv) + } +} diff --git a/server/connectionhub.go b/server/connectionhub.go index faf334f..9905de8 100644 --- a/server/connectionhub.go +++ b/server/connectionhub.go @@ -76,23 +76,19 @@ func (ch *connectionhub) run() { if len(err) != 0 { m.t.data <- []byte(err) } else { - if life == 0 { - m.t.data <- []byte("error:game over") - } else { - if val, ok := ch.matches[m.t]; ok { - m.t.data <- []byte(resultState + + if val, ok := ch.matches[m.t]; ok { + m.t.data <- []byte(resultState + + "[idx=" + msg.params["idx"] + "]:[type=" + strconv.Itoa(ele) + + "]:[life=" + strconv.Itoa(life) + "]") + if val != nil { + val.data <- []byte(enemyState + "[idx=" + msg.params["idx"] + "]:[type=" + strconv.Itoa(ele) + "]:[life=" + strconv.Itoa(life) + "]") - if val != nil { - val.data <- []byte(enemyState + - "[idx=" + msg.params["idx"] + "]:[type=" + strconv.Itoa(ele) + - "]:[life=" + strconv.Itoa(life) + "]") - } else { - m.t.data <- []byte("data:result:[status:won]") - } } else { - m.t.data <- []byte("error:no oponent") + m.t.data <- []byte("data:result:[status:won]") } + } else { + m.t.data <- []byte("error:no oponent") } } } diff --git a/server/entrapped.go b/server/entrapped.go index f428066..4af0b53 100644 --- a/server/entrapped.go +++ b/server/entrapped.go @@ -1,7 +1,7 @@ package entrapped import ( - "github.com/julienschmidt/httprouter" + "github.com/SKatiyar/entrapped/server/Godeps/_workspace/src/github.com/julienschmidt/httprouter" "net/http" ) diff --git a/server/troopers.go b/server/troopers.go index 210513f..e915fff 100644 --- a/server/troopers.go +++ b/server/troopers.go @@ -1,7 +1,7 @@ package entrapped import ( - "github.com/gorilla/websocket" + "github.com/SKatiyar/entrapped/server/Godeps/_workspace/src/github.com/gorilla/websocket" "net/http" "time" ) From 2feeb0044f7d9d0f272bcff2733009f185d6c148 Mon Sep 17 00:00:00 2001 From: SKatiyar Date: Tue, 14 Jul 2015 04:48:42 +0530 Subject: [PATCH 17/49] added procfile --- Procfile | 1 + 1 file changed, 1 insertion(+) create mode 100644 Procfile diff --git a/Procfile b/Procfile new file mode 100644 index 0000000..2d3e2a7 --- /dev/null +++ b/Procfile @@ -0,0 +1 @@ +web: entrapped-cmd From 9fb0c8932d64a4dfcc2257822c8e53099e5c95c8 Mon Sep 17 00:00:00 2001 From: SKatiyar Date: Tue, 14 Jul 2015 04:54:32 +0530 Subject: [PATCH 18/49] moved godeps out --- {server/Godeps => Godeps}/Godeps.json | 0 {server/Godeps => Godeps}/Readme | 0 {server/Godeps => Godeps}/_workspace/.gitignore | 0 .../_workspace/src/github.com/gorilla/websocket/.gitignore | 0 .../_workspace/src/github.com/gorilla/websocket/.travis.yml | 0 .../_workspace/src/github.com/gorilla/websocket/AUTHORS | 0 .../_workspace/src/github.com/gorilla/websocket/LICENSE | 0 .../_workspace/src/github.com/gorilla/websocket/README.md | 0 .../_workspace/src/github.com/gorilla/websocket/bench_test.go | 0 .../_workspace/src/github.com/gorilla/websocket/client.go | 0 .../src/github.com/gorilla/websocket/client_server_test.go | 0 .../_workspace/src/github.com/gorilla/websocket/client_test.go | 0 .../_workspace/src/github.com/gorilla/websocket/conn.go | 0 .../_workspace/src/github.com/gorilla/websocket/conn_test.go | 0 .../_workspace/src/github.com/gorilla/websocket/doc.go | 0 .../github.com/gorilla/websocket/examples/autobahn/README.md | 0 .../gorilla/websocket/examples/autobahn/fuzzingclient.json | 0 .../github.com/gorilla/websocket/examples/autobahn/server.go | 0 .../src/github.com/gorilla/websocket/examples/chat/README.md | 0 .../src/github.com/gorilla/websocket/examples/chat/conn.go | 0 .../src/github.com/gorilla/websocket/examples/chat/home.html | 0 .../src/github.com/gorilla/websocket/examples/chat/hub.go | 0 .../src/github.com/gorilla/websocket/examples/chat/main.go | 0 .../github.com/gorilla/websocket/examples/filewatch/README.md | 0 .../src/github.com/gorilla/websocket/examples/filewatch/main.go | 0 .../_workspace/src/github.com/gorilla/websocket/json.go | 0 .../_workspace/src/github.com/gorilla/websocket/json_test.go | 0 .../_workspace/src/github.com/gorilla/websocket/server.go | 0 .../_workspace/src/github.com/gorilla/websocket/server_test.go | 0 .../_workspace/src/github.com/gorilla/websocket/util.go | 0 .../_workspace/src/github.com/gorilla/websocket/util_test.go | 0 .../src/github.com/julienschmidt/httprouter/.travis.yml | 0 .../_workspace/src/github.com/julienschmidt/httprouter/LICENSE | 0 .../src/github.com/julienschmidt/httprouter/README.md | 0 .../_workspace/src/github.com/julienschmidt/httprouter/path.go | 0 .../src/github.com/julienschmidt/httprouter/path_test.go | 0 .../src/github.com/julienschmidt/httprouter/router.go | 0 .../src/github.com/julienschmidt/httprouter/router_test.go | 0 .../_workspace/src/github.com/julienschmidt/httprouter/tree.go | 0 .../src/github.com/julienschmidt/httprouter/tree_test.go | 0 server/entrapped.go | 2 +- server/troopers.go | 2 +- 42 files changed, 2 insertions(+), 2 deletions(-) rename {server/Godeps => Godeps}/Godeps.json (100%) rename {server/Godeps => Godeps}/Readme (100%) rename {server/Godeps => Godeps}/_workspace/.gitignore (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/gorilla/websocket/.gitignore (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/gorilla/websocket/.travis.yml (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/gorilla/websocket/AUTHORS (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/gorilla/websocket/LICENSE (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/gorilla/websocket/README.md (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/gorilla/websocket/bench_test.go (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/gorilla/websocket/client.go (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/gorilla/websocket/client_server_test.go (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/gorilla/websocket/client_test.go (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/gorilla/websocket/conn.go (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/gorilla/websocket/conn_test.go (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/gorilla/websocket/doc.go (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/gorilla/websocket/examples/autobahn/README.md (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/gorilla/websocket/examples/autobahn/fuzzingclient.json (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/gorilla/websocket/examples/autobahn/server.go (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/gorilla/websocket/examples/chat/README.md (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/gorilla/websocket/examples/chat/conn.go (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/gorilla/websocket/examples/chat/home.html (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/gorilla/websocket/examples/chat/hub.go (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/gorilla/websocket/examples/chat/main.go (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/gorilla/websocket/examples/filewatch/README.md (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/gorilla/websocket/examples/filewatch/main.go (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/gorilla/websocket/json.go (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/gorilla/websocket/json_test.go (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/gorilla/websocket/server.go (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/gorilla/websocket/server_test.go (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/gorilla/websocket/util.go (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/gorilla/websocket/util_test.go (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/julienschmidt/httprouter/.travis.yml (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/julienschmidt/httprouter/LICENSE (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/julienschmidt/httprouter/README.md (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/julienschmidt/httprouter/path.go (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/julienschmidt/httprouter/path_test.go (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/julienschmidt/httprouter/router.go (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/julienschmidt/httprouter/router_test.go (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/julienschmidt/httprouter/tree.go (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/julienschmidt/httprouter/tree_test.go (100%) diff --git a/server/Godeps/Godeps.json b/Godeps/Godeps.json similarity index 100% rename from server/Godeps/Godeps.json rename to Godeps/Godeps.json diff --git a/server/Godeps/Readme b/Godeps/Readme similarity index 100% rename from server/Godeps/Readme rename to Godeps/Readme diff --git a/server/Godeps/_workspace/.gitignore b/Godeps/_workspace/.gitignore similarity index 100% rename from server/Godeps/_workspace/.gitignore rename to Godeps/_workspace/.gitignore diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/.gitignore b/Godeps/_workspace/src/github.com/gorilla/websocket/.gitignore similarity index 100% rename from server/Godeps/_workspace/src/github.com/gorilla/websocket/.gitignore rename to Godeps/_workspace/src/github.com/gorilla/websocket/.gitignore diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/.travis.yml b/Godeps/_workspace/src/github.com/gorilla/websocket/.travis.yml similarity index 100% rename from server/Godeps/_workspace/src/github.com/gorilla/websocket/.travis.yml rename to Godeps/_workspace/src/github.com/gorilla/websocket/.travis.yml diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/AUTHORS b/Godeps/_workspace/src/github.com/gorilla/websocket/AUTHORS similarity index 100% rename from server/Godeps/_workspace/src/github.com/gorilla/websocket/AUTHORS rename to Godeps/_workspace/src/github.com/gorilla/websocket/AUTHORS diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/LICENSE b/Godeps/_workspace/src/github.com/gorilla/websocket/LICENSE similarity index 100% rename from server/Godeps/_workspace/src/github.com/gorilla/websocket/LICENSE rename to Godeps/_workspace/src/github.com/gorilla/websocket/LICENSE diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/README.md b/Godeps/_workspace/src/github.com/gorilla/websocket/README.md similarity index 100% rename from server/Godeps/_workspace/src/github.com/gorilla/websocket/README.md rename to Godeps/_workspace/src/github.com/gorilla/websocket/README.md diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/bench_test.go b/Godeps/_workspace/src/github.com/gorilla/websocket/bench_test.go similarity index 100% rename from server/Godeps/_workspace/src/github.com/gorilla/websocket/bench_test.go rename to Godeps/_workspace/src/github.com/gorilla/websocket/bench_test.go diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/client.go b/Godeps/_workspace/src/github.com/gorilla/websocket/client.go similarity index 100% rename from server/Godeps/_workspace/src/github.com/gorilla/websocket/client.go rename to Godeps/_workspace/src/github.com/gorilla/websocket/client.go diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/client_server_test.go b/Godeps/_workspace/src/github.com/gorilla/websocket/client_server_test.go similarity index 100% rename from server/Godeps/_workspace/src/github.com/gorilla/websocket/client_server_test.go rename to Godeps/_workspace/src/github.com/gorilla/websocket/client_server_test.go diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/client_test.go b/Godeps/_workspace/src/github.com/gorilla/websocket/client_test.go similarity index 100% rename from server/Godeps/_workspace/src/github.com/gorilla/websocket/client_test.go rename to Godeps/_workspace/src/github.com/gorilla/websocket/client_test.go diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/conn.go b/Godeps/_workspace/src/github.com/gorilla/websocket/conn.go similarity index 100% rename from server/Godeps/_workspace/src/github.com/gorilla/websocket/conn.go rename to Godeps/_workspace/src/github.com/gorilla/websocket/conn.go diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/conn_test.go b/Godeps/_workspace/src/github.com/gorilla/websocket/conn_test.go similarity index 100% rename from server/Godeps/_workspace/src/github.com/gorilla/websocket/conn_test.go rename to Godeps/_workspace/src/github.com/gorilla/websocket/conn_test.go diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/doc.go b/Godeps/_workspace/src/github.com/gorilla/websocket/doc.go similarity index 100% rename from server/Godeps/_workspace/src/github.com/gorilla/websocket/doc.go rename to Godeps/_workspace/src/github.com/gorilla/websocket/doc.go diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/autobahn/README.md b/Godeps/_workspace/src/github.com/gorilla/websocket/examples/autobahn/README.md similarity index 100% rename from server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/autobahn/README.md rename to Godeps/_workspace/src/github.com/gorilla/websocket/examples/autobahn/README.md diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/autobahn/fuzzingclient.json b/Godeps/_workspace/src/github.com/gorilla/websocket/examples/autobahn/fuzzingclient.json similarity index 100% rename from server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/autobahn/fuzzingclient.json rename to Godeps/_workspace/src/github.com/gorilla/websocket/examples/autobahn/fuzzingclient.json diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/autobahn/server.go b/Godeps/_workspace/src/github.com/gorilla/websocket/examples/autobahn/server.go similarity index 100% rename from server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/autobahn/server.go rename to Godeps/_workspace/src/github.com/gorilla/websocket/examples/autobahn/server.go diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/README.md b/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/README.md similarity index 100% rename from server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/README.md rename to Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/README.md diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/conn.go b/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/conn.go similarity index 100% rename from server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/conn.go rename to Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/conn.go diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/home.html b/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/home.html similarity index 100% rename from server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/home.html rename to Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/home.html diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/hub.go b/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/hub.go similarity index 100% rename from server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/hub.go rename to Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/hub.go diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/main.go b/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/main.go similarity index 100% rename from server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/main.go rename to Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/main.go diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/filewatch/README.md b/Godeps/_workspace/src/github.com/gorilla/websocket/examples/filewatch/README.md similarity index 100% rename from server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/filewatch/README.md rename to Godeps/_workspace/src/github.com/gorilla/websocket/examples/filewatch/README.md diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/filewatch/main.go b/Godeps/_workspace/src/github.com/gorilla/websocket/examples/filewatch/main.go similarity index 100% rename from server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/filewatch/main.go rename to Godeps/_workspace/src/github.com/gorilla/websocket/examples/filewatch/main.go diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/json.go b/Godeps/_workspace/src/github.com/gorilla/websocket/json.go similarity index 100% rename from server/Godeps/_workspace/src/github.com/gorilla/websocket/json.go rename to Godeps/_workspace/src/github.com/gorilla/websocket/json.go diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/json_test.go b/Godeps/_workspace/src/github.com/gorilla/websocket/json_test.go similarity index 100% rename from server/Godeps/_workspace/src/github.com/gorilla/websocket/json_test.go rename to Godeps/_workspace/src/github.com/gorilla/websocket/json_test.go diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/server.go b/Godeps/_workspace/src/github.com/gorilla/websocket/server.go similarity index 100% rename from server/Godeps/_workspace/src/github.com/gorilla/websocket/server.go rename to Godeps/_workspace/src/github.com/gorilla/websocket/server.go diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/server_test.go b/Godeps/_workspace/src/github.com/gorilla/websocket/server_test.go similarity index 100% rename from server/Godeps/_workspace/src/github.com/gorilla/websocket/server_test.go rename to Godeps/_workspace/src/github.com/gorilla/websocket/server_test.go diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/util.go b/Godeps/_workspace/src/github.com/gorilla/websocket/util.go similarity index 100% rename from server/Godeps/_workspace/src/github.com/gorilla/websocket/util.go rename to Godeps/_workspace/src/github.com/gorilla/websocket/util.go diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/util_test.go b/Godeps/_workspace/src/github.com/gorilla/websocket/util_test.go similarity index 100% rename from server/Godeps/_workspace/src/github.com/gorilla/websocket/util_test.go rename to Godeps/_workspace/src/github.com/gorilla/websocket/util_test.go diff --git a/server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/.travis.yml b/Godeps/_workspace/src/github.com/julienschmidt/httprouter/.travis.yml similarity index 100% rename from server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/.travis.yml rename to Godeps/_workspace/src/github.com/julienschmidt/httprouter/.travis.yml diff --git a/server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/LICENSE b/Godeps/_workspace/src/github.com/julienschmidt/httprouter/LICENSE similarity index 100% rename from server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/LICENSE rename to Godeps/_workspace/src/github.com/julienschmidt/httprouter/LICENSE diff --git a/server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/README.md b/Godeps/_workspace/src/github.com/julienschmidt/httprouter/README.md similarity index 100% rename from server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/README.md rename to Godeps/_workspace/src/github.com/julienschmidt/httprouter/README.md diff --git a/server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/path.go b/Godeps/_workspace/src/github.com/julienschmidt/httprouter/path.go similarity index 100% rename from server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/path.go rename to Godeps/_workspace/src/github.com/julienschmidt/httprouter/path.go diff --git a/server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/path_test.go b/Godeps/_workspace/src/github.com/julienschmidt/httprouter/path_test.go similarity index 100% rename from server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/path_test.go rename to Godeps/_workspace/src/github.com/julienschmidt/httprouter/path_test.go diff --git a/server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/router.go b/Godeps/_workspace/src/github.com/julienschmidt/httprouter/router.go similarity index 100% rename from server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/router.go rename to Godeps/_workspace/src/github.com/julienschmidt/httprouter/router.go diff --git a/server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/router_test.go b/Godeps/_workspace/src/github.com/julienschmidt/httprouter/router_test.go similarity index 100% rename from server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/router_test.go rename to Godeps/_workspace/src/github.com/julienschmidt/httprouter/router_test.go diff --git a/server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/tree.go b/Godeps/_workspace/src/github.com/julienschmidt/httprouter/tree.go similarity index 100% rename from server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/tree.go rename to Godeps/_workspace/src/github.com/julienschmidt/httprouter/tree.go diff --git a/server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/tree_test.go b/Godeps/_workspace/src/github.com/julienschmidt/httprouter/tree_test.go similarity index 100% rename from server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/tree_test.go rename to Godeps/_workspace/src/github.com/julienschmidt/httprouter/tree_test.go diff --git a/server/entrapped.go b/server/entrapped.go index 4af0b53..fcbaafb 100644 --- a/server/entrapped.go +++ b/server/entrapped.go @@ -1,7 +1,7 @@ package entrapped import ( - "github.com/SKatiyar/entrapped/server/Godeps/_workspace/src/github.com/julienschmidt/httprouter" + "github.com/SKatiyar/entrapped/Godeps/_workspace/src/github.com/julienschmidt/httprouter" "net/http" ) diff --git a/server/troopers.go b/server/troopers.go index e915fff..de47b93 100644 --- a/server/troopers.go +++ b/server/troopers.go @@ -1,7 +1,7 @@ package entrapped import ( - "github.com/SKatiyar/entrapped/server/Godeps/_workspace/src/github.com/gorilla/websocket" + "github.com/SKatiyar/entrapped/Godeps/_workspace/src/github.com/gorilla/websocket" "net/http" "time" ) From ef0635613b124b999d28d47ad6395f1daab25885 Mon Sep 17 00:00:00 2001 From: SKatiyar Date: Tue, 14 Jul 2015 04:59:11 +0530 Subject: [PATCH 19/49] trying to fix heroku build --- {server/.bkp => .bkp}/README.md | 0 {server/.bkp => .bkp}/controllers/controllers.go | 0 {server/.bkp => .bkp}/controllers/minefield.go | 0 {server/.bkp => .bkp}/models/errors.go | 0 {server/.bkp => .bkp}/models/minefield.go | 0 {server/.bkp => .bkp}/models/models.go | 0 {server/.bkp => .bkp}/models/user.go | 0 server/README.md => README.md | 0 server/connectionhub.go => connectionhub.go | 0 {server/entrapped-cmd => entrapped-cmd}/main.go | 2 +- server/entrapped.go => entrapped.go | 0 server/minefields.go => minefields.go | 0 server/minefields_test.go => minefields_test.go | 0 server/trap.go => trap.go | 0 server/troopers.go => troopers.go | 0 server/utility.go => utility.go | 0 16 files changed, 1 insertion(+), 1 deletion(-) rename {server/.bkp => .bkp}/README.md (100%) rename {server/.bkp => .bkp}/controllers/controllers.go (100%) rename {server/.bkp => .bkp}/controllers/minefield.go (100%) rename {server/.bkp => .bkp}/models/errors.go (100%) rename {server/.bkp => .bkp}/models/minefield.go (100%) rename {server/.bkp => .bkp}/models/models.go (100%) rename {server/.bkp => .bkp}/models/user.go (100%) rename server/README.md => README.md (100%) rename server/connectionhub.go => connectionhub.go (100%) rename {server/entrapped-cmd => entrapped-cmd}/main.go (79%) rename server/entrapped.go => entrapped.go (100%) rename server/minefields.go => minefields.go (100%) rename server/minefields_test.go => minefields_test.go (100%) rename server/trap.go => trap.go (100%) rename server/troopers.go => troopers.go (100%) rename server/utility.go => utility.go (100%) diff --git a/server/.bkp/README.md b/.bkp/README.md similarity index 100% rename from server/.bkp/README.md rename to .bkp/README.md diff --git a/server/.bkp/controllers/controllers.go b/.bkp/controllers/controllers.go similarity index 100% rename from server/.bkp/controllers/controllers.go rename to .bkp/controllers/controllers.go diff --git a/server/.bkp/controllers/minefield.go b/.bkp/controllers/minefield.go similarity index 100% rename from server/.bkp/controllers/minefield.go rename to .bkp/controllers/minefield.go diff --git a/server/.bkp/models/errors.go b/.bkp/models/errors.go similarity index 100% rename from server/.bkp/models/errors.go rename to .bkp/models/errors.go diff --git a/server/.bkp/models/minefield.go b/.bkp/models/minefield.go similarity index 100% rename from server/.bkp/models/minefield.go rename to .bkp/models/minefield.go diff --git a/server/.bkp/models/models.go b/.bkp/models/models.go similarity index 100% rename from server/.bkp/models/models.go rename to .bkp/models/models.go diff --git a/server/.bkp/models/user.go b/.bkp/models/user.go similarity index 100% rename from server/.bkp/models/user.go rename to .bkp/models/user.go diff --git a/server/README.md b/README.md similarity index 100% rename from server/README.md rename to README.md diff --git a/server/connectionhub.go b/connectionhub.go similarity index 100% rename from server/connectionhub.go rename to connectionhub.go diff --git a/server/entrapped-cmd/main.go b/entrapped-cmd/main.go similarity index 79% rename from server/entrapped-cmd/main.go rename to entrapped-cmd/main.go index 0357043..110c689 100644 --- a/server/entrapped-cmd/main.go +++ b/entrapped-cmd/main.go @@ -1,7 +1,7 @@ package main import ( - "github.com/SKatiyar/entrapped/server" + "github.com/SKatiyar/entrapped" "os" ) diff --git a/server/entrapped.go b/entrapped.go similarity index 100% rename from server/entrapped.go rename to entrapped.go diff --git a/server/minefields.go b/minefields.go similarity index 100% rename from server/minefields.go rename to minefields.go diff --git a/server/minefields_test.go b/minefields_test.go similarity index 100% rename from server/minefields_test.go rename to minefields_test.go diff --git a/server/trap.go b/trap.go similarity index 100% rename from server/trap.go rename to trap.go diff --git a/server/troopers.go b/troopers.go similarity index 100% rename from server/troopers.go rename to troopers.go diff --git a/server/utility.go b/utility.go similarity index 100% rename from server/utility.go rename to utility.go From da379a3bcafe975603982899bf9aebe5b78673be Mon Sep 17 00:00:00 2001 From: SKatiyar Date: Tue, 14 Jul 2015 05:07:05 +0530 Subject: [PATCH 20/49] yet another try --- {entrapped-cmd => cmd/entrapped}/main.go | 2 +- {Godeps => server/Godeps}/Godeps.json | 0 {Godeps => server/Godeps}/Readme | 0 {Godeps => server/Godeps}/_workspace/.gitignore | 0 .../_workspace/src/github.com/gorilla/websocket/.gitignore | 0 .../_workspace/src/github.com/gorilla/websocket/.travis.yml | 0 .../Godeps}/_workspace/src/github.com/gorilla/websocket/AUTHORS | 0 .../Godeps}/_workspace/src/github.com/gorilla/websocket/LICENSE | 0 .../_workspace/src/github.com/gorilla/websocket/README.md | 0 .../_workspace/src/github.com/gorilla/websocket/bench_test.go | 0 .../_workspace/src/github.com/gorilla/websocket/client.go | 0 .../src/github.com/gorilla/websocket/client_server_test.go | 0 .../_workspace/src/github.com/gorilla/websocket/client_test.go | 0 .../Godeps}/_workspace/src/github.com/gorilla/websocket/conn.go | 0 .../_workspace/src/github.com/gorilla/websocket/conn_test.go | 0 .../Godeps}/_workspace/src/github.com/gorilla/websocket/doc.go | 0 .../github.com/gorilla/websocket/examples/autobahn/README.md | 0 .../gorilla/websocket/examples/autobahn/fuzzingclient.json | 0 .../github.com/gorilla/websocket/examples/autobahn/server.go | 0 .../src/github.com/gorilla/websocket/examples/chat/README.md | 0 .../src/github.com/gorilla/websocket/examples/chat/conn.go | 0 .../src/github.com/gorilla/websocket/examples/chat/home.html | 0 .../src/github.com/gorilla/websocket/examples/chat/hub.go | 0 .../src/github.com/gorilla/websocket/examples/chat/main.go | 0 .../github.com/gorilla/websocket/examples/filewatch/README.md | 0 .../src/github.com/gorilla/websocket/examples/filewatch/main.go | 0 .../Godeps}/_workspace/src/github.com/gorilla/websocket/json.go | 0 .../_workspace/src/github.com/gorilla/websocket/json_test.go | 0 .../_workspace/src/github.com/gorilla/websocket/server.go | 0 .../_workspace/src/github.com/gorilla/websocket/server_test.go | 0 .../Godeps}/_workspace/src/github.com/gorilla/websocket/util.go | 0 .../_workspace/src/github.com/gorilla/websocket/util_test.go | 0 .../src/github.com/julienschmidt/httprouter/.travis.yml | 0 .../_workspace/src/github.com/julienschmidt/httprouter/LICENSE | 0 .../src/github.com/julienschmidt/httprouter/README.md | 0 .../_workspace/src/github.com/julienschmidt/httprouter/path.go | 0 .../src/github.com/julienschmidt/httprouter/path_test.go | 0 .../src/github.com/julienschmidt/httprouter/router.go | 0 .../src/github.com/julienschmidt/httprouter/router_test.go | 0 .../_workspace/src/github.com/julienschmidt/httprouter/tree.go | 0 .../src/github.com/julienschmidt/httprouter/tree_test.go | 0 connectionhub.go => server/connectionhub.go | 0 entrapped.go => server/entrapped.go | 2 +- minefields.go => server/minefields.go | 0 minefields_test.go => server/minefields_test.go | 0 trap.go => server/trap.go | 0 troopers.go => server/troopers.go | 2 +- utility.go => server/utility.go | 0 48 files changed, 3 insertions(+), 3 deletions(-) rename {entrapped-cmd => cmd/entrapped}/main.go (79%) rename {Godeps => server/Godeps}/Godeps.json (100%) rename {Godeps => server/Godeps}/Readme (100%) rename {Godeps => server/Godeps}/_workspace/.gitignore (100%) rename {Godeps => server/Godeps}/_workspace/src/github.com/gorilla/websocket/.gitignore (100%) rename {Godeps => server/Godeps}/_workspace/src/github.com/gorilla/websocket/.travis.yml (100%) rename {Godeps => server/Godeps}/_workspace/src/github.com/gorilla/websocket/AUTHORS (100%) rename {Godeps => server/Godeps}/_workspace/src/github.com/gorilla/websocket/LICENSE (100%) rename {Godeps => server/Godeps}/_workspace/src/github.com/gorilla/websocket/README.md (100%) rename {Godeps => server/Godeps}/_workspace/src/github.com/gorilla/websocket/bench_test.go (100%) rename {Godeps => server/Godeps}/_workspace/src/github.com/gorilla/websocket/client.go (100%) rename {Godeps => server/Godeps}/_workspace/src/github.com/gorilla/websocket/client_server_test.go (100%) rename {Godeps => server/Godeps}/_workspace/src/github.com/gorilla/websocket/client_test.go (100%) rename {Godeps => server/Godeps}/_workspace/src/github.com/gorilla/websocket/conn.go (100%) rename {Godeps => server/Godeps}/_workspace/src/github.com/gorilla/websocket/conn_test.go (100%) rename {Godeps => server/Godeps}/_workspace/src/github.com/gorilla/websocket/doc.go (100%) rename {Godeps => server/Godeps}/_workspace/src/github.com/gorilla/websocket/examples/autobahn/README.md (100%) rename {Godeps => server/Godeps}/_workspace/src/github.com/gorilla/websocket/examples/autobahn/fuzzingclient.json (100%) rename {Godeps => server/Godeps}/_workspace/src/github.com/gorilla/websocket/examples/autobahn/server.go (100%) rename {Godeps => server/Godeps}/_workspace/src/github.com/gorilla/websocket/examples/chat/README.md (100%) rename {Godeps => server/Godeps}/_workspace/src/github.com/gorilla/websocket/examples/chat/conn.go (100%) rename {Godeps => server/Godeps}/_workspace/src/github.com/gorilla/websocket/examples/chat/home.html (100%) rename {Godeps => server/Godeps}/_workspace/src/github.com/gorilla/websocket/examples/chat/hub.go (100%) rename {Godeps => server/Godeps}/_workspace/src/github.com/gorilla/websocket/examples/chat/main.go (100%) rename {Godeps => server/Godeps}/_workspace/src/github.com/gorilla/websocket/examples/filewatch/README.md (100%) rename {Godeps => server/Godeps}/_workspace/src/github.com/gorilla/websocket/examples/filewatch/main.go (100%) rename {Godeps => server/Godeps}/_workspace/src/github.com/gorilla/websocket/json.go (100%) rename {Godeps => server/Godeps}/_workspace/src/github.com/gorilla/websocket/json_test.go (100%) rename {Godeps => server/Godeps}/_workspace/src/github.com/gorilla/websocket/server.go (100%) rename {Godeps => server/Godeps}/_workspace/src/github.com/gorilla/websocket/server_test.go (100%) rename {Godeps => server/Godeps}/_workspace/src/github.com/gorilla/websocket/util.go (100%) rename {Godeps => server/Godeps}/_workspace/src/github.com/gorilla/websocket/util_test.go (100%) rename {Godeps => server/Godeps}/_workspace/src/github.com/julienschmidt/httprouter/.travis.yml (100%) rename {Godeps => server/Godeps}/_workspace/src/github.com/julienschmidt/httprouter/LICENSE (100%) rename {Godeps => server/Godeps}/_workspace/src/github.com/julienschmidt/httprouter/README.md (100%) rename {Godeps => server/Godeps}/_workspace/src/github.com/julienschmidt/httprouter/path.go (100%) rename {Godeps => server/Godeps}/_workspace/src/github.com/julienschmidt/httprouter/path_test.go (100%) rename {Godeps => server/Godeps}/_workspace/src/github.com/julienschmidt/httprouter/router.go (100%) rename {Godeps => server/Godeps}/_workspace/src/github.com/julienschmidt/httprouter/router_test.go (100%) rename {Godeps => server/Godeps}/_workspace/src/github.com/julienschmidt/httprouter/tree.go (100%) rename {Godeps => server/Godeps}/_workspace/src/github.com/julienschmidt/httprouter/tree_test.go (100%) rename connectionhub.go => server/connectionhub.go (100%) rename entrapped.go => server/entrapped.go (91%) rename minefields.go => server/minefields.go (100%) rename minefields_test.go => server/minefields_test.go (100%) rename trap.go => server/trap.go (100%) rename troopers.go => server/troopers.go (95%) rename utility.go => server/utility.go (100%) diff --git a/entrapped-cmd/main.go b/cmd/entrapped/main.go similarity index 79% rename from entrapped-cmd/main.go rename to cmd/entrapped/main.go index 110c689..0357043 100644 --- a/entrapped-cmd/main.go +++ b/cmd/entrapped/main.go @@ -1,7 +1,7 @@ package main import ( - "github.com/SKatiyar/entrapped" + "github.com/SKatiyar/entrapped/server" "os" ) diff --git a/Godeps/Godeps.json b/server/Godeps/Godeps.json similarity index 100% rename from Godeps/Godeps.json rename to server/Godeps/Godeps.json diff --git a/Godeps/Readme b/server/Godeps/Readme similarity index 100% rename from Godeps/Readme rename to server/Godeps/Readme diff --git a/Godeps/_workspace/.gitignore b/server/Godeps/_workspace/.gitignore similarity index 100% rename from Godeps/_workspace/.gitignore rename to server/Godeps/_workspace/.gitignore diff --git a/Godeps/_workspace/src/github.com/gorilla/websocket/.gitignore b/server/Godeps/_workspace/src/github.com/gorilla/websocket/.gitignore similarity index 100% rename from Godeps/_workspace/src/github.com/gorilla/websocket/.gitignore rename to server/Godeps/_workspace/src/github.com/gorilla/websocket/.gitignore diff --git a/Godeps/_workspace/src/github.com/gorilla/websocket/.travis.yml b/server/Godeps/_workspace/src/github.com/gorilla/websocket/.travis.yml similarity index 100% rename from Godeps/_workspace/src/github.com/gorilla/websocket/.travis.yml rename to server/Godeps/_workspace/src/github.com/gorilla/websocket/.travis.yml diff --git a/Godeps/_workspace/src/github.com/gorilla/websocket/AUTHORS b/server/Godeps/_workspace/src/github.com/gorilla/websocket/AUTHORS similarity index 100% rename from Godeps/_workspace/src/github.com/gorilla/websocket/AUTHORS rename to server/Godeps/_workspace/src/github.com/gorilla/websocket/AUTHORS diff --git a/Godeps/_workspace/src/github.com/gorilla/websocket/LICENSE b/server/Godeps/_workspace/src/github.com/gorilla/websocket/LICENSE similarity index 100% rename from Godeps/_workspace/src/github.com/gorilla/websocket/LICENSE rename to server/Godeps/_workspace/src/github.com/gorilla/websocket/LICENSE diff --git a/Godeps/_workspace/src/github.com/gorilla/websocket/README.md b/server/Godeps/_workspace/src/github.com/gorilla/websocket/README.md similarity index 100% rename from Godeps/_workspace/src/github.com/gorilla/websocket/README.md rename to server/Godeps/_workspace/src/github.com/gorilla/websocket/README.md diff --git a/Godeps/_workspace/src/github.com/gorilla/websocket/bench_test.go b/server/Godeps/_workspace/src/github.com/gorilla/websocket/bench_test.go similarity index 100% rename from Godeps/_workspace/src/github.com/gorilla/websocket/bench_test.go rename to server/Godeps/_workspace/src/github.com/gorilla/websocket/bench_test.go diff --git a/Godeps/_workspace/src/github.com/gorilla/websocket/client.go b/server/Godeps/_workspace/src/github.com/gorilla/websocket/client.go similarity index 100% rename from Godeps/_workspace/src/github.com/gorilla/websocket/client.go rename to server/Godeps/_workspace/src/github.com/gorilla/websocket/client.go diff --git a/Godeps/_workspace/src/github.com/gorilla/websocket/client_server_test.go b/server/Godeps/_workspace/src/github.com/gorilla/websocket/client_server_test.go similarity index 100% rename from Godeps/_workspace/src/github.com/gorilla/websocket/client_server_test.go rename to server/Godeps/_workspace/src/github.com/gorilla/websocket/client_server_test.go diff --git a/Godeps/_workspace/src/github.com/gorilla/websocket/client_test.go b/server/Godeps/_workspace/src/github.com/gorilla/websocket/client_test.go similarity index 100% rename from Godeps/_workspace/src/github.com/gorilla/websocket/client_test.go rename to server/Godeps/_workspace/src/github.com/gorilla/websocket/client_test.go diff --git a/Godeps/_workspace/src/github.com/gorilla/websocket/conn.go b/server/Godeps/_workspace/src/github.com/gorilla/websocket/conn.go similarity index 100% rename from Godeps/_workspace/src/github.com/gorilla/websocket/conn.go rename to server/Godeps/_workspace/src/github.com/gorilla/websocket/conn.go diff --git a/Godeps/_workspace/src/github.com/gorilla/websocket/conn_test.go b/server/Godeps/_workspace/src/github.com/gorilla/websocket/conn_test.go similarity index 100% rename from Godeps/_workspace/src/github.com/gorilla/websocket/conn_test.go rename to server/Godeps/_workspace/src/github.com/gorilla/websocket/conn_test.go diff --git a/Godeps/_workspace/src/github.com/gorilla/websocket/doc.go b/server/Godeps/_workspace/src/github.com/gorilla/websocket/doc.go similarity index 100% rename from Godeps/_workspace/src/github.com/gorilla/websocket/doc.go rename to server/Godeps/_workspace/src/github.com/gorilla/websocket/doc.go diff --git a/Godeps/_workspace/src/github.com/gorilla/websocket/examples/autobahn/README.md b/server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/autobahn/README.md similarity index 100% rename from Godeps/_workspace/src/github.com/gorilla/websocket/examples/autobahn/README.md rename to server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/autobahn/README.md diff --git a/Godeps/_workspace/src/github.com/gorilla/websocket/examples/autobahn/fuzzingclient.json b/server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/autobahn/fuzzingclient.json similarity index 100% rename from Godeps/_workspace/src/github.com/gorilla/websocket/examples/autobahn/fuzzingclient.json rename to server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/autobahn/fuzzingclient.json diff --git a/Godeps/_workspace/src/github.com/gorilla/websocket/examples/autobahn/server.go b/server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/autobahn/server.go similarity index 100% rename from Godeps/_workspace/src/github.com/gorilla/websocket/examples/autobahn/server.go rename to server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/autobahn/server.go diff --git a/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/README.md b/server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/README.md similarity index 100% rename from Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/README.md rename to server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/README.md diff --git a/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/conn.go b/server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/conn.go similarity index 100% rename from Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/conn.go rename to server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/conn.go diff --git a/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/home.html b/server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/home.html similarity index 100% rename from Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/home.html rename to server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/home.html diff --git a/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/hub.go b/server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/hub.go similarity index 100% rename from Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/hub.go rename to server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/hub.go diff --git a/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/main.go b/server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/main.go similarity index 100% rename from Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/main.go rename to server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/main.go diff --git a/Godeps/_workspace/src/github.com/gorilla/websocket/examples/filewatch/README.md b/server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/filewatch/README.md similarity index 100% rename from Godeps/_workspace/src/github.com/gorilla/websocket/examples/filewatch/README.md rename to server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/filewatch/README.md diff --git a/Godeps/_workspace/src/github.com/gorilla/websocket/examples/filewatch/main.go b/server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/filewatch/main.go similarity index 100% rename from Godeps/_workspace/src/github.com/gorilla/websocket/examples/filewatch/main.go rename to server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/filewatch/main.go diff --git a/Godeps/_workspace/src/github.com/gorilla/websocket/json.go b/server/Godeps/_workspace/src/github.com/gorilla/websocket/json.go similarity index 100% rename from Godeps/_workspace/src/github.com/gorilla/websocket/json.go rename to server/Godeps/_workspace/src/github.com/gorilla/websocket/json.go diff --git a/Godeps/_workspace/src/github.com/gorilla/websocket/json_test.go b/server/Godeps/_workspace/src/github.com/gorilla/websocket/json_test.go similarity index 100% rename from Godeps/_workspace/src/github.com/gorilla/websocket/json_test.go rename to server/Godeps/_workspace/src/github.com/gorilla/websocket/json_test.go diff --git a/Godeps/_workspace/src/github.com/gorilla/websocket/server.go b/server/Godeps/_workspace/src/github.com/gorilla/websocket/server.go similarity index 100% rename from Godeps/_workspace/src/github.com/gorilla/websocket/server.go rename to server/Godeps/_workspace/src/github.com/gorilla/websocket/server.go diff --git a/Godeps/_workspace/src/github.com/gorilla/websocket/server_test.go b/server/Godeps/_workspace/src/github.com/gorilla/websocket/server_test.go similarity index 100% rename from Godeps/_workspace/src/github.com/gorilla/websocket/server_test.go rename to server/Godeps/_workspace/src/github.com/gorilla/websocket/server_test.go diff --git a/Godeps/_workspace/src/github.com/gorilla/websocket/util.go b/server/Godeps/_workspace/src/github.com/gorilla/websocket/util.go similarity index 100% rename from Godeps/_workspace/src/github.com/gorilla/websocket/util.go rename to server/Godeps/_workspace/src/github.com/gorilla/websocket/util.go diff --git a/Godeps/_workspace/src/github.com/gorilla/websocket/util_test.go b/server/Godeps/_workspace/src/github.com/gorilla/websocket/util_test.go similarity index 100% rename from Godeps/_workspace/src/github.com/gorilla/websocket/util_test.go rename to server/Godeps/_workspace/src/github.com/gorilla/websocket/util_test.go diff --git a/Godeps/_workspace/src/github.com/julienschmidt/httprouter/.travis.yml b/server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/.travis.yml similarity index 100% rename from Godeps/_workspace/src/github.com/julienschmidt/httprouter/.travis.yml rename to server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/.travis.yml diff --git a/Godeps/_workspace/src/github.com/julienschmidt/httprouter/LICENSE b/server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/LICENSE similarity index 100% rename from Godeps/_workspace/src/github.com/julienschmidt/httprouter/LICENSE rename to server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/LICENSE diff --git a/Godeps/_workspace/src/github.com/julienschmidt/httprouter/README.md b/server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/README.md similarity index 100% rename from Godeps/_workspace/src/github.com/julienschmidt/httprouter/README.md rename to server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/README.md diff --git a/Godeps/_workspace/src/github.com/julienschmidt/httprouter/path.go b/server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/path.go similarity index 100% rename from Godeps/_workspace/src/github.com/julienschmidt/httprouter/path.go rename to server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/path.go diff --git a/Godeps/_workspace/src/github.com/julienschmidt/httprouter/path_test.go b/server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/path_test.go similarity index 100% rename from Godeps/_workspace/src/github.com/julienschmidt/httprouter/path_test.go rename to server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/path_test.go diff --git a/Godeps/_workspace/src/github.com/julienschmidt/httprouter/router.go b/server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/router.go similarity index 100% rename from Godeps/_workspace/src/github.com/julienschmidt/httprouter/router.go rename to server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/router.go diff --git a/Godeps/_workspace/src/github.com/julienschmidt/httprouter/router_test.go b/server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/router_test.go similarity index 100% rename from Godeps/_workspace/src/github.com/julienschmidt/httprouter/router_test.go rename to server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/router_test.go diff --git a/Godeps/_workspace/src/github.com/julienschmidt/httprouter/tree.go b/server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/tree.go similarity index 100% rename from Godeps/_workspace/src/github.com/julienschmidt/httprouter/tree.go rename to server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/tree.go diff --git a/Godeps/_workspace/src/github.com/julienschmidt/httprouter/tree_test.go b/server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/tree_test.go similarity index 100% rename from Godeps/_workspace/src/github.com/julienschmidt/httprouter/tree_test.go rename to server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/tree_test.go diff --git a/connectionhub.go b/server/connectionhub.go similarity index 100% rename from connectionhub.go rename to server/connectionhub.go diff --git a/entrapped.go b/server/entrapped.go similarity index 91% rename from entrapped.go rename to server/entrapped.go index fcbaafb..4af0b53 100644 --- a/entrapped.go +++ b/server/entrapped.go @@ -1,7 +1,7 @@ package entrapped import ( - "github.com/SKatiyar/entrapped/Godeps/_workspace/src/github.com/julienschmidt/httprouter" + "github.com/SKatiyar/entrapped/server/Godeps/_workspace/src/github.com/julienschmidt/httprouter" "net/http" ) diff --git a/minefields.go b/server/minefields.go similarity index 100% rename from minefields.go rename to server/minefields.go diff --git a/minefields_test.go b/server/minefields_test.go similarity index 100% rename from minefields_test.go rename to server/minefields_test.go diff --git a/trap.go b/server/trap.go similarity index 100% rename from trap.go rename to server/trap.go diff --git a/troopers.go b/server/troopers.go similarity index 95% rename from troopers.go rename to server/troopers.go index de47b93..e915fff 100644 --- a/troopers.go +++ b/server/troopers.go @@ -1,7 +1,7 @@ package entrapped import ( - "github.com/SKatiyar/entrapped/Godeps/_workspace/src/github.com/gorilla/websocket" + "github.com/SKatiyar/entrapped/server/Godeps/_workspace/src/github.com/gorilla/websocket" "net/http" "time" ) diff --git a/utility.go b/server/utility.go similarity index 100% rename from utility.go rename to server/utility.go From 8c423b4919550bb7e0fddfdd02eb4a0089556719 Mon Sep 17 00:00:00 2001 From: SKatiyar Date: Tue, 14 Jul 2015 05:18:51 +0530 Subject: [PATCH 21/49] maybe fixed --- {server/Godeps => Godeps}/Godeps.json | 2 +- {server/Godeps => Godeps}/Readme | 0 {server/Godeps => Godeps}/_workspace/.gitignore | 0 .../_workspace/src/github.com/gorilla/websocket/.gitignore | 0 .../_workspace/src/github.com/gorilla/websocket/.travis.yml | 0 .../_workspace/src/github.com/gorilla/websocket/AUTHORS | 0 .../_workspace/src/github.com/gorilla/websocket/LICENSE | 0 .../_workspace/src/github.com/gorilla/websocket/README.md | 0 .../_workspace/src/github.com/gorilla/websocket/bench_test.go | 0 .../_workspace/src/github.com/gorilla/websocket/client.go | 0 .../src/github.com/gorilla/websocket/client_server_test.go | 0 .../_workspace/src/github.com/gorilla/websocket/client_test.go | 0 .../_workspace/src/github.com/gorilla/websocket/conn.go | 0 .../_workspace/src/github.com/gorilla/websocket/conn_test.go | 0 .../_workspace/src/github.com/gorilla/websocket/doc.go | 0 .../github.com/gorilla/websocket/examples/autobahn/README.md | 0 .../gorilla/websocket/examples/autobahn/fuzzingclient.json | 0 .../github.com/gorilla/websocket/examples/autobahn/server.go | 0 .../src/github.com/gorilla/websocket/examples/chat/README.md | 0 .../src/github.com/gorilla/websocket/examples/chat/conn.go | 0 .../src/github.com/gorilla/websocket/examples/chat/home.html | 0 .../src/github.com/gorilla/websocket/examples/chat/hub.go | 0 .../src/github.com/gorilla/websocket/examples/chat/main.go | 0 .../github.com/gorilla/websocket/examples/filewatch/README.md | 0 .../src/github.com/gorilla/websocket/examples/filewatch/main.go | 0 .../_workspace/src/github.com/gorilla/websocket/json.go | 0 .../_workspace/src/github.com/gorilla/websocket/json_test.go | 0 .../_workspace/src/github.com/gorilla/websocket/server.go | 0 .../_workspace/src/github.com/gorilla/websocket/server_test.go | 0 .../_workspace/src/github.com/gorilla/websocket/util.go | 0 .../_workspace/src/github.com/gorilla/websocket/util_test.go | 0 .../src/github.com/julienschmidt/httprouter/.travis.yml | 0 .../_workspace/src/github.com/julienschmidt/httprouter/LICENSE | 0 .../src/github.com/julienschmidt/httprouter/README.md | 0 .../_workspace/src/github.com/julienschmidt/httprouter/path.go | 0 .../src/github.com/julienschmidt/httprouter/path_test.go | 0 .../src/github.com/julienschmidt/httprouter/router.go | 0 .../src/github.com/julienschmidt/httprouter/router_test.go | 0 .../_workspace/src/github.com/julienschmidt/httprouter/tree.go | 0 .../src/github.com/julienschmidt/httprouter/tree_test.go | 0 {cmd => server/cmd}/entrapped/main.go | 0 server/entrapped.go | 2 +- server/troopers.go | 2 +- 43 files changed, 3 insertions(+), 3 deletions(-) rename {server/Godeps => Godeps}/Godeps.json (84%) rename {server/Godeps => Godeps}/Readme (100%) rename {server/Godeps => Godeps}/_workspace/.gitignore (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/gorilla/websocket/.gitignore (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/gorilla/websocket/.travis.yml (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/gorilla/websocket/AUTHORS (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/gorilla/websocket/LICENSE (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/gorilla/websocket/README.md (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/gorilla/websocket/bench_test.go (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/gorilla/websocket/client.go (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/gorilla/websocket/client_server_test.go (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/gorilla/websocket/client_test.go (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/gorilla/websocket/conn.go (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/gorilla/websocket/conn_test.go (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/gorilla/websocket/doc.go (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/gorilla/websocket/examples/autobahn/README.md (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/gorilla/websocket/examples/autobahn/fuzzingclient.json (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/gorilla/websocket/examples/autobahn/server.go (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/gorilla/websocket/examples/chat/README.md (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/gorilla/websocket/examples/chat/conn.go (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/gorilla/websocket/examples/chat/home.html (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/gorilla/websocket/examples/chat/hub.go (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/gorilla/websocket/examples/chat/main.go (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/gorilla/websocket/examples/filewatch/README.md (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/gorilla/websocket/examples/filewatch/main.go (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/gorilla/websocket/json.go (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/gorilla/websocket/json_test.go (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/gorilla/websocket/server.go (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/gorilla/websocket/server_test.go (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/gorilla/websocket/util.go (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/gorilla/websocket/util_test.go (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/julienschmidt/httprouter/.travis.yml (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/julienschmidt/httprouter/LICENSE (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/julienschmidt/httprouter/README.md (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/julienschmidt/httprouter/path.go (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/julienschmidt/httprouter/path_test.go (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/julienschmidt/httprouter/router.go (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/julienschmidt/httprouter/router_test.go (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/julienschmidt/httprouter/tree.go (100%) rename {server/Godeps => Godeps}/_workspace/src/github.com/julienschmidt/httprouter/tree_test.go (100%) rename {cmd => server/cmd}/entrapped/main.go (100%) diff --git a/server/Godeps/Godeps.json b/Godeps/Godeps.json similarity index 84% rename from server/Godeps/Godeps.json rename to Godeps/Godeps.json index 0994362..71d3ec3 100644 --- a/server/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -1,5 +1,5 @@ { - "ImportPath": "github.com/SKatiyar/entrapped/server", + "ImportPath": "github.com/SKatiyar/entrapped", "GoVersion": "go1.4", "Deps": [ { diff --git a/server/Godeps/Readme b/Godeps/Readme similarity index 100% rename from server/Godeps/Readme rename to Godeps/Readme diff --git a/server/Godeps/_workspace/.gitignore b/Godeps/_workspace/.gitignore similarity index 100% rename from server/Godeps/_workspace/.gitignore rename to Godeps/_workspace/.gitignore diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/.gitignore b/Godeps/_workspace/src/github.com/gorilla/websocket/.gitignore similarity index 100% rename from server/Godeps/_workspace/src/github.com/gorilla/websocket/.gitignore rename to Godeps/_workspace/src/github.com/gorilla/websocket/.gitignore diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/.travis.yml b/Godeps/_workspace/src/github.com/gorilla/websocket/.travis.yml similarity index 100% rename from server/Godeps/_workspace/src/github.com/gorilla/websocket/.travis.yml rename to Godeps/_workspace/src/github.com/gorilla/websocket/.travis.yml diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/AUTHORS b/Godeps/_workspace/src/github.com/gorilla/websocket/AUTHORS similarity index 100% rename from server/Godeps/_workspace/src/github.com/gorilla/websocket/AUTHORS rename to Godeps/_workspace/src/github.com/gorilla/websocket/AUTHORS diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/LICENSE b/Godeps/_workspace/src/github.com/gorilla/websocket/LICENSE similarity index 100% rename from server/Godeps/_workspace/src/github.com/gorilla/websocket/LICENSE rename to Godeps/_workspace/src/github.com/gorilla/websocket/LICENSE diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/README.md b/Godeps/_workspace/src/github.com/gorilla/websocket/README.md similarity index 100% rename from server/Godeps/_workspace/src/github.com/gorilla/websocket/README.md rename to Godeps/_workspace/src/github.com/gorilla/websocket/README.md diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/bench_test.go b/Godeps/_workspace/src/github.com/gorilla/websocket/bench_test.go similarity index 100% rename from server/Godeps/_workspace/src/github.com/gorilla/websocket/bench_test.go rename to Godeps/_workspace/src/github.com/gorilla/websocket/bench_test.go diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/client.go b/Godeps/_workspace/src/github.com/gorilla/websocket/client.go similarity index 100% rename from server/Godeps/_workspace/src/github.com/gorilla/websocket/client.go rename to Godeps/_workspace/src/github.com/gorilla/websocket/client.go diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/client_server_test.go b/Godeps/_workspace/src/github.com/gorilla/websocket/client_server_test.go similarity index 100% rename from server/Godeps/_workspace/src/github.com/gorilla/websocket/client_server_test.go rename to Godeps/_workspace/src/github.com/gorilla/websocket/client_server_test.go diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/client_test.go b/Godeps/_workspace/src/github.com/gorilla/websocket/client_test.go similarity index 100% rename from server/Godeps/_workspace/src/github.com/gorilla/websocket/client_test.go rename to Godeps/_workspace/src/github.com/gorilla/websocket/client_test.go diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/conn.go b/Godeps/_workspace/src/github.com/gorilla/websocket/conn.go similarity index 100% rename from server/Godeps/_workspace/src/github.com/gorilla/websocket/conn.go rename to Godeps/_workspace/src/github.com/gorilla/websocket/conn.go diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/conn_test.go b/Godeps/_workspace/src/github.com/gorilla/websocket/conn_test.go similarity index 100% rename from server/Godeps/_workspace/src/github.com/gorilla/websocket/conn_test.go rename to Godeps/_workspace/src/github.com/gorilla/websocket/conn_test.go diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/doc.go b/Godeps/_workspace/src/github.com/gorilla/websocket/doc.go similarity index 100% rename from server/Godeps/_workspace/src/github.com/gorilla/websocket/doc.go rename to Godeps/_workspace/src/github.com/gorilla/websocket/doc.go diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/autobahn/README.md b/Godeps/_workspace/src/github.com/gorilla/websocket/examples/autobahn/README.md similarity index 100% rename from server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/autobahn/README.md rename to Godeps/_workspace/src/github.com/gorilla/websocket/examples/autobahn/README.md diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/autobahn/fuzzingclient.json b/Godeps/_workspace/src/github.com/gorilla/websocket/examples/autobahn/fuzzingclient.json similarity index 100% rename from server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/autobahn/fuzzingclient.json rename to Godeps/_workspace/src/github.com/gorilla/websocket/examples/autobahn/fuzzingclient.json diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/autobahn/server.go b/Godeps/_workspace/src/github.com/gorilla/websocket/examples/autobahn/server.go similarity index 100% rename from server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/autobahn/server.go rename to Godeps/_workspace/src/github.com/gorilla/websocket/examples/autobahn/server.go diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/README.md b/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/README.md similarity index 100% rename from server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/README.md rename to Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/README.md diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/conn.go b/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/conn.go similarity index 100% rename from server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/conn.go rename to Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/conn.go diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/home.html b/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/home.html similarity index 100% rename from server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/home.html rename to Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/home.html diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/hub.go b/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/hub.go similarity index 100% rename from server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/hub.go rename to Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/hub.go diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/main.go b/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/main.go similarity index 100% rename from server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/main.go rename to Godeps/_workspace/src/github.com/gorilla/websocket/examples/chat/main.go diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/filewatch/README.md b/Godeps/_workspace/src/github.com/gorilla/websocket/examples/filewatch/README.md similarity index 100% rename from server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/filewatch/README.md rename to Godeps/_workspace/src/github.com/gorilla/websocket/examples/filewatch/README.md diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/filewatch/main.go b/Godeps/_workspace/src/github.com/gorilla/websocket/examples/filewatch/main.go similarity index 100% rename from server/Godeps/_workspace/src/github.com/gorilla/websocket/examples/filewatch/main.go rename to Godeps/_workspace/src/github.com/gorilla/websocket/examples/filewatch/main.go diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/json.go b/Godeps/_workspace/src/github.com/gorilla/websocket/json.go similarity index 100% rename from server/Godeps/_workspace/src/github.com/gorilla/websocket/json.go rename to Godeps/_workspace/src/github.com/gorilla/websocket/json.go diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/json_test.go b/Godeps/_workspace/src/github.com/gorilla/websocket/json_test.go similarity index 100% rename from server/Godeps/_workspace/src/github.com/gorilla/websocket/json_test.go rename to Godeps/_workspace/src/github.com/gorilla/websocket/json_test.go diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/server.go b/Godeps/_workspace/src/github.com/gorilla/websocket/server.go similarity index 100% rename from server/Godeps/_workspace/src/github.com/gorilla/websocket/server.go rename to Godeps/_workspace/src/github.com/gorilla/websocket/server.go diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/server_test.go b/Godeps/_workspace/src/github.com/gorilla/websocket/server_test.go similarity index 100% rename from server/Godeps/_workspace/src/github.com/gorilla/websocket/server_test.go rename to Godeps/_workspace/src/github.com/gorilla/websocket/server_test.go diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/util.go b/Godeps/_workspace/src/github.com/gorilla/websocket/util.go similarity index 100% rename from server/Godeps/_workspace/src/github.com/gorilla/websocket/util.go rename to Godeps/_workspace/src/github.com/gorilla/websocket/util.go diff --git a/server/Godeps/_workspace/src/github.com/gorilla/websocket/util_test.go b/Godeps/_workspace/src/github.com/gorilla/websocket/util_test.go similarity index 100% rename from server/Godeps/_workspace/src/github.com/gorilla/websocket/util_test.go rename to Godeps/_workspace/src/github.com/gorilla/websocket/util_test.go diff --git a/server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/.travis.yml b/Godeps/_workspace/src/github.com/julienschmidt/httprouter/.travis.yml similarity index 100% rename from server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/.travis.yml rename to Godeps/_workspace/src/github.com/julienschmidt/httprouter/.travis.yml diff --git a/server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/LICENSE b/Godeps/_workspace/src/github.com/julienschmidt/httprouter/LICENSE similarity index 100% rename from server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/LICENSE rename to Godeps/_workspace/src/github.com/julienschmidt/httprouter/LICENSE diff --git a/server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/README.md b/Godeps/_workspace/src/github.com/julienschmidt/httprouter/README.md similarity index 100% rename from server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/README.md rename to Godeps/_workspace/src/github.com/julienschmidt/httprouter/README.md diff --git a/server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/path.go b/Godeps/_workspace/src/github.com/julienschmidt/httprouter/path.go similarity index 100% rename from server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/path.go rename to Godeps/_workspace/src/github.com/julienschmidt/httprouter/path.go diff --git a/server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/path_test.go b/Godeps/_workspace/src/github.com/julienschmidt/httprouter/path_test.go similarity index 100% rename from server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/path_test.go rename to Godeps/_workspace/src/github.com/julienschmidt/httprouter/path_test.go diff --git a/server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/router.go b/Godeps/_workspace/src/github.com/julienschmidt/httprouter/router.go similarity index 100% rename from server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/router.go rename to Godeps/_workspace/src/github.com/julienschmidt/httprouter/router.go diff --git a/server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/router_test.go b/Godeps/_workspace/src/github.com/julienschmidt/httprouter/router_test.go similarity index 100% rename from server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/router_test.go rename to Godeps/_workspace/src/github.com/julienschmidt/httprouter/router_test.go diff --git a/server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/tree.go b/Godeps/_workspace/src/github.com/julienschmidt/httprouter/tree.go similarity index 100% rename from server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/tree.go rename to Godeps/_workspace/src/github.com/julienschmidt/httprouter/tree.go diff --git a/server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/tree_test.go b/Godeps/_workspace/src/github.com/julienschmidt/httprouter/tree_test.go similarity index 100% rename from server/Godeps/_workspace/src/github.com/julienschmidt/httprouter/tree_test.go rename to Godeps/_workspace/src/github.com/julienschmidt/httprouter/tree_test.go diff --git a/cmd/entrapped/main.go b/server/cmd/entrapped/main.go similarity index 100% rename from cmd/entrapped/main.go rename to server/cmd/entrapped/main.go diff --git a/server/entrapped.go b/server/entrapped.go index 4af0b53..fcbaafb 100644 --- a/server/entrapped.go +++ b/server/entrapped.go @@ -1,7 +1,7 @@ package entrapped import ( - "github.com/SKatiyar/entrapped/server/Godeps/_workspace/src/github.com/julienschmidt/httprouter" + "github.com/SKatiyar/entrapped/Godeps/_workspace/src/github.com/julienschmidt/httprouter" "net/http" ) diff --git a/server/troopers.go b/server/troopers.go index e915fff..de47b93 100644 --- a/server/troopers.go +++ b/server/troopers.go @@ -1,7 +1,7 @@ package entrapped import ( - "github.com/SKatiyar/entrapped/server/Godeps/_workspace/src/github.com/gorilla/websocket" + "github.com/SKatiyar/entrapped/Godeps/_workspace/src/github.com/gorilla/websocket" "net/http" "time" ) From 4a79ba3f6f64dcb6f68772ccf8afce712a8db915 Mon Sep 17 00:00:00 2001 From: SKatiyar Date: Tue, 14 Jul 2015 05:20:56 +0530 Subject: [PATCH 22/49] fixed name --- Procfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Procfile b/Procfile index 2d3e2a7..59a3fe1 100644 --- a/Procfile +++ b/Procfile @@ -1 +1 @@ -web: entrapped-cmd +web: entrapped From 891838e5aa7871d468b478698ebd19adfd3cc5b0 Mon Sep 17 00:00:00 2001 From: SKatiyar Date: Tue, 14 Jul 2015 05:26:26 +0530 Subject: [PATCH 23/49] readme --- README.md => server/README.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename README.md => server/README.md (100%) diff --git a/README.md b/server/README.md similarity index 100% rename from README.md rename to server/README.md From de0588ce6cf66decc653d610cb54724577c7e9db Mon Sep 17 00:00:00 2001 From: ghome vic Date: Tue, 14 Jul 2015 05:31:25 +0530 Subject: [PATCH 24/49] Alpha 1.0 --- client/src/api/api.js | 9 +++- client/src/components/Blocks.jsx | 3 +- client/src/components/Field.jsx | 45 ++++++++++++++++ client/src/components/Minefield.jsx | 75 ++++++++++++++------------ client/src/stores/minestore.js | 83 +++++++++++++++++++++-------- client/src/styles/main.css | 22 +++++--- client/webpack.config.js | 2 +- 7 files changed, 171 insertions(+), 68 deletions(-) create mode 100644 client/src/components/Field.jsx diff --git a/client/src/api/api.js b/client/src/api/api.js index 851de92..4fa7a8e 100644 --- a/client/src/api/api.js +++ b/client/src/api/api.js @@ -21,8 +21,9 @@ module.exports = { }; conn.onmessage = function(evt) { + //console.log('data from server', evt); var data = _.getObject(evt.data); - + //console.log('data', data); AppDispatcher.handleServerAction(data); }; @@ -32,7 +33,11 @@ module.exports = { }, send: function(data) { - console.log('sending ', data); + //console.log('sending ', data); conn.send(data); + }, + + close: function() { + conn.close(); } }; diff --git a/client/src/components/Blocks.jsx b/client/src/components/Blocks.jsx index b4b5308..a736375 100644 --- a/client/src/components/Blocks.jsx +++ b/client/src/components/Blocks.jsx @@ -19,7 +19,7 @@ class Block extends React.Component { var cx = React.addons.classSet; var classes = cx({ 'block': true, - 'block__visited': this.props.status === -1, + 'block__visited': this.props.status === 0 || this.props.status === 9, 'block__dead': this.props.status === -2 }); @@ -42,7 +42,6 @@ class Blocks extends React.Component { } render() { - var nodes = []; var size = this.props.size; diff --git a/client/src/components/Field.jsx b/client/src/components/Field.jsx new file mode 100644 index 0000000..1f2d64e --- /dev/null +++ b/client/src/components/Field.jsx @@ -0,0 +1,45 @@ +import React from 'react/addons'; + +import Blocks from './Blocks.jsx'; + +class Field extends React.Component { + constructor(props) { + super(props); + } + + render() { + var cx = React.addons.classSet; + var classes = cx({ + 'minefield': true, + 'minefield__enemy': this.props.of === "enemy", + 'minefield__user': this.props.of === "player" + }); + + var nodes = []; + for (var i = 1; i <= 5; i++) { + var classname = "fa fa-2x fa-heartbeat heart-icons"; + + if (i <= this.props.player.life) { + classname = classname + " life-status__active"; + } + + nodes.push(); + } + + return ( +
+ +
+ + {nodes} + +
+

{this.props.player.username}

+
+ ) + } +}; +Field.propTypes = { of: React.PropTypes.string, player: React.PropTypes.object }; +Field.defaultProps = { of: 'user', player: {} }; + +export default Field; diff --git a/client/src/components/Minefield.jsx b/client/src/components/Minefield.jsx index f19013a..305b449 100644 --- a/client/src/components/Minefield.jsx +++ b/client/src/components/Minefield.jsx @@ -1,6 +1,6 @@ import React from 'react'; -import Blocks from './Blocks.jsx'; +import Field from './Field.jsx'; import MinesStore from '../stores/minestore.js'; import Api from '../api/api.js'; @@ -9,48 +9,55 @@ class Minefield extends React.Component { super(); this.state = { - mines : MinesStore.getMines(), - username: MinesStore.getUsername() + player: MinesStore.getUser(), + enemy: MinesStore.getEnemy() }; // connect Api.connect(MinesStore.getUsername()); + MinesStore.addChangeListener(this._onChange.bind(this)); + } + + componentWillUnmount() { + MinesStore.removeChangeListener(this._onChange); + } + + _onChange() { + this.setState({ + player: MinesStore.getUser(), + enemy: MinesStore.getEnemy() + }); } render() { + + var content = ( +
+ + +
+ ); + + if (!this.state.player.mines || !this.state.player.mines.length) { + content = ( +
+

Waiting for an opponent...

+
+ ); + } + + if (!this.state.player.life || !this.state.enemy.life) { + var winner = this.state.player.life ? this.state.player.username : this.state.enemy.username; + content = ( +
+

Game over. {winner} won.

+
+ ) + } + return (
-

Your Turn

- -
-
-
Enemy Minefield. Click on a block to place a mine.
- -
- - - - - - - -
-
- -
-
{this.state.username}, Your Minefield.
- -
- - - - - - - -
-
-
+ {content}
) } diff --git a/client/src/stores/minestore.js b/client/src/stores/minestore.js index f438fd5..266366c 100644 --- a/client/src/stores/minestore.js +++ b/client/src/stores/minestore.js @@ -18,20 +18,36 @@ var AppConstants = require('../constants/app_constants.js'); * Mines position (x, y) from array can be calculated by,: * x : index of an element / size of minesfield * y : index of an element % size of minesfield + * + * var mines = [ + * 0, -1, 0, 0, 0, 0, 0, + * 0, 0, 0, 2, 0, 0, -1, + * 0, -2, 0, 0, 0, 0, 0, + * 0, 0, 0, -1, 0, 0, 0, + * 0, 0, 0, -1, 0, 0, 0, + * 0, 0, 0, 0, 0, 0, -1, + * 0, 0, 0, 0, 0, 0, -1, + * ]; */ -var mines = [ - 0, -1, 0, 0, 0, 0, 0, - 0, 0, 0, 2, 0, 0, -1, - 0, -2, 0, 0, 0, 0, 0, - 0, 0, 0, -1, 0, 0, 0, - 0, 0, 0, -1, 0, 0, 0, - 0, 0, 0, 0, 0, 0, -1, - 0, 0, 0, 0, 0, 0, -1, -]; +var getMatrix = function(size) { + return Array.apply(null, Array(size * size)).map(Number.prototype.valueOf, -9); +}; /* username */ -var username = ''; +var player = { + 'username' : '', + 'life' : 5, + 'size' : 0 +}; + +var enemy = { + 'username' : '', + 'life' : 5, + 'size' : 0 +}; + +var CHANGE_EVENT = "change"; var MinesStore = assign({}, EventEmitter.prototype, { emitChange: function() { @@ -46,16 +62,20 @@ var MinesStore = assign({}, EventEmitter.prototype, { this.removeListener(CHANGE_EVENT, callback); }, - 'getMines': function() { - return mines; - }, - 'addUsername': function(name) { - username = name; + player.username = name; }, 'getUsername': function() { - return username; + return player.username; + }, + + 'getEnemy': function() { + return enemy; + }, + + 'getUser': function() { + return player; } }); @@ -64,23 +84,44 @@ MinesStore.dispatchToken = AppDispatcher.register(function(payload) { switch(action.type) { case 'registered': - console.log('user registered'); + player.life = action.payload.life; + player.size = action.payload.size; + MinesStore.emitChange(); break; case 'ready': - console.log('ready'); + /* got an opponent */ + enemy.username = action.payload.name; + enemy.life = action.payload.life; + enemy.size = action.payload.size; + /* only when ready, show the minefields */ + enemy.mines = getMatrix(enemy.size); + player.mines = getMatrix(player.size); + MinesStore.emitChange(); break; case 'open': - console.log('open'); + console.log('open', action); break; case 'result': - console.log('result'); + var idx = +action.payload.idx, + life = +action.payload.life, + type = +action.payload.type; + + player.mines[idx] = type; + player.life = life; + MinesStore.emitChange(); break; case 'enemy': - console.log('enemy'); + var idx = +action.payload.idx, + life = +action.payload.life, + type = +action.payload.type; + + enemy.mines[idx] = type; + enemy.life = life; + MinesStore.emitChange(); break; default: diff --git a/client/src/styles/main.css b/client/src/styles/main.css index 4d01e37..b03ad8e 100644 --- a/client/src/styles/main.css +++ b/client/src/styles/main.css @@ -26,24 +26,30 @@ .minefield { width: 50%; text-align: center; + margin-top: 5em; } .minefield__wrapper { width: 80%; margin: auto; } +.minefield__waiting { + text-align: center; + margin-top: 10%; + padding: 4em; +} .minefield__enemy { float: left; } .minefield__user { float: right; } - - - -/* turn */ -.turn { - text-align: center; - margin: 1em; +.minefield__text--instructions { + padding: 0; + margin: 0; + font-family: "1942 report"; +} +.minefield__text--waiting { + font-family: "1942 report"; } /* hearts */ @@ -52,13 +58,13 @@ } - /* life */ .life-status { position: relative; clear: both; text-align: center; padding: 3em; + padding-bottom: 0; } .life-status__active { color: #e74c3c; diff --git a/client/webpack.config.js b/client/webpack.config.js index 11645be..083a509 100644 --- a/client/webpack.config.js +++ b/client/webpack.config.js @@ -16,7 +16,7 @@ module.exports = { path: __dirname + '/dist' }, - debug : false, + debug : true, module: { loaders: [ From 70a9a02395f69073f15a9d3e7e9e33ab8fd1f0aa Mon Sep 17 00:00:00 2001 From: Suyash Katiyar Date: Tue, 14 Jul 2015 05:33:19 +0530 Subject: [PATCH 25/49] Create README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..7569ba4 --- /dev/null +++ b/README.md @@ -0,0 +1,2 @@ +# Entrapped +__Tiny little minefield of our dreams__ From 1445bb457370bbc78ec6c7cba18b918a387aa7d9 Mon Sep 17 00:00:00 2001 From: SKatiyar Date: Tue, 14 Jul 2015 05:33:53 +0530 Subject: [PATCH 26/49] updated readme --- .bkp/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.bkp/README.md b/.bkp/README.md index 784a357..968c772 100644 --- a/.bkp/README.md +++ b/.bkp/README.md @@ -1,2 +1,2 @@ -# Not to see here +# Nothing to see here #### Move along now From 3acaca894650712a8abd105acc9e242304f1b33b Mon Sep 17 00:00:00 2001 From: ghome vic Date: Tue, 14 Jul 2015 05:53:22 +0530 Subject: [PATCH 27/49] Apha 2.0 --- client/src/components/Blocks.jsx | 17 +++++++++++------ client/src/components/Field.jsx | 2 +- client/src/styles/main.css | 8 ++++++-- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/client/src/components/Blocks.jsx b/client/src/components/Blocks.jsx index a736375..a9fd157 100644 --- a/client/src/components/Blocks.jsx +++ b/client/src/components/Blocks.jsx @@ -18,7 +18,8 @@ class Block extends React.Component { render() { var cx = React.addons.classSet; var classes = cx({ - 'block': true, + 'block': this.props.of !== "player", + 'block__enemy': this.props.of === "player", 'block__visited': this.props.status === 0 || this.props.status === 9, 'block__dead': this.props.status === -2 }); @@ -29,12 +30,16 @@ class Block extends React.Component { } handleClick() { + if (this.props.of === "player") { + return; + } + var msg = "data:open:[idx=" + this.props.index + "]:[help=9]"; Api.send(msg); } }; -Block.propTypes = { status: React.PropTypes.number, index: React.PropTypes.number }; -Block.defaultProps = { status: 0, index: 0 }; +Block.propTypes = { status: React.PropTypes.number, index: React.PropTypes.number, of: React.PropTypes.string }; +Block.defaultProps = { status: 0, index: 0, of: null }; class Blocks extends React.Component { constructor(props) { @@ -51,7 +56,7 @@ class Blocks extends React.Component { for (var j = 0; j < size; j++) { var index = i * size + j; - _blocks.push(); + _blocks.push(); } nodes.push(({_blocks})); @@ -66,7 +71,7 @@ class Blocks extends React.Component { ); } }; -Blocks.propTypes = { size: React.PropTypes.number, mines: React.PropTypes.array }; -Blocks.defaultProps = { size: 7, mines: [] } +Blocks.propTypes = { size: React.PropTypes.number, mines: React.PropTypes.array, of: React.PropTypes.string }; +Blocks.defaultProps = { size: 7, mines: [], of: null } export default Blocks; diff --git a/client/src/components/Field.jsx b/client/src/components/Field.jsx index 1f2d64e..850b56c 100644 --- a/client/src/components/Field.jsx +++ b/client/src/components/Field.jsx @@ -28,7 +28,7 @@ class Field extends React.Component { return (
- +
{nodes} diff --git a/client/src/styles/main.css b/client/src/styles/main.css index b03ad8e..7d12915 100644 --- a/client/src/styles/main.css +++ b/client/src/styles/main.css @@ -7,11 +7,16 @@ height: 45px; background-color: #eee; } - .block:hover { background-color: #A8CAC5; } +.block__enemy { + width: 45px; + height: 45px; + background-color: #666; +} + .block__visited { background-color: #C8C8C8; } @@ -21,7 +26,6 @@ } - /* field */ .minefield { width: 50%; From 3096edd391a9b583ff1f6b771c1d8f9bfe671c1b Mon Sep 17 00:00:00 2001 From: ghome vic Date: Tue, 14 Jul 2015 06:01:10 +0530 Subject: [PATCH 28/49] Alpha 3.0 --- client/src/styles/main.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/styles/main.css b/client/src/styles/main.css index 7d12915..99a265c 100644 --- a/client/src/styles/main.css +++ b/client/src/styles/main.css @@ -14,7 +14,7 @@ .block__enemy { width: 45px; height: 45px; - background-color: #666; + background-color: rgba(26, 107, 144, 0.15); } .block__visited { From c64756d37ec7f1c386ce075b77ef92a9c9544867 Mon Sep 17 00:00:00 2001 From: ghome vic Date: Tue, 14 Jul 2015 07:06:22 +0530 Subject: [PATCH 29/49] Heroku --- client/src/components/Blocks.jsx | 3 +++ client/src/components/Field.jsx | 2 +- client/src/templates/index.html | 10 ++++++++-- client/webpack.config.js | 10 +++++----- 4 files changed, 17 insertions(+), 8 deletions(-) diff --git a/client/src/components/Blocks.jsx b/client/src/components/Blocks.jsx index a9fd157..278f016 100644 --- a/client/src/components/Blocks.jsx +++ b/client/src/components/Blocks.jsx @@ -36,6 +36,9 @@ class Block extends React.Component { var msg = "data:open:[idx=" + this.props.index + "]:[help=9]"; Api.send(msg); + + /* beep is a global function intended for fun */ + beep(); } }; Block.propTypes = { status: React.PropTypes.number, index: React.PropTypes.number, of: React.PropTypes.string }; diff --git a/client/src/components/Field.jsx b/client/src/components/Field.jsx index 850b56c..f9e751f 100644 --- a/client/src/components/Field.jsx +++ b/client/src/components/Field.jsx @@ -28,7 +28,7 @@ class Field extends React.Component { return (
- +
{nodes} diff --git a/client/src/templates/index.html b/client/src/templates/index.html index ab9f057..d10bc2d 100644 --- a/client/src/templates/index.html +++ b/client/src/templates/index.html @@ -5,8 +5,14 @@ Webpack + React - + - + + diff --git a/client/webpack.config.js b/client/webpack.config.js index 083a509..fab287a 100644 --- a/client/webpack.config.js +++ b/client/webpack.config.js @@ -12,8 +12,8 @@ module.exports = { ], output: { - filename: 'app.js', - path: __dirname + '/dist' + filename: '/statics/app.js', + path: __dirname + '/dist', }, debug : true, @@ -36,12 +36,12 @@ module.exports = { }, { test: /\.css$/, - loader: "file?name=[name].[ext]", + loader: "file?name=/statics/[name].[ext]", }, { test: /\.ttf$/, - loader: "file?name=[name].[ext]", - } + loader: "file?name=/statics/[name].[ext]", + }, ] }, From b57a11e49a72dd7dd6b9707bb0c5f19a3a7b26b2 Mon Sep 17 00:00:00 2001 From: ghome vic Date: Tue, 14 Jul 2015 07:15:37 +0530 Subject: [PATCH 30/49] Changed api --- client/src/api/api.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/src/api/api.js b/client/src/api/api.js index 4fa7a8e..7983fc6 100644 --- a/client/src/api/api.js +++ b/client/src/api/api.js @@ -5,7 +5,7 @@ var AppDispatcher = require('../dispatchers/app_dispatcher.js'); var _ = require('../../src/utility/utils.js'); -var apiUrl = "ws://192.168.0.103:7000"; +var apiUrl = "ws://entrapped.herokuapp.com"; /* websocket reference */ var conn = null; From 2d04c9a0a3124fe93e96496bd6736fe8a8a18df2 Mon Sep 17 00:00:00 2001 From: SKatiyar Date: Tue, 14 Jul 2015 05:43:15 +0530 Subject: [PATCH 31/49] preparing for deploy --- client/.gitignore | 1 - client/dist/1942.ttf | Bin 0 -> 52168 bytes client/dist/app.js | 28322 ++++++++++++++++ client/dist/index.html | 12 + client/dist/main.css | 101 + {.bkp => server/.bkp}/README.md | 0 .../.bkp}/controllers/controllers.go | 0 .../.bkp}/controllers/minefield.go | 0 {.bkp => server/.bkp}/models/errors.go | 0 {.bkp => server/.bkp}/models/minefield.go | 0 {.bkp => server/.bkp}/models/models.go | 0 {.bkp => server/.bkp}/models/user.go | 0 .gitignore => server/.gitignore | 0 13 files changed, 28435 insertions(+), 1 deletion(-) create mode 100644 client/dist/1942.ttf create mode 100644 client/dist/app.js create mode 100644 client/dist/index.html create mode 100644 client/dist/main.css rename {.bkp => server/.bkp}/README.md (100%) rename {.bkp => server/.bkp}/controllers/controllers.go (100%) rename {.bkp => server/.bkp}/controllers/minefield.go (100%) rename {.bkp => server/.bkp}/models/errors.go (100%) rename {.bkp => server/.bkp}/models/minefield.go (100%) rename {.bkp => server/.bkp}/models/models.go (100%) rename {.bkp => server/.bkp}/models/user.go (100%) rename .gitignore => server/.gitignore (100%) diff --git a/client/.gitignore b/client/.gitignore index de4d1f0..3c3629e 100644 --- a/client/.gitignore +++ b/client/.gitignore @@ -1,2 +1 @@ -dist node_modules diff --git a/client/dist/1942.ttf b/client/dist/1942.ttf new file mode 100644 index 0000000000000000000000000000000000000000..951cf8977fee6b055ac108bad6a79d817cf93b69 GIT binary patch literal 52168 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 0) hot._disposeHandlers.splice(idx, 1); +/******/ }, +/******/ +/******/ // Management API +/******/ check: hotCheck, +/******/ apply: hotApply, +/******/ status: function(l) { +/******/ if(!l) return hotStatus; +/******/ hotStatusHandlers.push(l); +/******/ }, +/******/ addStatusHandler: function(l) { +/******/ hotStatusHandlers.push(l); +/******/ }, +/******/ removeStatusHandler: function(l) { +/******/ var idx = hotStatusHandlers.indexOf(l); +/******/ if(idx >= 0) hotStatusHandlers.splice(idx, 1); +/******/ }, +/******/ +/******/ //inherit from previous dispose call +/******/ data: hotCurrentModuleData[moduleId] +/******/ }; +/******/ return hot; +/******/ } +/******/ +/******/ var hotStatusHandlers = []; +/******/ var hotStatus = "idle"; +/******/ +/******/ function hotSetStatus(newStatus) { +/******/ hotStatus = newStatus; +/******/ for(var i = 0; i < hotStatusHandlers.length; i++) +/******/ hotStatusHandlers[i].call(null, newStatus); +/******/ } +/******/ +/******/ // while downloading +/******/ var hotWaitingFiles = 0; +/******/ var hotChunksLoading = 0; +/******/ var hotWaitingFilesMap = {}; +/******/ var hotRequestedFilesMap = {}; +/******/ var hotAvailibleFilesMap = {}; +/******/ var hotCallback; +/******/ +/******/ // The update info +/******/ var hotUpdate, hotUpdateNewHash; +/******/ +/******/ function toModuleId(id) { +/******/ return (+id) + "" === id ? +id : id; +/******/ } +/******/ +/******/ function hotCheck(apply, callback) { +/******/ if(hotStatus !== "idle") throw new Error("check() is only allowed in idle status"); +/******/ if(typeof apply === "function") { +/******/ hotApplyOnUpdate = false; +/******/ callback = apply; +/******/ } else { +/******/ hotApplyOnUpdate = apply; +/******/ callback = callback || function(err) { if(err) throw err; }; +/******/ } +/******/ hotSetStatus("check"); +/******/ hotDownloadManifest(function(err, update) { +/******/ if(err) return callback(err); +/******/ if(!update) { +/******/ hotSetStatus("idle"); +/******/ callback(null, null); +/******/ return; +/******/ } +/******/ +/******/ hotRequestedFilesMap = {}; +/******/ hotAvailibleFilesMap = {}; +/******/ hotWaitingFilesMap = {}; +/******/ for(var i = 0; i < update.c.length; i++) +/******/ hotAvailibleFilesMap[update.c[i]] = true; +/******/ hotUpdateNewHash = update.h; +/******/ +/******/ hotSetStatus("prepare"); +/******/ hotCallback = callback; +/******/ hotUpdate = {}; +/******/ var chunkId = 0; { // eslint-disable-line no-lone-blocks +/******/ /*globals chunkId */ +/******/ hotEnsureUpdateChunk(chunkId); +/******/ } +/******/ if(hotStatus === "prepare" && hotChunksLoading === 0 && hotWaitingFiles === 0) { +/******/ hotUpdateDownloaded(); +/******/ } +/******/ }); +/******/ } +/******/ +/******/ function hotAddUpdateChunk(chunkId, moreModules) { // eslint-disable-line no-unused-vars +/******/ if(!hotAvailibleFilesMap[chunkId] || !hotRequestedFilesMap[chunkId]) +/******/ return; +/******/ hotRequestedFilesMap[chunkId] = false; +/******/ for(var moduleId in moreModules) { +/******/ if(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) { +/******/ hotUpdate[moduleId] = moreModules[moduleId]; +/******/ } +/******/ } +/******/ if(--hotWaitingFiles === 0 && hotChunksLoading === 0) { +/******/ hotUpdateDownloaded(); +/******/ } +/******/ } +/******/ +/******/ function hotEnsureUpdateChunk(chunkId) { +/******/ if(!hotAvailibleFilesMap[chunkId]) { +/******/ hotWaitingFilesMap[chunkId] = true; +/******/ } else { +/******/ hotRequestedFilesMap[chunkId] = true; +/******/ hotWaitingFiles++; +/******/ hotDownloadUpdateChunk(chunkId); +/******/ } +/******/ } +/******/ +/******/ function hotUpdateDownloaded() { +/******/ hotSetStatus("ready"); +/******/ var callback = hotCallback; +/******/ hotCallback = null; +/******/ if(!callback) return; +/******/ if(hotApplyOnUpdate) { +/******/ hotApply(hotApplyOnUpdate, callback); +/******/ } else { +/******/ var outdatedModules = []; +/******/ for(var id in hotUpdate) { +/******/ if(Object.prototype.hasOwnProperty.call(hotUpdate, id)) { +/******/ outdatedModules.push(toModuleId(id)); +/******/ } +/******/ } +/******/ callback(null, outdatedModules); +/******/ } +/******/ } +/******/ +/******/ function hotApply(options, callback) { +/******/ if(hotStatus !== "ready") throw new Error("apply() is only allowed in ready status"); +/******/ if(typeof options === "function") { +/******/ callback = options; +/******/ options = {}; +/******/ } else if(options && typeof options === "object") { +/******/ callback = callback || function(err) { if(err) throw err; }; +/******/ } else { +/******/ options = {}; +/******/ callback = callback || function(err) { if(err) throw err; }; +/******/ } +/******/ +/******/ function getAffectedStuff(module) { +/******/ var outdatedModules = [module]; +/******/ var outdatedDependencies = {}; +/******/ +/******/ var queue = outdatedModules.slice(); +/******/ while(queue.length > 0) { +/******/ var moduleId = queue.pop(); +/******/ var module = installedModules[moduleId]; +/******/ if(!module || module.hot._selfAccepted) +/******/ continue; +/******/ if(module.hot._selfDeclined) { +/******/ return new Error("Aborted because of self decline: " + moduleId); +/******/ } +/******/ if(moduleId === 0) { +/******/ return; +/******/ } +/******/ for(var i = 0; i < module.parents.length; i++) { +/******/ var parentId = module.parents[i]; +/******/ var parent = installedModules[parentId]; +/******/ if(parent.hot._declinedDependencies[moduleId]) { +/******/ return new Error("Aborted because of declined dependency: " + moduleId + " in " + parentId); +/******/ } +/******/ if(outdatedModules.indexOf(parentId) >= 0) continue; +/******/ if(parent.hot._acceptedDependencies[moduleId]) { +/******/ if(!outdatedDependencies[parentId]) +/******/ outdatedDependencies[parentId] = []; +/******/ addAllToSet(outdatedDependencies[parentId], [moduleId]); +/******/ continue; +/******/ } +/******/ delete outdatedDependencies[parentId]; +/******/ outdatedModules.push(parentId); +/******/ queue.push(parentId); +/******/ } +/******/ } +/******/ +/******/ return [outdatedModules, outdatedDependencies]; +/******/ } +/******/ function addAllToSet(a, b) { +/******/ for(var i = 0; i < b.length; i++) { +/******/ var item = b[i]; +/******/ if(a.indexOf(item) < 0) +/******/ a.push(item); +/******/ } +/******/ } +/******/ +/******/ // at begin all updates modules are outdated +/******/ // the "outdated" status can propagate to parents if they don't accept the children +/******/ var outdatedDependencies = {}; +/******/ var outdatedModules = []; +/******/ var appliedUpdate = {}; +/******/ for(var id in hotUpdate) { +/******/ if(Object.prototype.hasOwnProperty.call(hotUpdate, id)) { +/******/ var moduleId = toModuleId(id); +/******/ var result = getAffectedStuff(moduleId); +/******/ if(!result) { +/******/ if(options.ignoreUnaccepted) +/******/ continue; +/******/ hotSetStatus("abort"); +/******/ return callback(new Error("Aborted because " + moduleId + " is not accepted")); +/******/ } +/******/ if(result instanceof Error) { +/******/ hotSetStatus("abort"); +/******/ return callback(result); +/******/ } +/******/ appliedUpdate[moduleId] = hotUpdate[moduleId]; +/******/ addAllToSet(outdatedModules, result[0]); +/******/ for(var moduleId in result[1]) { +/******/ if(Object.prototype.hasOwnProperty.call(result[1], moduleId)) { +/******/ if(!outdatedDependencies[moduleId]) +/******/ outdatedDependencies[moduleId] = []; +/******/ addAllToSet(outdatedDependencies[moduleId], result[1][moduleId]); +/******/ } +/******/ } +/******/ } +/******/ } +/******/ +/******/ // Store self accepted outdated modules to require them later by the module system +/******/ var outdatedSelfAcceptedModules = []; +/******/ for(var i = 0; i < outdatedModules.length; i++) { +/******/ var moduleId = outdatedModules[i]; +/******/ if(installedModules[moduleId] && installedModules[moduleId].hot._selfAccepted) +/******/ outdatedSelfAcceptedModules.push({ +/******/ module: moduleId, +/******/ errorHandler: installedModules[moduleId].hot._selfAccepted +/******/ }); +/******/ } +/******/ +/******/ // Now in "dispose" phase +/******/ hotSetStatus("dispose"); +/******/ var queue = outdatedModules.slice(); +/******/ while(queue.length > 0) { +/******/ var moduleId = queue.pop(); +/******/ var module = installedModules[moduleId]; +/******/ if(!module) continue; +/******/ +/******/ var data = {}; +/******/ +/******/ // Call dispose handlers +/******/ var disposeHandlers = module.hot._disposeHandlers; +/******/ for(var j = 0; j < disposeHandlers.length; j++) { +/******/ var cb = disposeHandlers[j]; +/******/ cb(data); +/******/ } +/******/ hotCurrentModuleData[moduleId] = data; +/******/ +/******/ // disable module (this disables requires from this module) +/******/ module.hot.active = false; +/******/ +/******/ // remove module from cache +/******/ delete installedModules[moduleId]; +/******/ +/******/ // remove "parents" references from all children +/******/ for(var j = 0; j < module.children.length; j++) { +/******/ var child = installedModules[module.children[j]]; +/******/ if(!child) continue; +/******/ var idx = child.parents.indexOf(moduleId); +/******/ if(idx >= 0) { +/******/ child.parents.splice(idx, 1); +/******/ } +/******/ } +/******/ } +/******/ +/******/ // remove outdated dependency from module children +/******/ for(var moduleId in outdatedDependencies) { +/******/ if(Object.prototype.hasOwnProperty.call(outdatedDependencies, moduleId)) { +/******/ var module = installedModules[moduleId]; +/******/ var moduleOutdatedDependencies = outdatedDependencies[moduleId]; +/******/ for(var j = 0; j < moduleOutdatedDependencies.length; j++) { +/******/ var dependency = moduleOutdatedDependencies[j]; +/******/ var idx = module.children.indexOf(dependency); +/******/ if(idx >= 0) module.children.splice(idx, 1); +/******/ } +/******/ } +/******/ } +/******/ +/******/ // Not in "apply" phase +/******/ hotSetStatus("apply"); +/******/ +/******/ hotCurrentHash = hotUpdateNewHash; +/******/ +/******/ // insert new code +/******/ for(var moduleId in appliedUpdate) { +/******/ if(Object.prototype.hasOwnProperty.call(appliedUpdate, moduleId)) { +/******/ modules[moduleId] = appliedUpdate[moduleId]; +/******/ } +/******/ } +/******/ +/******/ // call accept handlers +/******/ var error = null; +/******/ for(var moduleId in outdatedDependencies) { +/******/ if(Object.prototype.hasOwnProperty.call(outdatedDependencies, moduleId)) { +/******/ var module = installedModules[moduleId]; +/******/ var moduleOutdatedDependencies = outdatedDependencies[moduleId]; +/******/ var callbacks = []; +/******/ for(var i = 0; i < moduleOutdatedDependencies.length; i++) { +/******/ var dependency = moduleOutdatedDependencies[i]; +/******/ var cb = module.hot._acceptedDependencies[dependency]; +/******/ if(callbacks.indexOf(cb) >= 0) continue; +/******/ callbacks.push(cb); +/******/ } +/******/ for(var i = 0; i < callbacks.length; i++) { +/******/ var cb = callbacks[i]; +/******/ try { +/******/ cb(outdatedDependencies); +/******/ } catch(err) { +/******/ if(!error) +/******/ error = err; +/******/ } +/******/ } +/******/ } +/******/ } +/******/ +/******/ // Load self accepted modules +/******/ for(var i = 0; i < outdatedSelfAcceptedModules.length; i++) { +/******/ var item = outdatedSelfAcceptedModules[i]; +/******/ var moduleId = item.module; +/******/ hotCurrentParents = [moduleId]; +/******/ try { +/******/ __webpack_require__(moduleId); +/******/ } catch(err) { +/******/ if(typeof item.errorHandler === "function") { +/******/ try { +/******/ item.errorHandler(err); +/******/ } catch(err) { +/******/ if(!error) +/******/ error = err; +/******/ } +/******/ } else if(!error) +/******/ error = err; +/******/ } +/******/ } +/******/ +/******/ // handle errors in accept handlers and self accepted module load +/******/ if(error) { +/******/ hotSetStatus("fail"); +/******/ return callback(error); +/******/ } +/******/ +/******/ hotSetStatus("idle"); +/******/ callback(null, outdatedModules); +/******/ } + +/******/ // The module cache +/******/ var installedModules = {}; + +/******/ // The require function +/******/ function __webpack_require__(moduleId) { + +/******/ // Check if module is in cache +/******/ if(installedModules[moduleId]) +/******/ return installedModules[moduleId].exports; + +/******/ // Create a new module (and put it into the cache) +/******/ var module = installedModules[moduleId] = { +/******/ exports: {}, +/******/ id: moduleId, +/******/ loaded: false, +/******/ hot: hotCreateModule(moduleId), +/******/ parents: hotCurrentParents, +/******/ children: [] +/******/ }; + +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, hotCreateRequire(moduleId)); + +/******/ // Flag the module as loaded +/******/ module.loaded = true; + +/******/ // Return the exports of the module +/******/ return module.exports; +/******/ } + + +/******/ // expose the modules object (__webpack_modules__) +/******/ __webpack_require__.m = modules; + +/******/ // expose the module cache +/******/ __webpack_require__.c = installedModules; + +/******/ // __webpack_public_path__ +/******/ __webpack_require__.p = ""; + +/******/ // __webpack_hash__ +/******/ __webpack_require__.h = function() { return hotCurrentHash; }; + +/******/ // Load entry module and return exports +/******/ return hotCreateRequire(0)(0); +/******/ }) +/************************************************************************/ +/******/ ([ +/* 0 */ +/***/ function(module, exports, __webpack_require__) { + + __webpack_require__(1); + __webpack_require__(3); + __webpack_require__(245); + __webpack_require__(246); + module.exports = __webpack_require__(247); + + +/***/ }, +/* 1 */ +/***/ function(module, exports, __webpack_require__) { + + /* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra + */ + /*globals window __webpack_hash__ */ + if(true) { + var lastData; + var upToDate = function upToDate() { + return lastData.indexOf(__webpack_require__.h()) >= 0; + }; + var check = function check() { + module.hot.check(function(err, updatedModules) { + if(err) { + if(module.hot.status() in {abort: 1, fail: 1}) { + console.warn("[HMR] Cannot check for update. Need to do a full reload!"); + console.warn("[HMR] " + err.stack || err.message); + } else { + console.warn("[HMR] Update check failed: " + err.stack || err.message); + } + return; + } + + if(!updatedModules) { + console.warn("[HMR] Cannot find update. Need to do a full reload!"); + console.warn("[HMR] (Probably because of restarting the webpack-dev-server)"); + return; + } + + module.hot.apply({ + ignoreUnaccepted: true + }, function(err, renewedModules) { + if(err) { + if(module.hot.status() in {abort: 1, fail: 1}) { + console.warn("[HMR] Cannot apply update. Need to do a full reload!"); + console.warn("[HMR] " + err.stack || err.message); + } else { + console.warn("[HMR] Update failed: " + err.stack || err.message); + } + return; + } + + if(!upToDate()) { + check(); + } + + __webpack_require__(2)(updatedModules, renewedModules); + + if(upToDate()) { + console.log("[HMR] App is up to date."); + } + }); + }); + }; + var addEventListener = window.addEventListener ? function(eventName, listener) { + window.addEventListener(eventName, listener, false); + } : function (eventName, listener) { + window.attachEvent("on" + eventName, listener); + }; + addEventListener("message", function(event) { + if(typeof event.data === "string" && event.data.indexOf("webpackHotUpdate") === 0) { + lastData = event.data; + if(!upToDate() && module.hot.status() === "idle") { + console.log("[HMR] Checking for updates on the server..."); + check(); + } + } + }); + console.log("[HMR] Waiting for update signal from WDS..."); + } else { + throw new Error("[HMR] Hot Module Replacement is disabled."); + } + + +/***/ }, +/* 2 */ +/***/ function(module, exports) { + + /* + MIT License http://www.opensource.org/licenses/mit-license.php + Author Tobias Koppers @sokra + */ + module.exports = function(updatedModules, renewedModules) { + var unacceptedModules = updatedModules.filter(function(moduleId) { + return renewedModules && renewedModules.indexOf(moduleId) < 0; + }); + + if(unacceptedModules.length > 0) { + console.warn("[HMR] The following modules couldn't be hot updated: (They would need a full reload!)"); + unacceptedModules.forEach(function(moduleId) { + console.warn("[HMR] - " + moduleId); + }); + } + + if(!renewedModules || renewedModules.length === 0) { + console.log("[HMR] Nothing hot updated."); + } else { + console.log("[HMR] Updated modules:"); + renewedModules.forEach(function(moduleId) { + console.log("[HMR] - " + moduleId); + }); + } + }; + + +/***/ }, +/* 3 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(module) {/* REACT HOT LOADER */ if (true) { (function () { var ReactHotAPI = __webpack_require__(202), RootInstanceProvider = __webpack_require__(200), ReactMount = __webpack_require__(74), React = __webpack_require__(9); module.makeHot = module.hot.data ? module.hot.data.makeHot : ReactHotAPI(function () { return RootInstanceProvider.getRootInstances(ReactMount); }, React); })(); } (function () { + + 'use strict'; + + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + + var _react = __webpack_require__(9); + + var _react2 = _interopRequireDefault(_react); + + var _reactRouter = __webpack_require__(5); + + var _reactRouter2 = _interopRequireDefault(_reactRouter); + + var _componentsHomeJsx = __webpack_require__(210); + + var _componentsHomeJsx2 = _interopRequireDefault(_componentsHomeJsx); + + var _componentsMinefieldJsx = __webpack_require__(222); + + var _componentsMinefieldJsx2 = _interopRequireDefault(_componentsMinefieldJsx); + + var App = _react2['default'].createClass({ + displayName: 'App', + + render: function render() { + return _react2['default'].createElement(_reactRouter.RouteHandler, null); + } + }); + + var Routes = _react2['default'].createElement( + _reactRouter.Route, + { name: 'app', path: '/', handler: App }, + _react2['default'].createElement(_reactRouter.Route, { name: 'home', path: '/home', handler: _componentsHomeJsx2['default'] }), + _react2['default'].createElement(_reactRouter.Route, { name: 'minefield', path: '/minefield', handler: _componentsMinefieldJsx2['default'] }), + _react2['default'].createElement(_reactRouter.DefaultRoute, { handler: _componentsHomeJsx2['default'] }) + ); + + _reactRouter2['default'].run(Routes, function (Handler) { + _react2['default'].render(_react2['default'].createElement(Handler, null), document.body); + }); + + /* REACT HOT LOADER */ }).call(this); if (true) { (function () { module.hot.dispose(function (data) { data.makeHot = module.makeHot; }); if (module.exports && module.makeHot) { var makeExportsHot = __webpack_require__(218), foundReactClasses = false; if (makeExportsHot(module, __webpack_require__(9))) { foundReactClasses = true; } var shouldAcceptModule = true && foundReactClasses; if (shouldAcceptModule) { module.hot.accept(function (err) { if (err) { console.error("Cannot not apply hot update to " + "app.jsx" + ": " + err.message); } }); } } })(); } + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(4)(module))) + +/***/ }, +/* 4 */ +/***/ function(module, exports) { + + module.exports = function(module) { + if(!module.webpackPolyfill) { + module.deprecate = function() {}; + module.paths = []; + // module.parent = undefined by default + module.children = []; + module.webpackPolyfill = 1; + } + return module; + } + + +/***/ }, +/* 5 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + exports.DefaultRoute = __webpack_require__(6); + exports.Link = __webpack_require__(175); + exports.NotFoundRoute = __webpack_require__(176); + exports.Redirect = __webpack_require__(177); + exports.Route = __webpack_require__(174); + exports.ActiveHandler = __webpack_require__(172); + exports.RouteHandler = exports.ActiveHandler; + + exports.HashLocation = __webpack_require__(178); + exports.HistoryLocation = __webpack_require__(181); + exports.RefreshLocation = __webpack_require__(182); + exports.StaticLocation = __webpack_require__(183); + exports.TestLocation = __webpack_require__(184); + + exports.ImitateBrowserBehavior = __webpack_require__(185); + exports.ScrollToTopBehavior = __webpack_require__(186); + + exports.History = __webpack_require__(180); + exports.Navigation = __webpack_require__(187); + exports.State = __webpack_require__(188); + + exports.createRoute = __webpack_require__(164).createRoute; + exports.createDefaultRoute = __webpack_require__(164).createDefaultRoute; + exports.createNotFoundRoute = __webpack_require__(164).createNotFoundRoute; + exports.createRedirect = __webpack_require__(164).createRedirect; + exports.createRoutesFromReactChildren = __webpack_require__(189); + + exports.create = __webpack_require__(190); + exports.run = __webpack_require__(199); + +/***/ }, +/* 6 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + var _classCallCheck = function (instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }; + + var _inherits = function (subClass, superClass) { if (typeof superClass !== 'function' && superClass !== null) { throw new TypeError('Super expression must either be null or a function, not ' + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) subClass.__proto__ = superClass; }; + + var PropTypes = __webpack_require__(7); + var RouteHandler = __webpack_require__(172); + var Route = __webpack_require__(174); + + /** + * A component is a special kind of that + * renders when its parent matches but none of its siblings do. + * Only one such route may be used at any given level in the + * route hierarchy. + */ + + var DefaultRoute = (function (_Route) { + function DefaultRoute() { + _classCallCheck(this, DefaultRoute); + + if (_Route != null) { + _Route.apply(this, arguments); + } + } + + _inherits(DefaultRoute, _Route); + + return DefaultRoute; + })(Route); + + // TODO: Include these in the above class definition + // once we can use ES7 property initializers. + // https://github.com/babel/babel/issues/619 + + DefaultRoute.propTypes = { + name: PropTypes.string, + path: PropTypes.falsy, + children: PropTypes.falsy, + handler: PropTypes.func.isRequired + }; + + DefaultRoute.defaultProps = { + handler: RouteHandler + }; + + module.exports = DefaultRoute; + +/***/ }, +/* 7 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + var assign = __webpack_require__(8); + var ReactPropTypes = __webpack_require__(9).PropTypes; + var Route = __webpack_require__(164); + + var PropTypes = assign({}, ReactPropTypes, { + + /** + * Indicates that a prop should be falsy. + */ + falsy: function falsy(props, propName, componentName) { + if (props[propName]) { + return new Error('<' + componentName + '> should not have a "' + propName + '" prop'); + } + }, + + /** + * Indicates that a prop should be a Route object. + */ + route: ReactPropTypes.instanceOf(Route), + + /** + * Indicates that a prop should be a Router object. + */ + //router: ReactPropTypes.instanceOf(Router) // TODO + router: ReactPropTypes.func + + }); + + module.exports = PropTypes; + +/***/ }, +/* 8 */ +/***/ function(module, exports) { + + /** + * Copyright 2014-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule Object.assign + */ + + // https://people.mozilla.org/~jorendorff/es6-draft.html#sec-object.assign + + 'use strict'; + + function assign(target, sources) { + if (target == null) { + throw new TypeError('Object.assign target cannot be null or undefined'); + } + + var to = Object(target); + var hasOwnProperty = Object.prototype.hasOwnProperty; + + for (var nextIndex = 1; nextIndex < arguments.length; nextIndex++) { + var nextSource = arguments[nextIndex]; + if (nextSource == null) { + continue; + } + + var from = Object(nextSource); + + // We don't currently support accessors nor proxies. Therefore this + // copy cannot throw. If we ever supported this then we must handle + // exceptions and side-effects. We don't support symbols so they won't + // be transferred. + + for (var key in from) { + if (hasOwnProperty.call(from, key)) { + to[key] = from[key]; + } + } + } + + return to; + } + + module.exports = assign; + + +/***/ }, +/* 9 */ +/***/ function(module, exports, __webpack_require__) { + + module.exports = __webpack_require__(10); + + +/***/ }, +/* 10 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule React + */ + + /* globals __REACT_DEVTOOLS_GLOBAL_HOOK__*/ + + 'use strict'; + + var EventPluginUtils = __webpack_require__(12); + var ReactChildren = __webpack_require__(16); + var ReactComponent = __webpack_require__(29); + var ReactClass = __webpack_require__(44); + var ReactContext = __webpack_require__(20); + var ReactCurrentOwner = __webpack_require__(24); + var ReactElement = __webpack_require__(19); + var ReactElementValidator = __webpack_require__(37); + var ReactDOM = __webpack_require__(47); + var ReactDOMTextComponent = __webpack_require__(49); + var ReactDefaultInjection = __webpack_require__(98); + var ReactInstanceHandles = __webpack_require__(27); + var ReactMount = __webpack_require__(74); + var ReactPerf = __webpack_require__(33); + var ReactPropTypes = __webpack_require__(129); + var ReactReconciler = __webpack_require__(34); + var ReactServerRendering = __webpack_require__(161); + + var assign = __webpack_require__(8); + var findDOMNode = __webpack_require__(118); + var onlyChild = __webpack_require__(163); + + ReactDefaultInjection.inject(); + + var createElement = ReactElement.createElement; + var createFactory = ReactElement.createFactory; + var cloneElement = ReactElement.cloneElement; + + if ("production" !== process.env.NODE_ENV) { + createElement = ReactElementValidator.createElement; + createFactory = ReactElementValidator.createFactory; + cloneElement = ReactElementValidator.cloneElement; + } + + var render = ReactPerf.measure('React', 'render', ReactMount.render); + + var React = { + Children: { + map: ReactChildren.map, + forEach: ReactChildren.forEach, + count: ReactChildren.count, + only: onlyChild + }, + Component: ReactComponent, + DOM: ReactDOM, + PropTypes: ReactPropTypes, + initializeTouchEvents: function(shouldUseTouch) { + EventPluginUtils.useTouchEvents = shouldUseTouch; + }, + createClass: ReactClass.createClass, + createElement: createElement, + cloneElement: cloneElement, + createFactory: createFactory, + createMixin: function(mixin) { + // Currently a noop. Will be used to validate and trace mixins. + return mixin; + }, + constructAndRenderComponent: ReactMount.constructAndRenderComponent, + constructAndRenderComponentByID: ReactMount.constructAndRenderComponentByID, + findDOMNode: findDOMNode, + render: render, + renderToString: ReactServerRendering.renderToString, + renderToStaticMarkup: ReactServerRendering.renderToStaticMarkup, + unmountComponentAtNode: ReactMount.unmountComponentAtNode, + isValidElement: ReactElement.isValidElement, + withContext: ReactContext.withContext, + + // Hook for JSX spread, don't use this for anything else. + __spread: assign + }; + + // Inject the runtime into a devtools global hook regardless of browser. + // Allows for debugging when the hook is injected on the page. + if ( + typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ !== 'undefined' && + typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.inject === 'function') { + __REACT_DEVTOOLS_GLOBAL_HOOK__.inject({ + CurrentOwner: ReactCurrentOwner, + InstanceHandles: ReactInstanceHandles, + Mount: ReactMount, + Reconciler: ReactReconciler, + TextComponent: ReactDOMTextComponent + }); + } + + if ("production" !== process.env.NODE_ENV) { + var ExecutionEnvironment = __webpack_require__(58); + if (ExecutionEnvironment.canUseDOM && window.top === window.self) { + + // If we're in Chrome, look for the devtools marker and provide a download + // link if not installed. + if (navigator.userAgent.indexOf('Chrome') > -1) { + if (typeof __REACT_DEVTOOLS_GLOBAL_HOOK__ === 'undefined') { + console.debug( + 'Download the React DevTools for a better development experience: ' + + 'https://fb.me/react-devtools' + ); + } + } + + var expectedFeatures = [ + // shims + Array.isArray, + Array.prototype.every, + Array.prototype.forEach, + Array.prototype.indexOf, + Array.prototype.map, + Date.now, + Function.prototype.bind, + Object.keys, + String.prototype.split, + String.prototype.trim, + + // shams + Object.create, + Object.freeze + ]; + + for (var i = 0; i < expectedFeatures.length; i++) { + if (!expectedFeatures[i]) { + console.error( + 'One or more ES5 shim/shams expected by React are not available: ' + + 'https://fb.me/react-warning-polyfills' + ); + break; + } + } + } + } + + React.version = '0.13.3'; + + module.exports = React; + + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(11))) + +/***/ }, +/* 11 */ +/***/ function(module, exports) { + + // shim for using process in browser + + var process = module.exports = {}; + var queue = []; + var draining = false; + var currentQueue; + var queueIndex = -1; + + function cleanUpNextTick() { + draining = false; + if (currentQueue.length) { + queue = currentQueue.concat(queue); + } else { + queueIndex = -1; + } + if (queue.length) { + drainQueue(); + } + } + + function drainQueue() { + if (draining) { + return; + } + var timeout = setTimeout(cleanUpNextTick); + draining = true; + + var len = queue.length; + while(len) { + currentQueue = queue; + queue = []; + while (++queueIndex < len) { + currentQueue[queueIndex].run(); + } + queueIndex = -1; + len = queue.length; + } + currentQueue = null; + draining = false; + clearTimeout(timeout); + } + + process.nextTick = function (fun) { + var args = new Array(arguments.length - 1); + if (arguments.length > 1) { + for (var i = 1; i < arguments.length; i++) { + args[i - 1] = arguments[i]; + } + } + queue.push(new Item(fun, args)); + if (queue.length === 1 && !draining) { + setTimeout(drainQueue, 0); + } + }; + + // v8 likes predictible objects + function Item(fun, array) { + this.fun = fun; + this.array = array; + } + Item.prototype.run = function () { + this.fun.apply(null, this.array); + }; + process.title = 'browser'; + process.browser = true; + process.env = {}; + process.argv = []; + process.version = ''; // empty string to avoid regexp issues + process.versions = {}; + + function noop() {} + + process.on = noop; + process.addListener = noop; + process.once = noop; + process.off = noop; + process.removeListener = noop; + process.removeAllListeners = noop; + process.emit = noop; + + process.binding = function (name) { + throw new Error('process.binding is not supported'); + }; + + // TODO(shtylman) + process.cwd = function () { return '/' }; + process.chdir = function (dir) { + throw new Error('process.chdir is not supported'); + }; + process.umask = function() { return 0; }; + + +/***/ }, +/* 12 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule EventPluginUtils + */ + + 'use strict'; + + var EventConstants = __webpack_require__(13); + + var invariant = __webpack_require__(15); + + /** + * Injected dependencies: + */ + + /** + * - `Mount`: [required] Module that can convert between React dom IDs and + * actual node references. + */ + var injection = { + Mount: null, + injectMount: function(InjectedMount) { + injection.Mount = InjectedMount; + if ("production" !== process.env.NODE_ENV) { + ("production" !== process.env.NODE_ENV ? invariant( + InjectedMount && InjectedMount.getNode, + 'EventPluginUtils.injection.injectMount(...): Injected Mount module ' + + 'is missing getNode.' + ) : invariant(InjectedMount && InjectedMount.getNode)); + } + } + }; + + var topLevelTypes = EventConstants.topLevelTypes; + + function isEndish(topLevelType) { + return topLevelType === topLevelTypes.topMouseUp || + topLevelType === topLevelTypes.topTouchEnd || + topLevelType === topLevelTypes.topTouchCancel; + } + + function isMoveish(topLevelType) { + return topLevelType === topLevelTypes.topMouseMove || + topLevelType === topLevelTypes.topTouchMove; + } + function isStartish(topLevelType) { + return topLevelType === topLevelTypes.topMouseDown || + topLevelType === topLevelTypes.topTouchStart; + } + + + var validateEventDispatches; + if ("production" !== process.env.NODE_ENV) { + validateEventDispatches = function(event) { + var dispatchListeners = event._dispatchListeners; + var dispatchIDs = event._dispatchIDs; + + var listenersIsArr = Array.isArray(dispatchListeners); + var idsIsArr = Array.isArray(dispatchIDs); + var IDsLen = idsIsArr ? dispatchIDs.length : dispatchIDs ? 1 : 0; + var listenersLen = listenersIsArr ? + dispatchListeners.length : + dispatchListeners ? 1 : 0; + + ("production" !== process.env.NODE_ENV ? invariant( + idsIsArr === listenersIsArr && IDsLen === listenersLen, + 'EventPluginUtils: Invalid `event`.' + ) : invariant(idsIsArr === listenersIsArr && IDsLen === listenersLen)); + }; + } + + /** + * Invokes `cb(event, listener, id)`. Avoids using call if no scope is + * provided. The `(listener,id)` pair effectively forms the "dispatch" but are + * kept separate to conserve memory. + */ + function forEachEventDispatch(event, cb) { + var dispatchListeners = event._dispatchListeners; + var dispatchIDs = event._dispatchIDs; + if ("production" !== process.env.NODE_ENV) { + validateEventDispatches(event); + } + if (Array.isArray(dispatchListeners)) { + for (var i = 0; i < dispatchListeners.length; i++) { + if (event.isPropagationStopped()) { + break; + } + // Listeners and IDs are two parallel arrays that are always in sync. + cb(event, dispatchListeners[i], dispatchIDs[i]); + } + } else if (dispatchListeners) { + cb(event, dispatchListeners, dispatchIDs); + } + } + + /** + * Default implementation of PluginModule.executeDispatch(). + * @param {SyntheticEvent} SyntheticEvent to handle + * @param {function} Application-level callback + * @param {string} domID DOM id to pass to the callback. + */ + function executeDispatch(event, listener, domID) { + event.currentTarget = injection.Mount.getNode(domID); + var returnValue = listener(event, domID); + event.currentTarget = null; + return returnValue; + } + + /** + * Standard/simple iteration through an event's collected dispatches. + */ + function executeDispatchesInOrder(event, cb) { + forEachEventDispatch(event, cb); + event._dispatchListeners = null; + event._dispatchIDs = null; + } + + /** + * Standard/simple iteration through an event's collected dispatches, but stops + * at the first dispatch execution returning true, and returns that id. + * + * @return id of the first dispatch execution who's listener returns true, or + * null if no listener returned true. + */ + function executeDispatchesInOrderStopAtTrueImpl(event) { + var dispatchListeners = event._dispatchListeners; + var dispatchIDs = event._dispatchIDs; + if ("production" !== process.env.NODE_ENV) { + validateEventDispatches(event); + } + if (Array.isArray(dispatchListeners)) { + for (var i = 0; i < dispatchListeners.length; i++) { + if (event.isPropagationStopped()) { + break; + } + // Listeners and IDs are two parallel arrays that are always in sync. + if (dispatchListeners[i](event, dispatchIDs[i])) { + return dispatchIDs[i]; + } + } + } else if (dispatchListeners) { + if (dispatchListeners(event, dispatchIDs)) { + return dispatchIDs; + } + } + return null; + } + + /** + * @see executeDispatchesInOrderStopAtTrueImpl + */ + function executeDispatchesInOrderStopAtTrue(event) { + var ret = executeDispatchesInOrderStopAtTrueImpl(event); + event._dispatchIDs = null; + event._dispatchListeners = null; + return ret; + } + + /** + * Execution of a "direct" dispatch - there must be at most one dispatch + * accumulated on the event or it is considered an error. It doesn't really make + * sense for an event with multiple dispatches (bubbled) to keep track of the + * return values at each dispatch execution, but it does tend to make sense when + * dealing with "direct" dispatches. + * + * @return The return value of executing the single dispatch. + */ + function executeDirectDispatch(event) { + if ("production" !== process.env.NODE_ENV) { + validateEventDispatches(event); + } + var dispatchListener = event._dispatchListeners; + var dispatchID = event._dispatchIDs; + ("production" !== process.env.NODE_ENV ? invariant( + !Array.isArray(dispatchListener), + 'executeDirectDispatch(...): Invalid `event`.' + ) : invariant(!Array.isArray(dispatchListener))); + var res = dispatchListener ? + dispatchListener(event, dispatchID) : + null; + event._dispatchListeners = null; + event._dispatchIDs = null; + return res; + } + + /** + * @param {SyntheticEvent} event + * @return {bool} True iff number of dispatches accumulated is greater than 0. + */ + function hasDispatches(event) { + return !!event._dispatchListeners; + } + + /** + * General utilities that are useful in creating custom Event Plugins. + */ + var EventPluginUtils = { + isEndish: isEndish, + isMoveish: isMoveish, + isStartish: isStartish, + + executeDirectDispatch: executeDirectDispatch, + executeDispatch: executeDispatch, + executeDispatchesInOrder: executeDispatchesInOrder, + executeDispatchesInOrderStopAtTrue: executeDispatchesInOrderStopAtTrue, + hasDispatches: hasDispatches, + injection: injection, + useTouchEvents: false + }; + + module.exports = EventPluginUtils; + + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(11))) + +/***/ }, +/* 13 */ +/***/ function(module, exports, __webpack_require__) { + + /** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule EventConstants + */ + + 'use strict'; + + var keyMirror = __webpack_require__(14); + + var PropagationPhases = keyMirror({bubbled: null, captured: null}); + + /** + * Types of raw signals from the browser caught at the top level. + */ + var topLevelTypes = keyMirror({ + topBlur: null, + topChange: null, + topClick: null, + topCompositionEnd: null, + topCompositionStart: null, + topCompositionUpdate: null, + topContextMenu: null, + topCopy: null, + topCut: null, + topDoubleClick: null, + topDrag: null, + topDragEnd: null, + topDragEnter: null, + topDragExit: null, + topDragLeave: null, + topDragOver: null, + topDragStart: null, + topDrop: null, + topError: null, + topFocus: null, + topInput: null, + topKeyDown: null, + topKeyPress: null, + topKeyUp: null, + topLoad: null, + topMouseDown: null, + topMouseMove: null, + topMouseOut: null, + topMouseOver: null, + topMouseUp: null, + topPaste: null, + topReset: null, + topScroll: null, + topSelectionChange: null, + topSubmit: null, + topTextInput: null, + topTouchCancel: null, + topTouchEnd: null, + topTouchMove: null, + topTouchStart: null, + topWheel: null + }); + + var EventConstants = { + topLevelTypes: topLevelTypes, + PropagationPhases: PropagationPhases + }; + + module.exports = EventConstants; + + +/***/ }, +/* 14 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule keyMirror + * @typechecks static-only + */ + + 'use strict'; + + var invariant = __webpack_require__(15); + + /** + * Constructs an enumeration with keys equal to their value. + * + * For example: + * + * var COLORS = keyMirror({blue: null, red: null}); + * var myColor = COLORS.blue; + * var isColorValid = !!COLORS[myColor]; + * + * The last line could not be performed if the values of the generated enum were + * not equal to their keys. + * + * Input: {key1: val1, key2: val2} + * Output: {key1: key1, key2: key2} + * + * @param {object} obj + * @return {object} + */ + var keyMirror = function(obj) { + var ret = {}; + var key; + ("production" !== process.env.NODE_ENV ? invariant( + obj instanceof Object && !Array.isArray(obj), + 'keyMirror(...): Argument must be an object.' + ) : invariant(obj instanceof Object && !Array.isArray(obj))); + for (key in obj) { + if (!obj.hasOwnProperty(key)) { + continue; + } + ret[key] = key; + } + return ret; + }; + + module.exports = keyMirror; + + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(11))) + +/***/ }, +/* 15 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule invariant + */ + + "use strict"; + + /** + * Use invariant() to assert state which your program assumes to be true. + * + * Provide sprintf-style format (only %s is supported) and arguments + * to provide information about what broke and what you were + * expecting. + * + * The invariant message will be stripped in production, but the invariant + * will remain to ensure logic does not differ in production. + */ + + var invariant = function(condition, format, a, b, c, d, e, f) { + if ("production" !== process.env.NODE_ENV) { + if (format === undefined) { + throw new Error('invariant requires an error message argument'); + } + } + + if (!condition) { + var error; + if (format === undefined) { + error = new Error( + 'Minified exception occurred; use the non-minified dev environment ' + + 'for the full error message and additional helpful warnings.' + ); + } else { + var args = [a, b, c, d, e, f]; + var argIndex = 0; + error = new Error( + 'Invariant Violation: ' + + format.replace(/%s/g, function() { return args[argIndex++]; }) + ); + } + + error.framesToPop = 1; // we don't care about invariant's own frame + throw error; + } + }; + + module.exports = invariant; + + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(11))) + +/***/ }, +/* 16 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactChildren + */ + + 'use strict'; + + var PooledClass = __webpack_require__(17); + var ReactFragment = __webpack_require__(18); + + var traverseAllChildren = __webpack_require__(25); + var warning = __webpack_require__(22); + + var twoArgumentPooler = PooledClass.twoArgumentPooler; + var threeArgumentPooler = PooledClass.threeArgumentPooler; + + /** + * PooledClass representing the bookkeeping associated with performing a child + * traversal. Allows avoiding binding callbacks. + * + * @constructor ForEachBookKeeping + * @param {!function} forEachFunction Function to perform traversal with. + * @param {?*} forEachContext Context to perform context with. + */ + function ForEachBookKeeping(forEachFunction, forEachContext) { + this.forEachFunction = forEachFunction; + this.forEachContext = forEachContext; + } + PooledClass.addPoolingTo(ForEachBookKeeping, twoArgumentPooler); + + function forEachSingleChild(traverseContext, child, name, i) { + var forEachBookKeeping = traverseContext; + forEachBookKeeping.forEachFunction.call( + forEachBookKeeping.forEachContext, child, i); + } + + /** + * Iterates through children that are typically specified as `props.children`. + * + * The provided forEachFunc(child, index) will be called for each + * leaf child. + * + * @param {?*} children Children tree container. + * @param {function(*, int)} forEachFunc. + * @param {*} forEachContext Context for forEachContext. + */ + function forEachChildren(children, forEachFunc, forEachContext) { + if (children == null) { + return children; + } + + var traverseContext = + ForEachBookKeeping.getPooled(forEachFunc, forEachContext); + traverseAllChildren(children, forEachSingleChild, traverseContext); + ForEachBookKeeping.release(traverseContext); + } + + /** + * PooledClass representing the bookkeeping associated with performing a child + * mapping. Allows avoiding binding callbacks. + * + * @constructor MapBookKeeping + * @param {!*} mapResult Object containing the ordered map of results. + * @param {!function} mapFunction Function to perform mapping with. + * @param {?*} mapContext Context to perform mapping with. + */ + function MapBookKeeping(mapResult, mapFunction, mapContext) { + this.mapResult = mapResult; + this.mapFunction = mapFunction; + this.mapContext = mapContext; + } + PooledClass.addPoolingTo(MapBookKeeping, threeArgumentPooler); + + function mapSingleChildIntoContext(traverseContext, child, name, i) { + var mapBookKeeping = traverseContext; + var mapResult = mapBookKeeping.mapResult; + + var keyUnique = !mapResult.hasOwnProperty(name); + if ("production" !== process.env.NODE_ENV) { + ("production" !== process.env.NODE_ENV ? warning( + keyUnique, + 'ReactChildren.map(...): Encountered two children with the same key, ' + + '`%s`. Child keys must be unique; when two children share a key, only ' + + 'the first child will be used.', + name + ) : null); + } + + if (keyUnique) { + var mappedChild = + mapBookKeeping.mapFunction.call(mapBookKeeping.mapContext, child, i); + mapResult[name] = mappedChild; + } + } + + /** + * Maps children that are typically specified as `props.children`. + * + * The provided mapFunction(child, key, index) will be called for each + * leaf child. + * + * TODO: This may likely break any calls to `ReactChildren.map` that were + * previously relying on the fact that we guarded against null children. + * + * @param {?*} children Children tree container. + * @param {function(*, int)} mapFunction. + * @param {*} mapContext Context for mapFunction. + * @return {object} Object containing the ordered map of results. + */ + function mapChildren(children, func, context) { + if (children == null) { + return children; + } + + var mapResult = {}; + var traverseContext = MapBookKeeping.getPooled(mapResult, func, context); + traverseAllChildren(children, mapSingleChildIntoContext, traverseContext); + MapBookKeeping.release(traverseContext); + return ReactFragment.create(mapResult); + } + + function forEachSingleChildDummy(traverseContext, child, name, i) { + return null; + } + + /** + * Count the number of children that are typically specified as + * `props.children`. + * + * @param {?*} children Children tree container. + * @return {number} The number of children. + */ + function countChildren(children, context) { + return traverseAllChildren(children, forEachSingleChildDummy, null); + } + + var ReactChildren = { + forEach: forEachChildren, + map: mapChildren, + count: countChildren + }; + + module.exports = ReactChildren; + + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(11))) + +/***/ }, +/* 17 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule PooledClass + */ + + 'use strict'; + + var invariant = __webpack_require__(15); + + /** + * Static poolers. Several custom versions for each potential number of + * arguments. A completely generic pooler is easy to implement, but would + * require accessing the `arguments` object. In each of these, `this` refers to + * the Class itself, not an instance. If any others are needed, simply add them + * here, or in their own files. + */ + var oneArgumentPooler = function(copyFieldsFrom) { + var Klass = this; + if (Klass.instancePool.length) { + var instance = Klass.instancePool.pop(); + Klass.call(instance, copyFieldsFrom); + return instance; + } else { + return new Klass(copyFieldsFrom); + } + }; + + var twoArgumentPooler = function(a1, a2) { + var Klass = this; + if (Klass.instancePool.length) { + var instance = Klass.instancePool.pop(); + Klass.call(instance, a1, a2); + return instance; + } else { + return new Klass(a1, a2); + } + }; + + var threeArgumentPooler = function(a1, a2, a3) { + var Klass = this; + if (Klass.instancePool.length) { + var instance = Klass.instancePool.pop(); + Klass.call(instance, a1, a2, a3); + return instance; + } else { + return new Klass(a1, a2, a3); + } + }; + + var fiveArgumentPooler = function(a1, a2, a3, a4, a5) { + var Klass = this; + if (Klass.instancePool.length) { + var instance = Klass.instancePool.pop(); + Klass.call(instance, a1, a2, a3, a4, a5); + return instance; + } else { + return new Klass(a1, a2, a3, a4, a5); + } + }; + + var standardReleaser = function(instance) { + var Klass = this; + ("production" !== process.env.NODE_ENV ? invariant( + instance instanceof Klass, + 'Trying to release an instance into a pool of a different type.' + ) : invariant(instance instanceof Klass)); + if (instance.destructor) { + instance.destructor(); + } + if (Klass.instancePool.length < Klass.poolSize) { + Klass.instancePool.push(instance); + } + }; + + var DEFAULT_POOL_SIZE = 10; + var DEFAULT_POOLER = oneArgumentPooler; + + /** + * Augments `CopyConstructor` to be a poolable class, augmenting only the class + * itself (statically) not adding any prototypical fields. Any CopyConstructor + * you give this may have a `poolSize` property, and will look for a + * prototypical `destructor` on instances (optional). + * + * @param {Function} CopyConstructor Constructor that can be used to reset. + * @param {Function} pooler Customizable pooler. + */ + var addPoolingTo = function(CopyConstructor, pooler) { + var NewKlass = CopyConstructor; + NewKlass.instancePool = []; + NewKlass.getPooled = pooler || DEFAULT_POOLER; + if (!NewKlass.poolSize) { + NewKlass.poolSize = DEFAULT_POOL_SIZE; + } + NewKlass.release = standardReleaser; + return NewKlass; + }; + + var PooledClass = { + addPoolingTo: addPoolingTo, + oneArgumentPooler: oneArgumentPooler, + twoArgumentPooler: twoArgumentPooler, + threeArgumentPooler: threeArgumentPooler, + fiveArgumentPooler: fiveArgumentPooler + }; + + module.exports = PooledClass; + + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(11))) + +/***/ }, +/* 18 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactFragment + */ + + 'use strict'; + + var ReactElement = __webpack_require__(19); + + var warning = __webpack_require__(22); + + /** + * We used to allow keyed objects to serve as a collection of ReactElements, + * or nested sets. This allowed us a way to explicitly key a set a fragment of + * components. This is now being replaced with an opaque data structure. + * The upgrade path is to call React.addons.createFragment({ key: value }) to + * create a keyed fragment. The resulting data structure is opaque, for now. + */ + + if ("production" !== process.env.NODE_ENV) { + var fragmentKey = '_reactFragment'; + var didWarnKey = '_reactDidWarn'; + var canWarnForReactFragment = false; + + try { + // Feature test. Don't even try to issue this warning if we can't use + // enumerable: false. + + var dummy = function() { + return 1; + }; + + Object.defineProperty( + {}, + fragmentKey, + {enumerable: false, value: true} + ); + + Object.defineProperty( + {}, + 'key', + {enumerable: true, get: dummy} + ); + + canWarnForReactFragment = true; + } catch (x) { } + + var proxyPropertyAccessWithWarning = function(obj, key) { + Object.defineProperty(obj, key, { + enumerable: true, + get: function() { + ("production" !== process.env.NODE_ENV ? warning( + this[didWarnKey], + 'A ReactFragment is an opaque type. Accessing any of its ' + + 'properties is deprecated. Pass it to one of the React.Children ' + + 'helpers.' + ) : null); + this[didWarnKey] = true; + return this[fragmentKey][key]; + }, + set: function(value) { + ("production" !== process.env.NODE_ENV ? warning( + this[didWarnKey], + 'A ReactFragment is an immutable opaque type. Mutating its ' + + 'properties is deprecated.' + ) : null); + this[didWarnKey] = true; + this[fragmentKey][key] = value; + } + }); + }; + + var issuedWarnings = {}; + + var didWarnForFragment = function(fragment) { + // We use the keys and the type of the value as a heuristic to dedupe the + // warning to avoid spamming too much. + var fragmentCacheKey = ''; + for (var key in fragment) { + fragmentCacheKey += key + ':' + (typeof fragment[key]) + ','; + } + var alreadyWarnedOnce = !!issuedWarnings[fragmentCacheKey]; + issuedWarnings[fragmentCacheKey] = true; + return alreadyWarnedOnce; + }; + } + + var ReactFragment = { + // Wrap a keyed object in an opaque proxy that warns you if you access any + // of its properties. + create: function(object) { + if ("production" !== process.env.NODE_ENV) { + if (typeof object !== 'object' || !object || Array.isArray(object)) { + ("production" !== process.env.NODE_ENV ? warning( + false, + 'React.addons.createFragment only accepts a single object.', + object + ) : null); + return object; + } + if (ReactElement.isValidElement(object)) { + ("production" !== process.env.NODE_ENV ? warning( + false, + 'React.addons.createFragment does not accept a ReactElement ' + + 'without a wrapper object.' + ) : null); + return object; + } + if (canWarnForReactFragment) { + var proxy = {}; + Object.defineProperty(proxy, fragmentKey, { + enumerable: false, + value: object + }); + Object.defineProperty(proxy, didWarnKey, { + writable: true, + enumerable: false, + value: false + }); + for (var key in object) { + proxyPropertyAccessWithWarning(proxy, key); + } + Object.preventExtensions(proxy); + return proxy; + } + } + return object; + }, + // Extract the original keyed object from the fragment opaque type. Warn if + // a plain object is passed here. + extract: function(fragment) { + if ("production" !== process.env.NODE_ENV) { + if (canWarnForReactFragment) { + if (!fragment[fragmentKey]) { + ("production" !== process.env.NODE_ENV ? warning( + didWarnForFragment(fragment), + 'Any use of a keyed object should be wrapped in ' + + 'React.addons.createFragment(object) before being passed as a ' + + 'child.' + ) : null); + return fragment; + } + return fragment[fragmentKey]; + } + } + return fragment; + }, + // Check if this is a fragment and if so, extract the keyed object. If it + // is a fragment-like object, warn that it should be wrapped. Ignore if we + // can't determine what kind of object this is. + extractIfFragment: function(fragment) { + if ("production" !== process.env.NODE_ENV) { + if (canWarnForReactFragment) { + // If it is the opaque type, return the keyed object. + if (fragment[fragmentKey]) { + return fragment[fragmentKey]; + } + // Otherwise, check each property if it has an element, if it does + // it is probably meant as a fragment, so we can warn early. Defer, + // the warning to extract. + for (var key in fragment) { + if (fragment.hasOwnProperty(key) && + ReactElement.isValidElement(fragment[key])) { + // This looks like a fragment object, we should provide an + // early warning. + return ReactFragment.extract(fragment); + } + } + } + } + return fragment; + } + }; + + module.exports = ReactFragment; + + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(11))) + +/***/ }, +/* 19 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2014-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactElement + */ + + 'use strict'; + + var ReactContext = __webpack_require__(20); + var ReactCurrentOwner = __webpack_require__(24); + + var assign = __webpack_require__(8); + var warning = __webpack_require__(22); + + var RESERVED_PROPS = { + key: true, + ref: true + }; + + /** + * Warn for mutations. + * + * @internal + * @param {object} object + * @param {string} key + */ + function defineWarningProperty(object, key) { + Object.defineProperty(object, key, { + + configurable: false, + enumerable: true, + + get: function() { + if (!this._store) { + return null; + } + return this._store[key]; + }, + + set: function(value) { + ("production" !== process.env.NODE_ENV ? warning( + false, + 'Don\'t set the %s property of the React element. Instead, ' + + 'specify the correct value when initially creating the element.', + key + ) : null); + this._store[key] = value; + } + + }); + } + + /** + * This is updated to true if the membrane is successfully created. + */ + var useMutationMembrane = false; + + /** + * Warn for mutations. + * + * @internal + * @param {object} element + */ + function defineMutationMembrane(prototype) { + try { + var pseudoFrozenProperties = { + props: true + }; + for (var key in pseudoFrozenProperties) { + defineWarningProperty(prototype, key); + } + useMutationMembrane = true; + } catch (x) { + // IE will fail on defineProperty + } + } + + /** + * Base constructor for all React elements. This is only used to make this + * work with a dynamic instanceof check. Nothing should live on this prototype. + * + * @param {*} type + * @param {string|object} ref + * @param {*} key + * @param {*} props + * @internal + */ + var ReactElement = function(type, key, ref, owner, context, props) { + // Built-in properties that belong on the element + this.type = type; + this.key = key; + this.ref = ref; + + // Record the component responsible for creating this element. + this._owner = owner; + + // TODO: Deprecate withContext, and then the context becomes accessible + // through the owner. + this._context = context; + + if ("production" !== process.env.NODE_ENV) { + // The validation flag and props are currently mutative. We put them on + // an external backing store so that we can freeze the whole object. + // This can be replaced with a WeakMap once they are implemented in + // commonly used development environments. + this._store = {props: props, originalProps: assign({}, props)}; + + // To make comparing ReactElements easier for testing purposes, we make + // the validation flag non-enumerable (where possible, which should + // include every environment we run tests in), so the test framework + // ignores it. + try { + Object.defineProperty(this._store, 'validated', { + configurable: false, + enumerable: false, + writable: true + }); + } catch (x) { + } + this._store.validated = false; + + // We're not allowed to set props directly on the object so we early + // return and rely on the prototype membrane to forward to the backing + // store. + if (useMutationMembrane) { + Object.freeze(this); + return; + } + } + + this.props = props; + }; + + // We intentionally don't expose the function on the constructor property. + // ReactElement should be indistinguishable from a plain object. + ReactElement.prototype = { + _isReactElement: true + }; + + if ("production" !== process.env.NODE_ENV) { + defineMutationMembrane(ReactElement.prototype); + } + + ReactElement.createElement = function(type, config, children) { + var propName; + + // Reserved names are extracted + var props = {}; + + var key = null; + var ref = null; + + if (config != null) { + ref = config.ref === undefined ? null : config.ref; + key = config.key === undefined ? null : '' + config.key; + // Remaining properties are added to a new props object + for (propName in config) { + if (config.hasOwnProperty(propName) && + !RESERVED_PROPS.hasOwnProperty(propName)) { + props[propName] = config[propName]; + } + } + } + + // Children can be more than one argument, and those are transferred onto + // the newly allocated props object. + var childrenLength = arguments.length - 2; + if (childrenLength === 1) { + props.children = children; + } else if (childrenLength > 1) { + var childArray = Array(childrenLength); + for (var i = 0; i < childrenLength; i++) { + childArray[i] = arguments[i + 2]; + } + props.children = childArray; + } + + // Resolve default props + if (type && type.defaultProps) { + var defaultProps = type.defaultProps; + for (propName in defaultProps) { + if (typeof props[propName] === 'undefined') { + props[propName] = defaultProps[propName]; + } + } + } + + return new ReactElement( + type, + key, + ref, + ReactCurrentOwner.current, + ReactContext.current, + props + ); + }; + + ReactElement.createFactory = function(type) { + var factory = ReactElement.createElement.bind(null, type); + // Expose the type on the factory and the prototype so that it can be + // easily accessed on elements. E.g. .type === Foo.type. + // This should not be named `constructor` since this may not be the function + // that created the element, and it may not even be a constructor. + // Legacy hook TODO: Warn if this is accessed + factory.type = type; + return factory; + }; + + ReactElement.cloneAndReplaceProps = function(oldElement, newProps) { + var newElement = new ReactElement( + oldElement.type, + oldElement.key, + oldElement.ref, + oldElement._owner, + oldElement._context, + newProps + ); + + if ("production" !== process.env.NODE_ENV) { + // If the key on the original is valid, then the clone is valid + newElement._store.validated = oldElement._store.validated; + } + return newElement; + }; + + ReactElement.cloneElement = function(element, config, children) { + var propName; + + // Original props are copied + var props = assign({}, element.props); + + // Reserved names are extracted + var key = element.key; + var ref = element.ref; + + // Owner will be preserved, unless ref is overridden + var owner = element._owner; + + if (config != null) { + if (config.ref !== undefined) { + // Silently steal the ref from the parent. + ref = config.ref; + owner = ReactCurrentOwner.current; + } + if (config.key !== undefined) { + key = '' + config.key; + } + // Remaining properties override existing props + for (propName in config) { + if (config.hasOwnProperty(propName) && + !RESERVED_PROPS.hasOwnProperty(propName)) { + props[propName] = config[propName]; + } + } + } + + // Children can be more than one argument, and those are transferred onto + // the newly allocated props object. + var childrenLength = arguments.length - 2; + if (childrenLength === 1) { + props.children = children; + } else if (childrenLength > 1) { + var childArray = Array(childrenLength); + for (var i = 0; i < childrenLength; i++) { + childArray[i] = arguments[i + 2]; + } + props.children = childArray; + } + + return new ReactElement( + element.type, + key, + ref, + owner, + element._context, + props + ); + }; + + /** + * @param {?object} object + * @return {boolean} True if `object` is a valid component. + * @final + */ + ReactElement.isValidElement = function(object) { + // ReactTestUtils is often used outside of beforeEach where as React is + // within it. This leads to two different instances of React on the same + // page. To identify a element from a different React instance we use + // a flag instead of an instanceof check. + var isElement = !!(object && object._isReactElement); + // if (isElement && !(object instanceof ReactElement)) { + // This is an indicator that you're using multiple versions of React at the + // same time. This will screw with ownership and stuff. Fix it, please. + // TODO: We could possibly warn here. + // } + return isElement; + }; + + module.exports = ReactElement; + + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(11))) + +/***/ }, +/* 20 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactContext + */ + + 'use strict'; + + var assign = __webpack_require__(8); + var emptyObject = __webpack_require__(21); + var warning = __webpack_require__(22); + + var didWarn = false; + + /** + * Keeps track of the current context. + * + * The context is automatically passed down the component ownership hierarchy + * and is accessible via `this.context` on ReactCompositeComponents. + */ + var ReactContext = { + + /** + * @internal + * @type {object} + */ + current: emptyObject, + + /** + * Temporarily extends the current context while executing scopedCallback. + * + * A typical use case might look like + * + * render: function() { + * var children = ReactContext.withContext({foo: 'foo'}, () => ( + * + * )); + * return
{children}
; + * } + * + * @param {object} newContext New context to merge into the existing context + * @param {function} scopedCallback Callback to run with the new context + * @return {ReactComponent|array} + */ + withContext: function(newContext, scopedCallback) { + if ("production" !== process.env.NODE_ENV) { + ("production" !== process.env.NODE_ENV ? warning( + didWarn, + 'withContext is deprecated and will be removed in a future version. ' + + 'Use a wrapper component with getChildContext instead.' + ) : null); + + didWarn = true; + } + + var result; + var previousContext = ReactContext.current; + ReactContext.current = assign({}, previousContext, newContext); + try { + result = scopedCallback(); + } finally { + ReactContext.current = previousContext; + } + return result; + } + + }; + + module.exports = ReactContext; + + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(11))) + +/***/ }, +/* 21 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule emptyObject + */ + + "use strict"; + + var emptyObject = {}; + + if ("production" !== process.env.NODE_ENV) { + Object.freeze(emptyObject); + } + + module.exports = emptyObject; + + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(11))) + +/***/ }, +/* 22 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2014-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule warning + */ + + "use strict"; + + var emptyFunction = __webpack_require__(23); + + /** + * Similar to invariant but only logs a warning if the condition is not met. + * This can be used to log issues in development environments in critical + * paths. Removing the logging code for production environments will keep the + * same logic and follow the same code paths. + */ + + var warning = emptyFunction; + + if ("production" !== process.env.NODE_ENV) { + warning = function(condition, format ) {for (var args=[],$__0=2,$__1=arguments.length;$__0<$__1;$__0++) args.push(arguments[$__0]); + if (format === undefined) { + throw new Error( + '`warning(condition, format, ...args)` requires a warning ' + + 'message argument' + ); + } + + if (format.length < 10 || /^[s\W]*$/.test(format)) { + throw new Error( + 'The warning format should be able to uniquely identify this ' + + 'warning. Please, use a more descriptive format than: ' + format + ); + } + + if (format.indexOf('Failed Composite propType: ') === 0) { + return; // Ignore CompositeComponent proptype check. + } + + if (!condition) { + var argIndex = 0; + var message = 'Warning: ' + format.replace(/%s/g, function() {return args[argIndex++];}); + console.warn(message); + try { + // --- Welcome to debugging React --- + // This error was thrown as a convenience so that you can use this stack + // to find the callsite that caused this warning to fire. + throw new Error(message); + } catch(x) {} + } + }; + } + + module.exports = warning; + + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(11))) + +/***/ }, +/* 23 */ +/***/ function(module, exports) { + + /** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule emptyFunction + */ + + function makeEmptyFunction(arg) { + return function() { + return arg; + }; + } + + /** + * This function accepts and discards inputs; it has no side effects. This is + * primarily useful idiomatically for overridable function endpoints which + * always need to be callable, since JS lacks a null-call idiom ala Cocoa. + */ + function emptyFunction() {} + + emptyFunction.thatReturns = makeEmptyFunction; + emptyFunction.thatReturnsFalse = makeEmptyFunction(false); + emptyFunction.thatReturnsTrue = makeEmptyFunction(true); + emptyFunction.thatReturnsNull = makeEmptyFunction(null); + emptyFunction.thatReturnsThis = function() { return this; }; + emptyFunction.thatReturnsArgument = function(arg) { return arg; }; + + module.exports = emptyFunction; + + +/***/ }, +/* 24 */ +/***/ function(module, exports) { + + /** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactCurrentOwner + */ + + 'use strict'; + + /** + * Keeps track of the current owner. + * + * The current owner is the component who should own any components that are + * currently being constructed. + * + * The depth indicate how many composite components are above this render level. + */ + var ReactCurrentOwner = { + + /** + * @internal + * @type {ReactComponent} + */ + current: null + + }; + + module.exports = ReactCurrentOwner; + + +/***/ }, +/* 25 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule traverseAllChildren + */ + + 'use strict'; + + var ReactElement = __webpack_require__(19); + var ReactFragment = __webpack_require__(18); + var ReactInstanceHandles = __webpack_require__(27); + + var getIteratorFn = __webpack_require__(26); + var invariant = __webpack_require__(15); + var warning = __webpack_require__(22); + + var SEPARATOR = ReactInstanceHandles.SEPARATOR; + var SUBSEPARATOR = ':'; + + /** + * TODO: Test that a single child and an array with one item have the same key + * pattern. + */ + + var userProvidedKeyEscaperLookup = { + '=': '=0', + '.': '=1', + ':': '=2' + }; + + var userProvidedKeyEscapeRegex = /[=.:]/g; + + var didWarnAboutMaps = false; + + function userProvidedKeyEscaper(match) { + return userProvidedKeyEscaperLookup[match]; + } + + /** + * Generate a key string that identifies a component within a set. + * + * @param {*} component A component that could contain a manual key. + * @param {number} index Index that is used if a manual key is not provided. + * @return {string} + */ + function getComponentKey(component, index) { + if (component && component.key != null) { + // Explicit key + return wrapUserProvidedKey(component.key); + } + // Implicit key determined by the index in the set + return index.toString(36); + } + + /** + * Escape a component key so that it is safe to use in a reactid. + * + * @param {*} key Component key to be escaped. + * @return {string} An escaped string. + */ + function escapeUserProvidedKey(text) { + return ('' + text).replace( + userProvidedKeyEscapeRegex, + userProvidedKeyEscaper + ); + } + + /** + * Wrap a `key` value explicitly provided by the user to distinguish it from + * implicitly-generated keys generated by a component's index in its parent. + * + * @param {string} key Value of a user-provided `key` attribute + * @return {string} + */ + function wrapUserProvidedKey(key) { + return '$' + escapeUserProvidedKey(key); + } + + /** + * @param {?*} children Children tree container. + * @param {!string} nameSoFar Name of the key path so far. + * @param {!number} indexSoFar Number of children encountered until this point. + * @param {!function} callback Callback to invoke with each child found. + * @param {?*} traverseContext Used to pass information throughout the traversal + * process. + * @return {!number} The number of children in this subtree. + */ + function traverseAllChildrenImpl( + children, + nameSoFar, + indexSoFar, + callback, + traverseContext + ) { + var type = typeof children; + + if (type === 'undefined' || type === 'boolean') { + // All of the above are perceived as null. + children = null; + } + + if (children === null || + type === 'string' || + type === 'number' || + ReactElement.isValidElement(children)) { + callback( + traverseContext, + children, + // If it's the only child, treat the name as if it was wrapped in an array + // so that it's consistent if the number of children grows. + nameSoFar === '' ? SEPARATOR + getComponentKey(children, 0) : nameSoFar, + indexSoFar + ); + return 1; + } + + var child, nextName, nextIndex; + var subtreeCount = 0; // Count of children found in the current subtree. + + if (Array.isArray(children)) { + for (var i = 0; i < children.length; i++) { + child = children[i]; + nextName = ( + (nameSoFar !== '' ? nameSoFar + SUBSEPARATOR : SEPARATOR) + + getComponentKey(child, i) + ); + nextIndex = indexSoFar + subtreeCount; + subtreeCount += traverseAllChildrenImpl( + child, + nextName, + nextIndex, + callback, + traverseContext + ); + } + } else { + var iteratorFn = getIteratorFn(children); + if (iteratorFn) { + var iterator = iteratorFn.call(children); + var step; + if (iteratorFn !== children.entries) { + var ii = 0; + while (!(step = iterator.next()).done) { + child = step.value; + nextName = ( + (nameSoFar !== '' ? nameSoFar + SUBSEPARATOR : SEPARATOR) + + getComponentKey(child, ii++) + ); + nextIndex = indexSoFar + subtreeCount; + subtreeCount += traverseAllChildrenImpl( + child, + nextName, + nextIndex, + callback, + traverseContext + ); + } + } else { + if ("production" !== process.env.NODE_ENV) { + ("production" !== process.env.NODE_ENV ? warning( + didWarnAboutMaps, + 'Using Maps as children is not yet fully supported. It is an ' + + 'experimental feature that might be removed. Convert it to a ' + + 'sequence / iterable of keyed ReactElements instead.' + ) : null); + didWarnAboutMaps = true; + } + // Iterator will provide entry [k,v] tuples rather than values. + while (!(step = iterator.next()).done) { + var entry = step.value; + if (entry) { + child = entry[1]; + nextName = ( + (nameSoFar !== '' ? nameSoFar + SUBSEPARATOR : SEPARATOR) + + wrapUserProvidedKey(entry[0]) + SUBSEPARATOR + + getComponentKey(child, 0) + ); + nextIndex = indexSoFar + subtreeCount; + subtreeCount += traverseAllChildrenImpl( + child, + nextName, + nextIndex, + callback, + traverseContext + ); + } + } + } + } else if (type === 'object') { + ("production" !== process.env.NODE_ENV ? invariant( + children.nodeType !== 1, + 'traverseAllChildren(...): Encountered an invalid child; DOM ' + + 'elements are not valid children of React components.' + ) : invariant(children.nodeType !== 1)); + var fragment = ReactFragment.extract(children); + for (var key in fragment) { + if (fragment.hasOwnProperty(key)) { + child = fragment[key]; + nextName = ( + (nameSoFar !== '' ? nameSoFar + SUBSEPARATOR : SEPARATOR) + + wrapUserProvidedKey(key) + SUBSEPARATOR + + getComponentKey(child, 0) + ); + nextIndex = indexSoFar + subtreeCount; + subtreeCount += traverseAllChildrenImpl( + child, + nextName, + nextIndex, + callback, + traverseContext + ); + } + } + } + } + + return subtreeCount; + } + + /** + * Traverses children that are typically specified as `props.children`, but + * might also be specified through attributes: + * + * - `traverseAllChildren(this.props.children, ...)` + * - `traverseAllChildren(this.props.leftPanelChildren, ...)` + * + * The `traverseContext` is an optional argument that is passed through the + * entire traversal. It can be used to store accumulations or anything else that + * the callback might find relevant. + * + * @param {?*} children Children tree object. + * @param {!function} callback To invoke upon traversing each child. + * @param {?*} traverseContext Context for traversal. + * @return {!number} The number of children in this subtree. + */ + function traverseAllChildren(children, callback, traverseContext) { + if (children == null) { + return 0; + } + + return traverseAllChildrenImpl(children, '', 0, callback, traverseContext); + } + + module.exports = traverseAllChildren; + + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(11))) + +/***/ }, +/* 26 */ +/***/ function(module, exports) { + + /** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule getIteratorFn + * @typechecks static-only + */ + + 'use strict'; + + /* global Symbol */ + var ITERATOR_SYMBOL = typeof Symbol === 'function' && Symbol.iterator; + var FAUX_ITERATOR_SYMBOL = '@@iterator'; // Before Symbol spec. + + /** + * Returns the iterator method function contained on the iterable object. + * + * Be sure to invoke the function with the iterable as context: + * + * var iteratorFn = getIteratorFn(myIterable); + * if (iteratorFn) { + * var iterator = iteratorFn.call(myIterable); + * ... + * } + * + * @param {?object} maybeIterable + * @return {?function} + */ + function getIteratorFn(maybeIterable) { + var iteratorFn = maybeIterable && ( + (ITERATOR_SYMBOL && maybeIterable[ITERATOR_SYMBOL] || maybeIterable[FAUX_ITERATOR_SYMBOL]) + ); + if (typeof iteratorFn === 'function') { + return iteratorFn; + } + } + + module.exports = getIteratorFn; + + +/***/ }, +/* 27 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactInstanceHandles + * @typechecks static-only + */ + + 'use strict'; + + var ReactRootIndex = __webpack_require__(28); + + var invariant = __webpack_require__(15); + + var SEPARATOR = '.'; + var SEPARATOR_LENGTH = SEPARATOR.length; + + /** + * Maximum depth of traversals before we consider the possibility of a bad ID. + */ + var MAX_TREE_DEPTH = 100; + + /** + * Creates a DOM ID prefix to use when mounting React components. + * + * @param {number} index A unique integer + * @return {string} React root ID. + * @internal + */ + function getReactRootIDString(index) { + return SEPARATOR + index.toString(36); + } + + /** + * Checks if a character in the supplied ID is a separator or the end. + * + * @param {string} id A React DOM ID. + * @param {number} index Index of the character to check. + * @return {boolean} True if the character is a separator or end of the ID. + * @private + */ + function isBoundary(id, index) { + return id.charAt(index) === SEPARATOR || index === id.length; + } + + /** + * Checks if the supplied string is a valid React DOM ID. + * + * @param {string} id A React DOM ID, maybe. + * @return {boolean} True if the string is a valid React DOM ID. + * @private + */ + function isValidID(id) { + return id === '' || ( + id.charAt(0) === SEPARATOR && id.charAt(id.length - 1) !== SEPARATOR + ); + } + + /** + * Checks if the first ID is an ancestor of or equal to the second ID. + * + * @param {string} ancestorID + * @param {string} descendantID + * @return {boolean} True if `ancestorID` is an ancestor of `descendantID`. + * @internal + */ + function isAncestorIDOf(ancestorID, descendantID) { + return ( + descendantID.indexOf(ancestorID) === 0 && + isBoundary(descendantID, ancestorID.length) + ); + } + + /** + * Gets the parent ID of the supplied React DOM ID, `id`. + * + * @param {string} id ID of a component. + * @return {string} ID of the parent, or an empty string. + * @private + */ + function getParentID(id) { + return id ? id.substr(0, id.lastIndexOf(SEPARATOR)) : ''; + } + + /** + * Gets the next DOM ID on the tree path from the supplied `ancestorID` to the + * supplied `destinationID`. If they are equal, the ID is returned. + * + * @param {string} ancestorID ID of an ancestor node of `destinationID`. + * @param {string} destinationID ID of the destination node. + * @return {string} Next ID on the path from `ancestorID` to `destinationID`. + * @private + */ + function getNextDescendantID(ancestorID, destinationID) { + ("production" !== process.env.NODE_ENV ? invariant( + isValidID(ancestorID) && isValidID(destinationID), + 'getNextDescendantID(%s, %s): Received an invalid React DOM ID.', + ancestorID, + destinationID + ) : invariant(isValidID(ancestorID) && isValidID(destinationID))); + ("production" !== process.env.NODE_ENV ? invariant( + isAncestorIDOf(ancestorID, destinationID), + 'getNextDescendantID(...): React has made an invalid assumption about ' + + 'the DOM hierarchy. Expected `%s` to be an ancestor of `%s`.', + ancestorID, + destinationID + ) : invariant(isAncestorIDOf(ancestorID, destinationID))); + if (ancestorID === destinationID) { + return ancestorID; + } + // Skip over the ancestor and the immediate separator. Traverse until we hit + // another separator or we reach the end of `destinationID`. + var start = ancestorID.length + SEPARATOR_LENGTH; + var i; + for (i = start; i < destinationID.length; i++) { + if (isBoundary(destinationID, i)) { + break; + } + } + return destinationID.substr(0, i); + } + + /** + * Gets the nearest common ancestor ID of two IDs. + * + * Using this ID scheme, the nearest common ancestor ID is the longest common + * prefix of the two IDs that immediately preceded a "marker" in both strings. + * + * @param {string} oneID + * @param {string} twoID + * @return {string} Nearest common ancestor ID, or the empty string if none. + * @private + */ + function getFirstCommonAncestorID(oneID, twoID) { + var minLength = Math.min(oneID.length, twoID.length); + if (minLength === 0) { + return ''; + } + var lastCommonMarkerIndex = 0; + // Use `<=` to traverse until the "EOL" of the shorter string. + for (var i = 0; i <= minLength; i++) { + if (isBoundary(oneID, i) && isBoundary(twoID, i)) { + lastCommonMarkerIndex = i; + } else if (oneID.charAt(i) !== twoID.charAt(i)) { + break; + } + } + var longestCommonID = oneID.substr(0, lastCommonMarkerIndex); + ("production" !== process.env.NODE_ENV ? invariant( + isValidID(longestCommonID), + 'getFirstCommonAncestorID(%s, %s): Expected a valid React DOM ID: %s', + oneID, + twoID, + longestCommonID + ) : invariant(isValidID(longestCommonID))); + return longestCommonID; + } + + /** + * Traverses the parent path between two IDs (either up or down). The IDs must + * not be the same, and there must exist a parent path between them. If the + * callback returns `false`, traversal is stopped. + * + * @param {?string} start ID at which to start traversal. + * @param {?string} stop ID at which to end traversal. + * @param {function} cb Callback to invoke each ID with. + * @param {?boolean} skipFirst Whether or not to skip the first node. + * @param {?boolean} skipLast Whether or not to skip the last node. + * @private + */ + function traverseParentPath(start, stop, cb, arg, skipFirst, skipLast) { + start = start || ''; + stop = stop || ''; + ("production" !== process.env.NODE_ENV ? invariant( + start !== stop, + 'traverseParentPath(...): Cannot traverse from and to the same ID, `%s`.', + start + ) : invariant(start !== stop)); + var traverseUp = isAncestorIDOf(stop, start); + ("production" !== process.env.NODE_ENV ? invariant( + traverseUp || isAncestorIDOf(start, stop), + 'traverseParentPath(%s, %s, ...): Cannot traverse from two IDs that do ' + + 'not have a parent path.', + start, + stop + ) : invariant(traverseUp || isAncestorIDOf(start, stop))); + // Traverse from `start` to `stop` one depth at a time. + var depth = 0; + var traverse = traverseUp ? getParentID : getNextDescendantID; + for (var id = start; /* until break */; id = traverse(id, stop)) { + var ret; + if ((!skipFirst || id !== start) && (!skipLast || id !== stop)) { + ret = cb(id, traverseUp, arg); + } + if (ret === false || id === stop) { + // Only break //after// visiting `stop`. + break; + } + ("production" !== process.env.NODE_ENV ? invariant( + depth++ < MAX_TREE_DEPTH, + 'traverseParentPath(%s, %s, ...): Detected an infinite loop while ' + + 'traversing the React DOM ID tree. This may be due to malformed IDs: %s', + start, stop + ) : invariant(depth++ < MAX_TREE_DEPTH)); + } + } + + /** + * Manages the IDs assigned to DOM representations of React components. This + * uses a specific scheme in order to traverse the DOM efficiently (e.g. in + * order to simulate events). + * + * @internal + */ + var ReactInstanceHandles = { + + /** + * Constructs a React root ID + * @return {string} A React root ID. + */ + createReactRootID: function() { + return getReactRootIDString(ReactRootIndex.createReactRootIndex()); + }, + + /** + * Constructs a React ID by joining a root ID with a name. + * + * @param {string} rootID Root ID of a parent component. + * @param {string} name A component's name (as flattened children). + * @return {string} A React ID. + * @internal + */ + createReactID: function(rootID, name) { + return rootID + name; + }, + + /** + * Gets the DOM ID of the React component that is the root of the tree that + * contains the React component with the supplied DOM ID. + * + * @param {string} id DOM ID of a React component. + * @return {?string} DOM ID of the React component that is the root. + * @internal + */ + getReactRootIDFromNodeID: function(id) { + if (id && id.charAt(0) === SEPARATOR && id.length > 1) { + var index = id.indexOf(SEPARATOR, 1); + return index > -1 ? id.substr(0, index) : id; + } + return null; + }, + + /** + * Traverses the ID hierarchy and invokes the supplied `cb` on any IDs that + * should would receive a `mouseEnter` or `mouseLeave` event. + * + * NOTE: Does not invoke the callback on the nearest common ancestor because + * nothing "entered" or "left" that element. + * + * @param {string} leaveID ID being left. + * @param {string} enterID ID being entered. + * @param {function} cb Callback to invoke on each entered/left ID. + * @param {*} upArg Argument to invoke the callback with on left IDs. + * @param {*} downArg Argument to invoke the callback with on entered IDs. + * @internal + */ + traverseEnterLeave: function(leaveID, enterID, cb, upArg, downArg) { + var ancestorID = getFirstCommonAncestorID(leaveID, enterID); + if (ancestorID !== leaveID) { + traverseParentPath(leaveID, ancestorID, cb, upArg, false, true); + } + if (ancestorID !== enterID) { + traverseParentPath(ancestorID, enterID, cb, downArg, true, false); + } + }, + + /** + * Simulates the traversal of a two-phase, capture/bubble event dispatch. + * + * NOTE: This traversal happens on IDs without touching the DOM. + * + * @param {string} targetID ID of the target node. + * @param {function} cb Callback to invoke. + * @param {*} arg Argument to invoke the callback with. + * @internal + */ + traverseTwoPhase: function(targetID, cb, arg) { + if (targetID) { + traverseParentPath('', targetID, cb, arg, true, false); + traverseParentPath(targetID, '', cb, arg, false, true); + } + }, + + /** + * Traverse a node ID, calling the supplied `cb` for each ancestor ID. For + * example, passing `.0.$row-0.1` would result in `cb` getting called + * with `.0`, `.0.$row-0`, and `.0.$row-0.1`. + * + * NOTE: This traversal happens on IDs without touching the DOM. + * + * @param {string} targetID ID of the target node. + * @param {function} cb Callback to invoke. + * @param {*} arg Argument to invoke the callback with. + * @internal + */ + traverseAncestors: function(targetID, cb, arg) { + traverseParentPath('', targetID, cb, arg, true, false); + }, + + /** + * Exposed for unit testing. + * @private + */ + _getFirstCommonAncestorID: getFirstCommonAncestorID, + + /** + * Exposed for unit testing. + * @private + */ + _getNextDescendantID: getNextDescendantID, + + isAncestorIDOf: isAncestorIDOf, + + SEPARATOR: SEPARATOR + + }; + + module.exports = ReactInstanceHandles; + + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(11))) + +/***/ }, +/* 28 */ +/***/ function(module, exports) { + + /** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactRootIndex + * @typechecks + */ + + 'use strict'; + + var ReactRootIndexInjection = { + /** + * @param {function} _createReactRootIndex + */ + injectCreateReactRootIndex: function(_createReactRootIndex) { + ReactRootIndex.createReactRootIndex = _createReactRootIndex; + } + }; + + var ReactRootIndex = { + createReactRootIndex: null, + injection: ReactRootIndexInjection + }; + + module.exports = ReactRootIndex; + + +/***/ }, +/* 29 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactComponent + */ + + 'use strict'; + + var ReactUpdateQueue = __webpack_require__(30); + + var invariant = __webpack_require__(15); + var warning = __webpack_require__(22); + + /** + * Base class helpers for the updating state of a component. + */ + function ReactComponent(props, context) { + this.props = props; + this.context = context; + } + + /** + * Sets a subset of the state. Always use this to mutate + * state. You should treat `this.state` as immutable. + * + * There is no guarantee that `this.state` will be immediately updated, so + * accessing `this.state` after calling this method may return the old value. + * + * There is no guarantee that calls to `setState` will run synchronously, + * as they may eventually be batched together. You can provide an optional + * callback that will be executed when the call to setState is actually + * completed. + * + * When a function is provided to setState, it will be called at some point in + * the future (not synchronously). It will be called with the up to date + * component arguments (state, props, context). These values can be different + * from this.* because your function may be called after receiveProps but before + * shouldComponentUpdate, and this new state, props, and context will not yet be + * assigned to this. + * + * @param {object|function} partialState Next partial state or function to + * produce next partial state to be merged with current state. + * @param {?function} callback Called after state is updated. + * @final + * @protected + */ + ReactComponent.prototype.setState = function(partialState, callback) { + ("production" !== process.env.NODE_ENV ? invariant( + typeof partialState === 'object' || + typeof partialState === 'function' || + partialState == null, + 'setState(...): takes an object of state variables to update or a ' + + 'function which returns an object of state variables.' + ) : invariant(typeof partialState === 'object' || + typeof partialState === 'function' || + partialState == null)); + if ("production" !== process.env.NODE_ENV) { + ("production" !== process.env.NODE_ENV ? warning( + partialState != null, + 'setState(...): You passed an undefined or null state object; ' + + 'instead, use forceUpdate().' + ) : null); + } + ReactUpdateQueue.enqueueSetState(this, partialState); + if (callback) { + ReactUpdateQueue.enqueueCallback(this, callback); + } + }; + + /** + * Forces an update. This should only be invoked when it is known with + * certainty that we are **not** in a DOM transaction. + * + * You may want to call this when you know that some deeper aspect of the + * component's state has changed but `setState` was not called. + * + * This will not invoke `shouldComponentUpdate`, but it will invoke + * `componentWillUpdate` and `componentDidUpdate`. + * + * @param {?function} callback Called after update is complete. + * @final + * @protected + */ + ReactComponent.prototype.forceUpdate = function(callback) { + ReactUpdateQueue.enqueueForceUpdate(this); + if (callback) { + ReactUpdateQueue.enqueueCallback(this, callback); + } + }; + + /** + * Deprecated APIs. These APIs used to exist on classic React classes but since + * we would like to deprecate them, we're not going to move them over to this + * modern base class. Instead, we define a getter that warns if it's accessed. + */ + if ("production" !== process.env.NODE_ENV) { + var deprecatedAPIs = { + getDOMNode: [ + 'getDOMNode', + 'Use React.findDOMNode(component) instead.' + ], + isMounted: [ + 'isMounted', + 'Instead, make sure to clean up subscriptions and pending requests in ' + + 'componentWillUnmount to prevent memory leaks.' + ], + replaceProps: [ + 'replaceProps', + 'Instead, call React.render again at the top level.' + ], + replaceState: [ + 'replaceState', + 'Refactor your code to use setState instead (see ' + + 'https://github.com/facebook/react/issues/3236).' + ], + setProps: [ + 'setProps', + 'Instead, call React.render again at the top level.' + ] + }; + var defineDeprecationWarning = function(methodName, info) { + try { + Object.defineProperty(ReactComponent.prototype, methodName, { + get: function() { + ("production" !== process.env.NODE_ENV ? warning( + false, + '%s(...) is deprecated in plain JavaScript React classes. %s', + info[0], + info[1] + ) : null); + return undefined; + } + }); + } catch (x) { + // IE will fail on defineProperty (es5-shim/sham too) + } + }; + for (var fnName in deprecatedAPIs) { + if (deprecatedAPIs.hasOwnProperty(fnName)) { + defineDeprecationWarning(fnName, deprecatedAPIs[fnName]); + } + } + } + + module.exports = ReactComponent; + + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(11))) + +/***/ }, +/* 30 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactUpdateQueue + */ + + 'use strict'; + + var ReactLifeCycle = __webpack_require__(42); + var ReactCurrentOwner = __webpack_require__(24); + var ReactElement = __webpack_require__(19); + var ReactInstanceMap = __webpack_require__(43); + var ReactUpdates = __webpack_require__(31); + + var assign = __webpack_require__(8); + var invariant = __webpack_require__(15); + var warning = __webpack_require__(22); + + function enqueueUpdate(internalInstance) { + if (internalInstance !== ReactLifeCycle.currentlyMountingInstance) { + // If we're in a componentWillMount handler, don't enqueue a rerender + // because ReactUpdates assumes we're in a browser context (which is + // wrong for server rendering) and we're about to do a render anyway. + // See bug in #1740. + ReactUpdates.enqueueUpdate(internalInstance); + } + } + + function getInternalInstanceReadyForUpdate(publicInstance, callerName) { + ("production" !== process.env.NODE_ENV ? invariant( + ReactCurrentOwner.current == null, + '%s(...): Cannot update during an existing state transition ' + + '(such as within `render`). Render methods should be a pure function ' + + 'of props and state.', + callerName + ) : invariant(ReactCurrentOwner.current == null)); + + var internalInstance = ReactInstanceMap.get(publicInstance); + if (!internalInstance) { + if ("production" !== process.env.NODE_ENV) { + // Only warn when we have a callerName. Otherwise we should be silent. + // We're probably calling from enqueueCallback. We don't want to warn + // there because we already warned for the corresponding lifecycle method. + ("production" !== process.env.NODE_ENV ? warning( + !callerName, + '%s(...): Can only update a mounted or mounting component. ' + + 'This usually means you called %s() on an unmounted ' + + 'component. This is a no-op.', + callerName, + callerName + ) : null); + } + return null; + } + + if (internalInstance === ReactLifeCycle.currentlyUnmountingInstance) { + return null; + } + + return internalInstance; + } + + /** + * ReactUpdateQueue allows for state updates to be scheduled into a later + * reconciliation step. + */ + var ReactUpdateQueue = { + + /** + * Enqueue a callback that will be executed after all the pending updates + * have processed. + * + * @param {ReactClass} publicInstance The instance to use as `this` context. + * @param {?function} callback Called after state is updated. + * @internal + */ + enqueueCallback: function(publicInstance, callback) { + ("production" !== process.env.NODE_ENV ? invariant( + typeof callback === 'function', + 'enqueueCallback(...): You called `setProps`, `replaceProps`, ' + + '`setState`, `replaceState`, or `forceUpdate` with a callback that ' + + 'isn\'t callable.' + ) : invariant(typeof callback === 'function')); + var internalInstance = getInternalInstanceReadyForUpdate(publicInstance); + + // Previously we would throw an error if we didn't have an internal + // instance. Since we want to make it a no-op instead, we mirror the same + // behavior we have in other enqueue* methods. + // We also need to ignore callbacks in componentWillMount. See + // enqueueUpdates. + if (!internalInstance || + internalInstance === ReactLifeCycle.currentlyMountingInstance) { + return null; + } + + if (internalInstance._pendingCallbacks) { + internalInstance._pendingCallbacks.push(callback); + } else { + internalInstance._pendingCallbacks = [callback]; + } + // TODO: The callback here is ignored when setState is called from + // componentWillMount. Either fix it or disallow doing so completely in + // favor of getInitialState. Alternatively, we can disallow + // componentWillMount during server-side rendering. + enqueueUpdate(internalInstance); + }, + + enqueueCallbackInternal: function(internalInstance, callback) { + ("production" !== process.env.NODE_ENV ? invariant( + typeof callback === 'function', + 'enqueueCallback(...): You called `setProps`, `replaceProps`, ' + + '`setState`, `replaceState`, or `forceUpdate` with a callback that ' + + 'isn\'t callable.' + ) : invariant(typeof callback === 'function')); + if (internalInstance._pendingCallbacks) { + internalInstance._pendingCallbacks.push(callback); + } else { + internalInstance._pendingCallbacks = [callback]; + } + enqueueUpdate(internalInstance); + }, + + /** + * Forces an update. This should only be invoked when it is known with + * certainty that we are **not** in a DOM transaction. + * + * You may want to call this when you know that some deeper aspect of the + * component's state has changed but `setState` was not called. + * + * This will not invoke `shouldUpdateComponent`, but it will invoke + * `componentWillUpdate` and `componentDidUpdate`. + * + * @param {ReactClass} publicInstance The instance that should rerender. + * @internal + */ + enqueueForceUpdate: function(publicInstance) { + var internalInstance = getInternalInstanceReadyForUpdate( + publicInstance, + 'forceUpdate' + ); + + if (!internalInstance) { + return; + } + + internalInstance._pendingForceUpdate = true; + + enqueueUpdate(internalInstance); + }, + + /** + * Replaces all of the state. Always use this or `setState` to mutate state. + * You should treat `this.state` as immutable. + * + * There is no guarantee that `this.state` will be immediately updated, so + * accessing `this.state` after calling this method may return the old value. + * + * @param {ReactClass} publicInstance The instance that should rerender. + * @param {object} completeState Next state. + * @internal + */ + enqueueReplaceState: function(publicInstance, completeState) { + var internalInstance = getInternalInstanceReadyForUpdate( + publicInstance, + 'replaceState' + ); + + if (!internalInstance) { + return; + } + + internalInstance._pendingStateQueue = [completeState]; + internalInstance._pendingReplaceState = true; + + enqueueUpdate(internalInstance); + }, + + /** + * Sets a subset of the state. This only exists because _pendingState is + * internal. This provides a merging strategy that is not available to deep + * properties which is confusing. TODO: Expose pendingState or don't use it + * during the merge. + * + * @param {ReactClass} publicInstance The instance that should rerender. + * @param {object} partialState Next partial state to be merged with state. + * @internal + */ + enqueueSetState: function(publicInstance, partialState) { + var internalInstance = getInternalInstanceReadyForUpdate( + publicInstance, + 'setState' + ); + + if (!internalInstance) { + return; + } + + var queue = + internalInstance._pendingStateQueue || + (internalInstance._pendingStateQueue = []); + queue.push(partialState); + + enqueueUpdate(internalInstance); + }, + + /** + * Sets a subset of the props. + * + * @param {ReactClass} publicInstance The instance that should rerender. + * @param {object} partialProps Subset of the next props. + * @internal + */ + enqueueSetProps: function(publicInstance, partialProps) { + var internalInstance = getInternalInstanceReadyForUpdate( + publicInstance, + 'setProps' + ); + + if (!internalInstance) { + return; + } + + ("production" !== process.env.NODE_ENV ? invariant( + internalInstance._isTopLevel, + 'setProps(...): You called `setProps` on a ' + + 'component with a parent. This is an anti-pattern since props will ' + + 'get reactively updated when rendered. Instead, change the owner\'s ' + + '`render` method to pass the correct value as props to the component ' + + 'where it is created.' + ) : invariant(internalInstance._isTopLevel)); + + // Merge with the pending element if it exists, otherwise with existing + // element props. + var element = internalInstance._pendingElement || + internalInstance._currentElement; + var props = assign({}, element.props, partialProps); + internalInstance._pendingElement = ReactElement.cloneAndReplaceProps( + element, + props + ); + + enqueueUpdate(internalInstance); + }, + + /** + * Replaces all of the props. + * + * @param {ReactClass} publicInstance The instance that should rerender. + * @param {object} props New props. + * @internal + */ + enqueueReplaceProps: function(publicInstance, props) { + var internalInstance = getInternalInstanceReadyForUpdate( + publicInstance, + 'replaceProps' + ); + + if (!internalInstance) { + return; + } + + ("production" !== process.env.NODE_ENV ? invariant( + internalInstance._isTopLevel, + 'replaceProps(...): You called `replaceProps` on a ' + + 'component with a parent. This is an anti-pattern since props will ' + + 'get reactively updated when rendered. Instead, change the owner\'s ' + + '`render` method to pass the correct value as props to the component ' + + 'where it is created.' + ) : invariant(internalInstance._isTopLevel)); + + // Merge with the pending element if it exists, otherwise with existing + // element props. + var element = internalInstance._pendingElement || + internalInstance._currentElement; + internalInstance._pendingElement = ReactElement.cloneAndReplaceProps( + element, + props + ); + + enqueueUpdate(internalInstance); + }, + + enqueueElementInternal: function(internalInstance, newElement) { + internalInstance._pendingElement = newElement; + enqueueUpdate(internalInstance); + } + + }; + + module.exports = ReactUpdateQueue; + + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(11))) + +/***/ }, +/* 31 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactUpdates + */ + + 'use strict'; + + var CallbackQueue = __webpack_require__(32); + var PooledClass = __webpack_require__(17); + var ReactCurrentOwner = __webpack_require__(24); + var ReactPerf = __webpack_require__(33); + var ReactReconciler = __webpack_require__(34); + var Transaction = __webpack_require__(41); + + var assign = __webpack_require__(8); + var invariant = __webpack_require__(15); + var warning = __webpack_require__(22); + + var dirtyComponents = []; + var asapCallbackQueue = CallbackQueue.getPooled(); + var asapEnqueued = false; + + var batchingStrategy = null; + + function ensureInjected() { + ("production" !== process.env.NODE_ENV ? invariant( + ReactUpdates.ReactReconcileTransaction && batchingStrategy, + 'ReactUpdates: must inject a reconcile transaction class and batching ' + + 'strategy' + ) : invariant(ReactUpdates.ReactReconcileTransaction && batchingStrategy)); + } + + var NESTED_UPDATES = { + initialize: function() { + this.dirtyComponentsLength = dirtyComponents.length; + }, + close: function() { + if (this.dirtyComponentsLength !== dirtyComponents.length) { + // Additional updates were enqueued by componentDidUpdate handlers or + // similar; before our own UPDATE_QUEUEING wrapper closes, we want to run + // these new updates so that if A's componentDidUpdate calls setState on + // B, B will update before the callback A's updater provided when calling + // setState. + dirtyComponents.splice(0, this.dirtyComponentsLength); + flushBatchedUpdates(); + } else { + dirtyComponents.length = 0; + } + } + }; + + var UPDATE_QUEUEING = { + initialize: function() { + this.callbackQueue.reset(); + }, + close: function() { + this.callbackQueue.notifyAll(); + } + }; + + var TRANSACTION_WRAPPERS = [NESTED_UPDATES, UPDATE_QUEUEING]; + + function ReactUpdatesFlushTransaction() { + this.reinitializeTransaction(); + this.dirtyComponentsLength = null; + this.callbackQueue = CallbackQueue.getPooled(); + this.reconcileTransaction = + ReactUpdates.ReactReconcileTransaction.getPooled(); + } + + assign( + ReactUpdatesFlushTransaction.prototype, + Transaction.Mixin, { + getTransactionWrappers: function() { + return TRANSACTION_WRAPPERS; + }, + + destructor: function() { + this.dirtyComponentsLength = null; + CallbackQueue.release(this.callbackQueue); + this.callbackQueue = null; + ReactUpdates.ReactReconcileTransaction.release(this.reconcileTransaction); + this.reconcileTransaction = null; + }, + + perform: function(method, scope, a) { + // Essentially calls `this.reconcileTransaction.perform(method, scope, a)` + // with this transaction's wrappers around it. + return Transaction.Mixin.perform.call( + this, + this.reconcileTransaction.perform, + this.reconcileTransaction, + method, + scope, + a + ); + } + }); + + PooledClass.addPoolingTo(ReactUpdatesFlushTransaction); + + function batchedUpdates(callback, a, b, c, d) { + ensureInjected(); + batchingStrategy.batchedUpdates(callback, a, b, c, d); + } + + /** + * Array comparator for ReactComponents by mount ordering. + * + * @param {ReactComponent} c1 first component you're comparing + * @param {ReactComponent} c2 second component you're comparing + * @return {number} Return value usable by Array.prototype.sort(). + */ + function mountOrderComparator(c1, c2) { + return c1._mountOrder - c2._mountOrder; + } + + function runBatchedUpdates(transaction) { + var len = transaction.dirtyComponentsLength; + ("production" !== process.env.NODE_ENV ? invariant( + len === dirtyComponents.length, + 'Expected flush transaction\'s stored dirty-components length (%s) to ' + + 'match dirty-components array length (%s).', + len, + dirtyComponents.length + ) : invariant(len === dirtyComponents.length)); + + // Since reconciling a component higher in the owner hierarchy usually (not + // always -- see shouldComponentUpdate()) will reconcile children, reconcile + // them before their children by sorting the array. + dirtyComponents.sort(mountOrderComparator); + + for (var i = 0; i < len; i++) { + // If a component is unmounted before pending changes apply, it will still + // be here, but we assume that it has cleared its _pendingCallbacks and + // that performUpdateIfNecessary is a noop. + var component = dirtyComponents[i]; + + // If performUpdateIfNecessary happens to enqueue any new updates, we + // shouldn't execute the callbacks until the next render happens, so + // stash the callbacks first + var callbacks = component._pendingCallbacks; + component._pendingCallbacks = null; + + ReactReconciler.performUpdateIfNecessary( + component, + transaction.reconcileTransaction + ); + + if (callbacks) { + for (var j = 0; j < callbacks.length; j++) { + transaction.callbackQueue.enqueue( + callbacks[j], + component.getPublicInstance() + ); + } + } + } + } + + var flushBatchedUpdates = function() { + // ReactUpdatesFlushTransaction's wrappers will clear the dirtyComponents + // array and perform any updates enqueued by mount-ready handlers (i.e., + // componentDidUpdate) but we need to check here too in order to catch + // updates enqueued by setState callbacks and asap calls. + while (dirtyComponents.length || asapEnqueued) { + if (dirtyComponents.length) { + var transaction = ReactUpdatesFlushTransaction.getPooled(); + transaction.perform(runBatchedUpdates, null, transaction); + ReactUpdatesFlushTransaction.release(transaction); + } + + if (asapEnqueued) { + asapEnqueued = false; + var queue = asapCallbackQueue; + asapCallbackQueue = CallbackQueue.getPooled(); + queue.notifyAll(); + CallbackQueue.release(queue); + } + } + }; + flushBatchedUpdates = ReactPerf.measure( + 'ReactUpdates', + 'flushBatchedUpdates', + flushBatchedUpdates + ); + + /** + * Mark a component as needing a rerender, adding an optional callback to a + * list of functions which will be executed once the rerender occurs. + */ + function enqueueUpdate(component) { + ensureInjected(); + + // Various parts of our code (such as ReactCompositeComponent's + // _renderValidatedComponent) assume that calls to render aren't nested; + // verify that that's the case. (This is called by each top-level update + // function, like setProps, setState, forceUpdate, etc.; creation and + // destruction of top-level components is guarded in ReactMount.) + ("production" !== process.env.NODE_ENV ? warning( + ReactCurrentOwner.current == null, + 'enqueueUpdate(): Render methods should be a pure function of props ' + + 'and state; triggering nested component updates from render is not ' + + 'allowed. If necessary, trigger nested updates in ' + + 'componentDidUpdate.' + ) : null); + + if (!batchingStrategy.isBatchingUpdates) { + batchingStrategy.batchedUpdates(enqueueUpdate, component); + return; + } + + dirtyComponents.push(component); + } + + /** + * Enqueue a callback to be run at the end of the current batching cycle. Throws + * if no updates are currently being performed. + */ + function asap(callback, context) { + ("production" !== process.env.NODE_ENV ? invariant( + batchingStrategy.isBatchingUpdates, + 'ReactUpdates.asap: Can\'t enqueue an asap callback in a context where' + + 'updates are not being batched.' + ) : invariant(batchingStrategy.isBatchingUpdates)); + asapCallbackQueue.enqueue(callback, context); + asapEnqueued = true; + } + + var ReactUpdatesInjection = { + injectReconcileTransaction: function(ReconcileTransaction) { + ("production" !== process.env.NODE_ENV ? invariant( + ReconcileTransaction, + 'ReactUpdates: must provide a reconcile transaction class' + ) : invariant(ReconcileTransaction)); + ReactUpdates.ReactReconcileTransaction = ReconcileTransaction; + }, + + injectBatchingStrategy: function(_batchingStrategy) { + ("production" !== process.env.NODE_ENV ? invariant( + _batchingStrategy, + 'ReactUpdates: must provide a batching strategy' + ) : invariant(_batchingStrategy)); + ("production" !== process.env.NODE_ENV ? invariant( + typeof _batchingStrategy.batchedUpdates === 'function', + 'ReactUpdates: must provide a batchedUpdates() function' + ) : invariant(typeof _batchingStrategy.batchedUpdates === 'function')); + ("production" !== process.env.NODE_ENV ? invariant( + typeof _batchingStrategy.isBatchingUpdates === 'boolean', + 'ReactUpdates: must provide an isBatchingUpdates boolean attribute' + ) : invariant(typeof _batchingStrategy.isBatchingUpdates === 'boolean')); + batchingStrategy = _batchingStrategy; + } + }; + + var ReactUpdates = { + /** + * React references `ReactReconcileTransaction` using this property in order + * to allow dependency injection. + * + * @internal + */ + ReactReconcileTransaction: null, + + batchedUpdates: batchedUpdates, + enqueueUpdate: enqueueUpdate, + flushBatchedUpdates: flushBatchedUpdates, + injection: ReactUpdatesInjection, + asap: asap + }; + + module.exports = ReactUpdates; + + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(11))) + +/***/ }, +/* 32 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule CallbackQueue + */ + + 'use strict'; + + var PooledClass = __webpack_require__(17); + + var assign = __webpack_require__(8); + var invariant = __webpack_require__(15); + + /** + * A specialized pseudo-event module to help keep track of components waiting to + * be notified when their DOM representations are available for use. + * + * This implements `PooledClass`, so you should never need to instantiate this. + * Instead, use `CallbackQueue.getPooled()`. + * + * @class ReactMountReady + * @implements PooledClass + * @internal + */ + function CallbackQueue() { + this._callbacks = null; + this._contexts = null; + } + + assign(CallbackQueue.prototype, { + + /** + * Enqueues a callback to be invoked when `notifyAll` is invoked. + * + * @param {function} callback Invoked when `notifyAll` is invoked. + * @param {?object} context Context to call `callback` with. + * @internal + */ + enqueue: function(callback, context) { + this._callbacks = this._callbacks || []; + this._contexts = this._contexts || []; + this._callbacks.push(callback); + this._contexts.push(context); + }, + + /** + * Invokes all enqueued callbacks and clears the queue. This is invoked after + * the DOM representation of a component has been created or updated. + * + * @internal + */ + notifyAll: function() { + var callbacks = this._callbacks; + var contexts = this._contexts; + if (callbacks) { + ("production" !== process.env.NODE_ENV ? invariant( + callbacks.length === contexts.length, + 'Mismatched list of contexts in callback queue' + ) : invariant(callbacks.length === contexts.length)); + this._callbacks = null; + this._contexts = null; + for (var i = 0, l = callbacks.length; i < l; i++) { + callbacks[i].call(contexts[i]); + } + callbacks.length = 0; + contexts.length = 0; + } + }, + + /** + * Resets the internal queue. + * + * @internal + */ + reset: function() { + this._callbacks = null; + this._contexts = null; + }, + + /** + * `PooledClass` looks for this. + */ + destructor: function() { + this.reset(); + } + + }); + + PooledClass.addPoolingTo(CallbackQueue); + + module.exports = CallbackQueue; + + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(11))) + +/***/ }, +/* 33 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactPerf + * @typechecks static-only + */ + + 'use strict'; + + /** + * ReactPerf is a general AOP system designed to measure performance. This + * module only has the hooks: see ReactDefaultPerf for the analysis tool. + */ + var ReactPerf = { + /** + * Boolean to enable/disable measurement. Set to false by default to prevent + * accidental logging and perf loss. + */ + enableMeasure: false, + + /** + * Holds onto the measure function in use. By default, don't measure + * anything, but we'll override this if we inject a measure function. + */ + storedMeasure: _noMeasure, + + /** + * @param {object} object + * @param {string} objectName + * @param {object} methodNames + */ + measureMethods: function(object, objectName, methodNames) { + if ("production" !== process.env.NODE_ENV) { + for (var key in methodNames) { + if (!methodNames.hasOwnProperty(key)) { + continue; + } + object[key] = ReactPerf.measure( + objectName, + methodNames[key], + object[key] + ); + } + } + }, + + /** + * Use this to wrap methods you want to measure. Zero overhead in production. + * + * @param {string} objName + * @param {string} fnName + * @param {function} func + * @return {function} + */ + measure: function(objName, fnName, func) { + if ("production" !== process.env.NODE_ENV) { + var measuredFunc = null; + var wrapper = function() { + if (ReactPerf.enableMeasure) { + if (!measuredFunc) { + measuredFunc = ReactPerf.storedMeasure(objName, fnName, func); + } + return measuredFunc.apply(this, arguments); + } + return func.apply(this, arguments); + }; + wrapper.displayName = objName + '_' + fnName; + return wrapper; + } + return func; + }, + + injection: { + /** + * @param {function} measure + */ + injectMeasure: function(measure) { + ReactPerf.storedMeasure = measure; + } + } + }; + + /** + * Simply passes through the measured function, without measuring it. + * + * @param {string} objName + * @param {string} fnName + * @param {function} func + * @return {function} + */ + function _noMeasure(objName, fnName, func) { + return func; + } + + module.exports = ReactPerf; + + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(11))) + +/***/ }, +/* 34 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactReconciler + */ + + 'use strict'; + + var ReactRef = __webpack_require__(35); + var ReactElementValidator = __webpack_require__(37); + + /** + * Helper to call ReactRef.attachRefs with this composite component, split out + * to avoid allocations in the transaction mount-ready queue. + */ + function attachRefs() { + ReactRef.attachRefs(this, this._currentElement); + } + + var ReactReconciler = { + + /** + * Initializes the component, renders markup, and registers event listeners. + * + * @param {ReactComponent} internalInstance + * @param {string} rootID DOM ID of the root node. + * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction + * @return {?string} Rendered markup to be inserted into the DOM. + * @final + * @internal + */ + mountComponent: function(internalInstance, rootID, transaction, context) { + var markup = internalInstance.mountComponent(rootID, transaction, context); + if ("production" !== process.env.NODE_ENV) { + ReactElementValidator.checkAndWarnForMutatedProps( + internalInstance._currentElement + ); + } + transaction.getReactMountReady().enqueue(attachRefs, internalInstance); + return markup; + }, + + /** + * Releases any resources allocated by `mountComponent`. + * + * @final + * @internal + */ + unmountComponent: function(internalInstance) { + ReactRef.detachRefs(internalInstance, internalInstance._currentElement); + internalInstance.unmountComponent(); + }, + + /** + * Update a component using a new element. + * + * @param {ReactComponent} internalInstance + * @param {ReactElement} nextElement + * @param {ReactReconcileTransaction} transaction + * @param {object} context + * @internal + */ + receiveComponent: function( + internalInstance, nextElement, transaction, context + ) { + var prevElement = internalInstance._currentElement; + + if (nextElement === prevElement && nextElement._owner != null) { + // Since elements are immutable after the owner is rendered, + // we can do a cheap identity compare here to determine if this is a + // superfluous reconcile. It's possible for state to be mutable but such + // change should trigger an update of the owner which would recreate + // the element. We explicitly check for the existence of an owner since + // it's possible for an element created outside a composite to be + // deeply mutated and reused. + return; + } + + if ("production" !== process.env.NODE_ENV) { + ReactElementValidator.checkAndWarnForMutatedProps(nextElement); + } + + var refsChanged = ReactRef.shouldUpdateRefs( + prevElement, + nextElement + ); + + if (refsChanged) { + ReactRef.detachRefs(internalInstance, prevElement); + } + + internalInstance.receiveComponent(nextElement, transaction, context); + + if (refsChanged) { + transaction.getReactMountReady().enqueue(attachRefs, internalInstance); + } + }, + + /** + * Flush any dirty changes in a component. + * + * @param {ReactComponent} internalInstance + * @param {ReactReconcileTransaction} transaction + * @internal + */ + performUpdateIfNecessary: function( + internalInstance, + transaction + ) { + internalInstance.performUpdateIfNecessary(transaction); + } + + }; + + module.exports = ReactReconciler; + + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(11))) + +/***/ }, +/* 35 */ +/***/ function(module, exports, __webpack_require__) { + + /** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactRef + */ + + 'use strict'; + + var ReactOwner = __webpack_require__(36); + + var ReactRef = {}; + + function attachRef(ref, component, owner) { + if (typeof ref === 'function') { + ref(component.getPublicInstance()); + } else { + // Legacy ref + ReactOwner.addComponentAsRefTo(component, ref, owner); + } + } + + function detachRef(ref, component, owner) { + if (typeof ref === 'function') { + ref(null); + } else { + // Legacy ref + ReactOwner.removeComponentAsRefFrom(component, ref, owner); + } + } + + ReactRef.attachRefs = function(instance, element) { + var ref = element.ref; + if (ref != null) { + attachRef(ref, instance, element._owner); + } + }; + + ReactRef.shouldUpdateRefs = function(prevElement, nextElement) { + // If either the owner or a `ref` has changed, make sure the newest owner + // has stored a reference to `this`, and the previous owner (if different) + // has forgotten the reference to `this`. We use the element instead + // of the public this.props because the post processing cannot determine + // a ref. The ref conceptually lives on the element. + + // TODO: Should this even be possible? The owner cannot change because + // it's forbidden by shouldUpdateReactComponent. The ref can change + // if you swap the keys of but not the refs. Reconsider where this check + // is made. It probably belongs where the key checking and + // instantiateReactComponent is done. + + return ( + nextElement._owner !== prevElement._owner || + nextElement.ref !== prevElement.ref + ); + }; + + ReactRef.detachRefs = function(instance, element) { + var ref = element.ref; + if (ref != null) { + detachRef(ref, instance, element._owner); + } + }; + + module.exports = ReactRef; + + +/***/ }, +/* 36 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactOwner + */ + + 'use strict'; + + var invariant = __webpack_require__(15); + + /** + * ReactOwners are capable of storing references to owned components. + * + * All components are capable of //being// referenced by owner components, but + * only ReactOwner components are capable of //referencing// owned components. + * The named reference is known as a "ref". + * + * Refs are available when mounted and updated during reconciliation. + * + * var MyComponent = React.createClass({ + * render: function() { + * return ( + *
+ * + *
+ * ); + * }, + * handleClick: function() { + * this.refs.custom.handleClick(); + * }, + * componentDidMount: function() { + * this.refs.custom.initialize(); + * } + * }); + * + * Refs should rarely be used. When refs are used, they should only be done to + * control data that is not handled by React's data flow. + * + * @class ReactOwner + */ + var ReactOwner = { + + /** + * @param {?object} object + * @return {boolean} True if `object` is a valid owner. + * @final + */ + isValidOwner: function(object) { + return !!( + (object && + typeof object.attachRef === 'function' && typeof object.detachRef === 'function') + ); + }, + + /** + * Adds a component by ref to an owner component. + * + * @param {ReactComponent} component Component to reference. + * @param {string} ref Name by which to refer to the component. + * @param {ReactOwner} owner Component on which to record the ref. + * @final + * @internal + */ + addComponentAsRefTo: function(component, ref, owner) { + ("production" !== process.env.NODE_ENV ? invariant( + ReactOwner.isValidOwner(owner), + 'addComponentAsRefTo(...): Only a ReactOwner can have refs. This ' + + 'usually means that you\'re trying to add a ref to a component that ' + + 'doesn\'t have an owner (that is, was not created inside of another ' + + 'component\'s `render` method). Try rendering this component inside of ' + + 'a new top-level component which will hold the ref.' + ) : invariant(ReactOwner.isValidOwner(owner))); + owner.attachRef(ref, component); + }, + + /** + * Removes a component by ref from an owner component. + * + * @param {ReactComponent} component Component to dereference. + * @param {string} ref Name of the ref to remove. + * @param {ReactOwner} owner Component on which the ref is recorded. + * @final + * @internal + */ + removeComponentAsRefFrom: function(component, ref, owner) { + ("production" !== process.env.NODE_ENV ? invariant( + ReactOwner.isValidOwner(owner), + 'removeComponentAsRefFrom(...): Only a ReactOwner can have refs. This ' + + 'usually means that you\'re trying to remove a ref to a component that ' + + 'doesn\'t have an owner (that is, was not created inside of another ' + + 'component\'s `render` method). Try rendering this component inside of ' + + 'a new top-level component which will hold the ref.' + ) : invariant(ReactOwner.isValidOwner(owner))); + // Check that `component` is still the current ref because we do not want to + // detach the ref if another component stole it. + if (owner.getPublicInstance().refs[ref] === component.getPublicInstance()) { + owner.detachRef(ref); + } + } + + }; + + module.exports = ReactOwner; + + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(11))) + +/***/ }, +/* 37 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2014-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactElementValidator + */ + + /** + * ReactElementValidator provides a wrapper around a element factory + * which validates the props passed to the element. This is intended to be + * used only in DEV and could be replaced by a static type checker for languages + * that support it. + */ + + 'use strict'; + + var ReactElement = __webpack_require__(19); + var ReactFragment = __webpack_require__(18); + var ReactPropTypeLocations = __webpack_require__(38); + var ReactPropTypeLocationNames = __webpack_require__(39); + var ReactCurrentOwner = __webpack_require__(24); + var ReactNativeComponent = __webpack_require__(40); + + var getIteratorFn = __webpack_require__(26); + var invariant = __webpack_require__(15); + var warning = __webpack_require__(22); + + function getDeclarationErrorAddendum() { + if (ReactCurrentOwner.current) { + var name = ReactCurrentOwner.current.getName(); + if (name) { + return ' Check the render method of `' + name + '`.'; + } + } + return ''; + } + + /** + * Warn if there's no key explicitly set on dynamic arrays of children or + * object keys are not valid. This allows us to keep track of children between + * updates. + */ + var ownerHasKeyUseWarning = {}; + + var loggedTypeFailures = {}; + + var NUMERIC_PROPERTY_REGEX = /^\d+$/; + + /** + * Gets the instance's name for use in warnings. + * + * @internal + * @return {?string} Display name or undefined + */ + function getName(instance) { + var publicInstance = instance && instance.getPublicInstance(); + if (!publicInstance) { + return undefined; + } + var constructor = publicInstance.constructor; + if (!constructor) { + return undefined; + } + return constructor.displayName || constructor.name || undefined; + } + + /** + * Gets the current owner's displayName for use in warnings. + * + * @internal + * @return {?string} Display name or undefined + */ + function getCurrentOwnerDisplayName() { + var current = ReactCurrentOwner.current; + return ( + current && getName(current) || undefined + ); + } + + /** + * Warn if the element doesn't have an explicit key assigned to it. + * This element is in an array. The array could grow and shrink or be + * reordered. All children that haven't already been validated are required to + * have a "key" property assigned to it. + * + * @internal + * @param {ReactElement} element Element that requires a key. + * @param {*} parentType element's parent's type. + */ + function validateExplicitKey(element, parentType) { + if (element._store.validated || element.key != null) { + return; + } + element._store.validated = true; + + warnAndMonitorForKeyUse( + 'Each child in an array or iterator should have a unique "key" prop.', + element, + parentType + ); + } + + /** + * Warn if the key is being defined as an object property but has an incorrect + * value. + * + * @internal + * @param {string} name Property name of the key. + * @param {ReactElement} element Component that requires a key. + * @param {*} parentType element's parent's type. + */ + function validatePropertyKey(name, element, parentType) { + if (!NUMERIC_PROPERTY_REGEX.test(name)) { + return; + } + warnAndMonitorForKeyUse( + 'Child objects should have non-numeric keys so ordering is preserved.', + element, + parentType + ); + } + + /** + * Shared warning and monitoring code for the key warnings. + * + * @internal + * @param {string} message The base warning that gets output. + * @param {ReactElement} element Component that requires a key. + * @param {*} parentType element's parent's type. + */ + function warnAndMonitorForKeyUse(message, element, parentType) { + var ownerName = getCurrentOwnerDisplayName(); + var parentName = typeof parentType === 'string' ? + parentType : parentType.displayName || parentType.name; + + var useName = ownerName || parentName; + var memoizer = ownerHasKeyUseWarning[message] || ( + (ownerHasKeyUseWarning[message] = {}) + ); + if (memoizer.hasOwnProperty(useName)) { + return; + } + memoizer[useName] = true; + + var parentOrOwnerAddendum = + ownerName ? (" Check the render method of " + ownerName + ".") : + parentName ? (" Check the React.render call using <" + parentName + ">.") : + ''; + + // Usually the current owner is the offender, but if it accepts children as a + // property, it may be the creator of the child that's responsible for + // assigning it a key. + var childOwnerAddendum = ''; + if (element && + element._owner && + element._owner !== ReactCurrentOwner.current) { + // Name of the component that originally created this child. + var childOwnerName = getName(element._owner); + + childOwnerAddendum = (" It was passed a child from " + childOwnerName + "."); + } + + ("production" !== process.env.NODE_ENV ? warning( + false, + message + '%s%s See https://fb.me/react-warning-keys for more information.', + parentOrOwnerAddendum, + childOwnerAddendum + ) : null); + } + + /** + * Ensure that every element either is passed in a static location, in an + * array with an explicit keys property defined, or in an object literal + * with valid key property. + * + * @internal + * @param {ReactNode} node Statically passed child of any type. + * @param {*} parentType node's parent's type. + */ + function validateChildKeys(node, parentType) { + if (Array.isArray(node)) { + for (var i = 0; i < node.length; i++) { + var child = node[i]; + if (ReactElement.isValidElement(child)) { + validateExplicitKey(child, parentType); + } + } + } else if (ReactElement.isValidElement(node)) { + // This element was passed in a valid location. + node._store.validated = true; + } else if (node) { + var iteratorFn = getIteratorFn(node); + // Entry iterators provide implicit keys. + if (iteratorFn) { + if (iteratorFn !== node.entries) { + var iterator = iteratorFn.call(node); + var step; + while (!(step = iterator.next()).done) { + if (ReactElement.isValidElement(step.value)) { + validateExplicitKey(step.value, parentType); + } + } + } + } else if (typeof node === 'object') { + var fragment = ReactFragment.extractIfFragment(node); + for (var key in fragment) { + if (fragment.hasOwnProperty(key)) { + validatePropertyKey(key, fragment[key], parentType); + } + } + } + } + } + + /** + * Assert that the props are valid + * + * @param {string} componentName Name of the component for error messages. + * @param {object} propTypes Map of prop name to a ReactPropType + * @param {object} props + * @param {string} location e.g. "prop", "context", "child context" + * @private + */ + function checkPropTypes(componentName, propTypes, props, location) { + for (var propName in propTypes) { + if (propTypes.hasOwnProperty(propName)) { + var error; + // Prop type validation may throw. In case they do, we don't want to + // fail the render phase where it didn't fail before. So we log it. + // After these have been cleaned up, we'll let them throw. + try { + // This is intentionally an invariant that gets caught. It's the same + // behavior as without this statement except with a better message. + ("production" !== process.env.NODE_ENV ? invariant( + typeof propTypes[propName] === 'function', + '%s: %s type `%s` is invalid; it must be a function, usually from ' + + 'React.PropTypes.', + componentName || 'React class', + ReactPropTypeLocationNames[location], + propName + ) : invariant(typeof propTypes[propName] === 'function')); + error = propTypes[propName](props, propName, componentName, location); + } catch (ex) { + error = ex; + } + if (error instanceof Error && !(error.message in loggedTypeFailures)) { + // Only monitor this failure once because there tends to be a lot of the + // same error. + loggedTypeFailures[error.message] = true; + + var addendum = getDeclarationErrorAddendum(this); + ("production" !== process.env.NODE_ENV ? warning(false, 'Failed propType: %s%s', error.message, addendum) : null); + } + } + } + } + + var warnedPropsMutations = {}; + + /** + * Warn about mutating props when setting `propName` on `element`. + * + * @param {string} propName The string key within props that was set + * @param {ReactElement} element + */ + function warnForPropsMutation(propName, element) { + var type = element.type; + var elementName = typeof type === 'string' ? type : type.displayName; + var ownerName = element._owner ? + element._owner.getPublicInstance().constructor.displayName : null; + + var warningKey = propName + '|' + elementName + '|' + ownerName; + if (warnedPropsMutations.hasOwnProperty(warningKey)) { + return; + } + warnedPropsMutations[warningKey] = true; + + var elementInfo = ''; + if (elementName) { + elementInfo = ' <' + elementName + ' />'; + } + var ownerInfo = ''; + if (ownerName) { + ownerInfo = ' The element was created by ' + ownerName + '.'; + } + + ("production" !== process.env.NODE_ENV ? warning( + false, + 'Don\'t set .props.%s of the React component%s. Instead, specify the ' + + 'correct value when initially creating the element or use ' + + 'React.cloneElement to make a new element with updated props.%s', + propName, + elementInfo, + ownerInfo + ) : null); + } + + // Inline Object.is polyfill + function is(a, b) { + if (a !== a) { + // NaN + return b !== b; + } + if (a === 0 && b === 0) { + // +-0 + return 1 / a === 1 / b; + } + return a === b; + } + + /** + * Given an element, check if its props have been mutated since element + * creation (or the last call to this function). In particular, check if any + * new props have been added, which we can't directly catch by defining warning + * properties on the props object. + * + * @param {ReactElement} element + */ + function checkAndWarnForMutatedProps(element) { + if (!element._store) { + // Element was created using `new ReactElement` directly or with + // `ReactElement.createElement`; skip mutation checking + return; + } + + var originalProps = element._store.originalProps; + var props = element.props; + + for (var propName in props) { + if (props.hasOwnProperty(propName)) { + if (!originalProps.hasOwnProperty(propName) || + !is(originalProps[propName], props[propName])) { + warnForPropsMutation(propName, element); + + // Copy over the new value so that the two props objects match again + originalProps[propName] = props[propName]; + } + } + } + } + + /** + * Given an element, validate that its props follow the propTypes definition, + * provided by the type. + * + * @param {ReactElement} element + */ + function validatePropTypes(element) { + if (element.type == null) { + // This has already warned. Don't throw. + return; + } + // Extract the component class from the element. Converts string types + // to a composite class which may have propTypes. + // TODO: Validating a string's propTypes is not decoupled from the + // rendering target which is problematic. + var componentClass = ReactNativeComponent.getComponentClassForElement( + element + ); + var name = componentClass.displayName || componentClass.name; + if (componentClass.propTypes) { + checkPropTypes( + name, + componentClass.propTypes, + element.props, + ReactPropTypeLocations.prop + ); + } + if (typeof componentClass.getDefaultProps === 'function') { + ("production" !== process.env.NODE_ENV ? warning( + componentClass.getDefaultProps.isReactClassApproved, + 'getDefaultProps is only used on classic React.createClass ' + + 'definitions. Use a static property named `defaultProps` instead.' + ) : null); + } + } + + var ReactElementValidator = { + + checkAndWarnForMutatedProps: checkAndWarnForMutatedProps, + + createElement: function(type, props, children) { + // We warn in this case but don't throw. We expect the element creation to + // succeed and there will likely be errors in render. + ("production" !== process.env.NODE_ENV ? warning( + type != null, + 'React.createElement: type should not be null or undefined. It should ' + + 'be a string (for DOM elements) or a ReactClass (for composite ' + + 'components).' + ) : null); + + var element = ReactElement.createElement.apply(this, arguments); + + // The result can be nullish if a mock or a custom function is used. + // TODO: Drop this when these are no longer allowed as the type argument. + if (element == null) { + return element; + } + + for (var i = 2; i < arguments.length; i++) { + validateChildKeys(arguments[i], type); + } + + validatePropTypes(element); + + return element; + }, + + createFactory: function(type) { + var validatedFactory = ReactElementValidator.createElement.bind( + null, + type + ); + // Legacy hook TODO: Warn if this is accessed + validatedFactory.type = type; + + if ("production" !== process.env.NODE_ENV) { + try { + Object.defineProperty( + validatedFactory, + 'type', + { + enumerable: false, + get: function() { + ("production" !== process.env.NODE_ENV ? warning( + false, + 'Factory.type is deprecated. Access the class directly ' + + 'before passing it to createFactory.' + ) : null); + Object.defineProperty(this, 'type', { + value: type + }); + return type; + } + } + ); + } catch (x) { + // IE will fail on defineProperty (es5-shim/sham too) + } + } + + + return validatedFactory; + }, + + cloneElement: function(element, props, children) { + var newElement = ReactElement.cloneElement.apply(this, arguments); + for (var i = 2; i < arguments.length; i++) { + validateChildKeys(arguments[i], newElement.type); + } + validatePropTypes(newElement); + return newElement; + } + + }; + + module.exports = ReactElementValidator; + + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(11))) + +/***/ }, +/* 38 */ +/***/ function(module, exports, __webpack_require__) { + + /** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactPropTypeLocations + */ + + 'use strict'; + + var keyMirror = __webpack_require__(14); + + var ReactPropTypeLocations = keyMirror({ + prop: null, + context: null, + childContext: null + }); + + module.exports = ReactPropTypeLocations; + + +/***/ }, +/* 39 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactPropTypeLocationNames + */ + + 'use strict'; + + var ReactPropTypeLocationNames = {}; + + if ("production" !== process.env.NODE_ENV) { + ReactPropTypeLocationNames = { + prop: 'prop', + context: 'context', + childContext: 'child context' + }; + } + + module.exports = ReactPropTypeLocationNames; + + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(11))) + +/***/ }, +/* 40 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2014-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactNativeComponent + */ + + 'use strict'; + + var assign = __webpack_require__(8); + var invariant = __webpack_require__(15); + + var autoGenerateWrapperClass = null; + var genericComponentClass = null; + // This registry keeps track of wrapper classes around native tags + var tagToComponentClass = {}; + var textComponentClass = null; + + var ReactNativeComponentInjection = { + // This accepts a class that receives the tag string. This is a catch all + // that can render any kind of tag. + injectGenericComponentClass: function(componentClass) { + genericComponentClass = componentClass; + }, + // This accepts a text component class that takes the text string to be + // rendered as props. + injectTextComponentClass: function(componentClass) { + textComponentClass = componentClass; + }, + // This accepts a keyed object with classes as values. Each key represents a + // tag. That particular tag will use this class instead of the generic one. + injectComponentClasses: function(componentClasses) { + assign(tagToComponentClass, componentClasses); + }, + // Temporary hack since we expect DOM refs to behave like composites, + // for this release. + injectAutoWrapper: function(wrapperFactory) { + autoGenerateWrapperClass = wrapperFactory; + } + }; + + /** + * Get a composite component wrapper class for a specific tag. + * + * @param {ReactElement} element The tag for which to get the class. + * @return {function} The React class constructor function. + */ + function getComponentClassForElement(element) { + if (typeof element.type === 'function') { + return element.type; + } + var tag = element.type; + var componentClass = tagToComponentClass[tag]; + if (componentClass == null) { + tagToComponentClass[tag] = componentClass = autoGenerateWrapperClass(tag); + } + return componentClass; + } + + /** + * Get a native internal component class for a specific tag. + * + * @param {ReactElement} element The element to create. + * @return {function} The internal class constructor function. + */ + function createInternalComponent(element) { + ("production" !== process.env.NODE_ENV ? invariant( + genericComponentClass, + 'There is no registered component for the tag %s', + element.type + ) : invariant(genericComponentClass)); + return new genericComponentClass(element.type, element.props); + } + + /** + * @param {ReactText} text + * @return {ReactComponent} + */ + function createInstanceForText(text) { + return new textComponentClass(text); + } + + /** + * @param {ReactComponent} component + * @return {boolean} + */ + function isTextComponent(component) { + return component instanceof textComponentClass; + } + + var ReactNativeComponent = { + getComponentClassForElement: getComponentClassForElement, + createInternalComponent: createInternalComponent, + createInstanceForText: createInstanceForText, + isTextComponent: isTextComponent, + injection: ReactNativeComponentInjection + }; + + module.exports = ReactNativeComponent; + + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(11))) + +/***/ }, +/* 41 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule Transaction + */ + + 'use strict'; + + var invariant = __webpack_require__(15); + + /** + * `Transaction` creates a black box that is able to wrap any method such that + * certain invariants are maintained before and after the method is invoked + * (Even if an exception is thrown while invoking the wrapped method). Whoever + * instantiates a transaction can provide enforcers of the invariants at + * creation time. The `Transaction` class itself will supply one additional + * automatic invariant for you - the invariant that any transaction instance + * should not be run while it is already being run. You would typically create a + * single instance of a `Transaction` for reuse multiple times, that potentially + * is used to wrap several different methods. Wrappers are extremely simple - + * they only require implementing two methods. + * + *
+	 *                       wrappers (injected at creation time)
+	 *                                      +        +
+	 *                                      |        |
+	 *                    +-----------------|--------|--------------+
+	 *                    |                 v        |              |
+	 *                    |      +---------------+   |              |
+	 *                    |   +--|    wrapper1   |---|----+         |
+	 *                    |   |  +---------------+   v    |         |
+	 *                    |   |          +-------------+  |         |
+	 *                    |   |     +----|   wrapper2  |--------+   |
+	 *                    |   |     |    +-------------+  |     |   |
+	 *                    |   |     |                     |     |   |
+	 *                    |   v     v                     v     v   | wrapper
+	 *                    | +---+ +---+   +---------+   +---+ +---+ | invariants
+	 * perform(anyMethod) | |   | |   |   |         |   |   | |   | | maintained
+	 * +----------------->|-|---|-|---|-->|anyMethod|---|---|-|---|-|-------->
+	 *                    | |   | |   |   |         |   |   | |   | |
+	 *                    | |   | |   |   |         |   |   | |   | |
+	 *                    | |   | |   |   |         |   |   | |   | |
+	 *                    | +---+ +---+   +---------+   +---+ +---+ |
+	 *                    |  initialize                    close    |
+	 *                    +-----------------------------------------+
+	 * 
+ * + * Use cases: + * - Preserving the input selection ranges before/after reconciliation. + * Restoring selection even in the event of an unexpected error. + * - Deactivating events while rearranging the DOM, preventing blurs/focuses, + * while guaranteeing that afterwards, the event system is reactivated. + * - Flushing a queue of collected DOM mutations to the main UI thread after a + * reconciliation takes place in a worker thread. + * - Invoking any collected `componentDidUpdate` callbacks after rendering new + * content. + * - (Future use case): Wrapping particular flushes of the `ReactWorker` queue + * to preserve the `scrollTop` (an automatic scroll aware DOM). + * - (Future use case): Layout calculations before and after DOM updates. + * + * Transactional plugin API: + * - A module that has an `initialize` method that returns any precomputation. + * - and a `close` method that accepts the precomputation. `close` is invoked + * when the wrapped process is completed, or has failed. + * + * @param {Array} transactionWrapper Wrapper modules + * that implement `initialize` and `close`. + * @return {Transaction} Single transaction for reuse in thread. + * + * @class Transaction + */ + var Mixin = { + /** + * Sets up this instance so that it is prepared for collecting metrics. Does + * so such that this setup method may be used on an instance that is already + * initialized, in a way that does not consume additional memory upon reuse. + * That can be useful if you decide to make your subclass of this mixin a + * "PooledClass". + */ + reinitializeTransaction: function() { + this.transactionWrappers = this.getTransactionWrappers(); + if (!this.wrapperInitData) { + this.wrapperInitData = []; + } else { + this.wrapperInitData.length = 0; + } + this._isInTransaction = false; + }, + + _isInTransaction: false, + + /** + * @abstract + * @return {Array} Array of transaction wrappers. + */ + getTransactionWrappers: null, + + isInTransaction: function() { + return !!this._isInTransaction; + }, + + /** + * Executes the function within a safety window. Use this for the top level + * methods that result in large amounts of computation/mutations that would + * need to be safety checked. + * + * @param {function} method Member of scope to call. + * @param {Object} scope Scope to invoke from. + * @param {Object?=} args... Arguments to pass to the method (optional). + * Helps prevent need to bind in many cases. + * @return Return value from `method`. + */ + perform: function(method, scope, a, b, c, d, e, f) { + ("production" !== process.env.NODE_ENV ? invariant( + !this.isInTransaction(), + 'Transaction.perform(...): Cannot initialize a transaction when there ' + + 'is already an outstanding transaction.' + ) : invariant(!this.isInTransaction())); + var errorThrown; + var ret; + try { + this._isInTransaction = true; + // Catching errors makes debugging more difficult, so we start with + // errorThrown set to true before setting it to false after calling + // close -- if it's still set to true in the finally block, it means + // one of these calls threw. + errorThrown = true; + this.initializeAll(0); + ret = method.call(scope, a, b, c, d, e, f); + errorThrown = false; + } finally { + try { + if (errorThrown) { + // If `method` throws, prefer to show that stack trace over any thrown + // by invoking `closeAll`. + try { + this.closeAll(0); + } catch (err) { + } + } else { + // Since `method` didn't throw, we don't want to silence the exception + // here. + this.closeAll(0); + } + } finally { + this._isInTransaction = false; + } + } + return ret; + }, + + initializeAll: function(startIndex) { + var transactionWrappers = this.transactionWrappers; + for (var i = startIndex; i < transactionWrappers.length; i++) { + var wrapper = transactionWrappers[i]; + try { + // Catching errors makes debugging more difficult, so we start with the + // OBSERVED_ERROR state before overwriting it with the real return value + // of initialize -- if it's still set to OBSERVED_ERROR in the finally + // block, it means wrapper.initialize threw. + this.wrapperInitData[i] = Transaction.OBSERVED_ERROR; + this.wrapperInitData[i] = wrapper.initialize ? + wrapper.initialize.call(this) : + null; + } finally { + if (this.wrapperInitData[i] === Transaction.OBSERVED_ERROR) { + // The initializer for wrapper i threw an error; initialize the + // remaining wrappers but silence any exceptions from them to ensure + // that the first error is the one to bubble up. + try { + this.initializeAll(i + 1); + } catch (err) { + } + } + } + } + }, + + /** + * Invokes each of `this.transactionWrappers.close[i]` functions, passing into + * them the respective return values of `this.transactionWrappers.init[i]` + * (`close`rs that correspond to initializers that failed will not be + * invoked). + */ + closeAll: function(startIndex) { + ("production" !== process.env.NODE_ENV ? invariant( + this.isInTransaction(), + 'Transaction.closeAll(): Cannot close transaction when none are open.' + ) : invariant(this.isInTransaction())); + var transactionWrappers = this.transactionWrappers; + for (var i = startIndex; i < transactionWrappers.length; i++) { + var wrapper = transactionWrappers[i]; + var initData = this.wrapperInitData[i]; + var errorThrown; + try { + // Catching errors makes debugging more difficult, so we start with + // errorThrown set to true before setting it to false after calling + // close -- if it's still set to true in the finally block, it means + // wrapper.close threw. + errorThrown = true; + if (initData !== Transaction.OBSERVED_ERROR && wrapper.close) { + wrapper.close.call(this, initData); + } + errorThrown = false; + } finally { + if (errorThrown) { + // The closer for wrapper i threw an error; close the remaining + // wrappers but silence any exceptions from them to ensure that the + // first error is the one to bubble up. + try { + this.closeAll(i + 1); + } catch (e) { + } + } + } + } + this.wrapperInitData.length = 0; + } + }; + + var Transaction = { + + Mixin: Mixin, + + /** + * Token to look for to determine if an error occured. + */ + OBSERVED_ERROR: {} + + }; + + module.exports = Transaction; + + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(11))) + +/***/ }, +/* 42 */ +/***/ function(module, exports) { + + /** + * Copyright 2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactLifeCycle + */ + + 'use strict'; + + /** + * This module manages the bookkeeping when a component is in the process + * of being mounted or being unmounted. This is used as a way to enforce + * invariants (or warnings) when it is not recommended to call + * setState/forceUpdate. + * + * currentlyMountingInstance: During the construction phase, it is not possible + * to trigger an update since the instance is not fully mounted yet. However, we + * currently allow this as a convenience for mutating the initial state. + * + * currentlyUnmountingInstance: During the unmounting phase, the instance is + * still mounted and can therefore schedule an update. However, this is not + * recommended and probably an error since it's about to be unmounted. + * Therefore we still want to trigger in an error for that case. + */ + + var ReactLifeCycle = { + currentlyMountingInstance: null, + currentlyUnmountingInstance: null + }; + + module.exports = ReactLifeCycle; + + +/***/ }, +/* 43 */ +/***/ function(module, exports) { + + /** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactInstanceMap + */ + + 'use strict'; + + /** + * `ReactInstanceMap` maintains a mapping from a public facing stateful + * instance (key) and the internal representation (value). This allows public + * methods to accept the user facing instance as an argument and map them back + * to internal methods. + */ + + // TODO: Replace this with ES6: var ReactInstanceMap = new Map(); + var ReactInstanceMap = { + + /** + * This API should be called `delete` but we'd have to make sure to always + * transform these to strings for IE support. When this transform is fully + * supported we can rename it. + */ + remove: function(key) { + key._reactInternalInstance = undefined; + }, + + get: function(key) { + return key._reactInternalInstance; + }, + + has: function(key) { + return key._reactInternalInstance !== undefined; + }, + + set: function(key, value) { + key._reactInternalInstance = value; + } + + }; + + module.exports = ReactInstanceMap; + + +/***/ }, +/* 44 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactClass + */ + + 'use strict'; + + var ReactComponent = __webpack_require__(29); + var ReactCurrentOwner = __webpack_require__(24); + var ReactElement = __webpack_require__(19); + var ReactErrorUtils = __webpack_require__(45); + var ReactInstanceMap = __webpack_require__(43); + var ReactLifeCycle = __webpack_require__(42); + var ReactPropTypeLocations = __webpack_require__(38); + var ReactPropTypeLocationNames = __webpack_require__(39); + var ReactUpdateQueue = __webpack_require__(30); + + var assign = __webpack_require__(8); + var invariant = __webpack_require__(15); + var keyMirror = __webpack_require__(14); + var keyOf = __webpack_require__(46); + var warning = __webpack_require__(22); + + var MIXINS_KEY = keyOf({mixins: null}); + + /** + * Policies that describe methods in `ReactClassInterface`. + */ + var SpecPolicy = keyMirror({ + /** + * These methods may be defined only once by the class specification or mixin. + */ + DEFINE_ONCE: null, + /** + * These methods may be defined by both the class specification and mixins. + * Subsequent definitions will be chained. These methods must return void. + */ + DEFINE_MANY: null, + /** + * These methods are overriding the base class. + */ + OVERRIDE_BASE: null, + /** + * These methods are similar to DEFINE_MANY, except we assume they return + * objects. We try to merge the keys of the return values of all the mixed in + * functions. If there is a key conflict we throw. + */ + DEFINE_MANY_MERGED: null + }); + + + var injectedMixins = []; + + /** + * Composite components are higher-level components that compose other composite + * or native components. + * + * To create a new type of `ReactClass`, pass a specification of + * your new class to `React.createClass`. The only requirement of your class + * specification is that you implement a `render` method. + * + * var MyComponent = React.createClass({ + * render: function() { + * return
Hello World
; + * } + * }); + * + * The class specification supports a specific protocol of methods that have + * special meaning (e.g. `render`). See `ReactClassInterface` for + * more the comprehensive protocol. Any other properties and methods in the + * class specification will available on the prototype. + * + * @interface ReactClassInterface + * @internal + */ + var ReactClassInterface = { + + /** + * An array of Mixin objects to include when defining your component. + * + * @type {array} + * @optional + */ + mixins: SpecPolicy.DEFINE_MANY, + + /** + * An object containing properties and methods that should be defined on + * the component's constructor instead of its prototype (static methods). + * + * @type {object} + * @optional + */ + statics: SpecPolicy.DEFINE_MANY, + + /** + * Definition of prop types for this component. + * + * @type {object} + * @optional + */ + propTypes: SpecPolicy.DEFINE_MANY, + + /** + * Definition of context types for this component. + * + * @type {object} + * @optional + */ + contextTypes: SpecPolicy.DEFINE_MANY, + + /** + * Definition of context types this component sets for its children. + * + * @type {object} + * @optional + */ + childContextTypes: SpecPolicy.DEFINE_MANY, + + // ==== Definition methods ==== + + /** + * Invoked when the component is mounted. Values in the mapping will be set on + * `this.props` if that prop is not specified (i.e. using an `in` check). + * + * This method is invoked before `getInitialState` and therefore cannot rely + * on `this.state` or use `this.setState`. + * + * @return {object} + * @optional + */ + getDefaultProps: SpecPolicy.DEFINE_MANY_MERGED, + + /** + * Invoked once before the component is mounted. The return value will be used + * as the initial value of `this.state`. + * + * getInitialState: function() { + * return { + * isOn: false, + * fooBaz: new BazFoo() + * } + * } + * + * @return {object} + * @optional + */ + getInitialState: SpecPolicy.DEFINE_MANY_MERGED, + + /** + * @return {object} + * @optional + */ + getChildContext: SpecPolicy.DEFINE_MANY_MERGED, + + /** + * Uses props from `this.props` and state from `this.state` to render the + * structure of the component. + * + * No guarantees are made about when or how often this method is invoked, so + * it must not have side effects. + * + * render: function() { + * var name = this.props.name; + * return
Hello, {name}!
; + * } + * + * @return {ReactComponent} + * @nosideeffects + * @required + */ + render: SpecPolicy.DEFINE_ONCE, + + + + // ==== Delegate methods ==== + + /** + * Invoked when the component is initially created and about to be mounted. + * This may have side effects, but any external subscriptions or data created + * by this method must be cleaned up in `componentWillUnmount`. + * + * @optional + */ + componentWillMount: SpecPolicy.DEFINE_MANY, + + /** + * Invoked when the component has been mounted and has a DOM representation. + * However, there is no guarantee that the DOM node is in the document. + * + * Use this as an opportunity to operate on the DOM when the component has + * been mounted (initialized and rendered) for the first time. + * + * @param {DOMElement} rootNode DOM element representing the component. + * @optional + */ + componentDidMount: SpecPolicy.DEFINE_MANY, + + /** + * Invoked before the component receives new props. + * + * Use this as an opportunity to react to a prop transition by updating the + * state using `this.setState`. Current props are accessed via `this.props`. + * + * componentWillReceiveProps: function(nextProps, nextContext) { + * this.setState({ + * likesIncreasing: nextProps.likeCount > this.props.likeCount + * }); + * } + * + * NOTE: There is no equivalent `componentWillReceiveState`. An incoming prop + * transition may cause a state change, but the opposite is not true. If you + * need it, you are probably looking for `componentWillUpdate`. + * + * @param {object} nextProps + * @optional + */ + componentWillReceiveProps: SpecPolicy.DEFINE_MANY, + + /** + * Invoked while deciding if the component should be updated as a result of + * receiving new props, state and/or context. + * + * Use this as an opportunity to `return false` when you're certain that the + * transition to the new props/state/context will not require a component + * update. + * + * shouldComponentUpdate: function(nextProps, nextState, nextContext) { + * return !equal(nextProps, this.props) || + * !equal(nextState, this.state) || + * !equal(nextContext, this.context); + * } + * + * @param {object} nextProps + * @param {?object} nextState + * @param {?object} nextContext + * @return {boolean} True if the component should update. + * @optional + */ + shouldComponentUpdate: SpecPolicy.DEFINE_ONCE, + + /** + * Invoked when the component is about to update due to a transition from + * `this.props`, `this.state` and `this.context` to `nextProps`, `nextState` + * and `nextContext`. + * + * Use this as an opportunity to perform preparation before an update occurs. + * + * NOTE: You **cannot** use `this.setState()` in this method. + * + * @param {object} nextProps + * @param {?object} nextState + * @param {?object} nextContext + * @param {ReactReconcileTransaction} transaction + * @optional + */ + componentWillUpdate: SpecPolicy.DEFINE_MANY, + + /** + * Invoked when the component's DOM representation has been updated. + * + * Use this as an opportunity to operate on the DOM when the component has + * been updated. + * + * @param {object} prevProps + * @param {?object} prevState + * @param {?object} prevContext + * @param {DOMElement} rootNode DOM element representing the component. + * @optional + */ + componentDidUpdate: SpecPolicy.DEFINE_MANY, + + /** + * Invoked when the component is about to be removed from its parent and have + * its DOM representation destroyed. + * + * Use this as an opportunity to deallocate any external resources. + * + * NOTE: There is no `componentDidUnmount` since your component will have been + * destroyed by that point. + * + * @optional + */ + componentWillUnmount: SpecPolicy.DEFINE_MANY, + + + + // ==== Advanced methods ==== + + /** + * Updates the component's currently mounted DOM representation. + * + * By default, this implements React's rendering and reconciliation algorithm. + * Sophisticated clients may wish to override this. + * + * @param {ReactReconcileTransaction} transaction + * @internal + * @overridable + */ + updateComponent: SpecPolicy.OVERRIDE_BASE + + }; + + /** + * Mapping from class specification keys to special processing functions. + * + * Although these are declared like instance properties in the specification + * when defining classes using `React.createClass`, they are actually static + * and are accessible on the constructor instead of the prototype. Despite + * being static, they must be defined outside of the "statics" key under + * which all other static methods are defined. + */ + var RESERVED_SPEC_KEYS = { + displayName: function(Constructor, displayName) { + Constructor.displayName = displayName; + }, + mixins: function(Constructor, mixins) { + if (mixins) { + for (var i = 0; i < mixins.length; i++) { + mixSpecIntoComponent(Constructor, mixins[i]); + } + } + }, + childContextTypes: function(Constructor, childContextTypes) { + if ("production" !== process.env.NODE_ENV) { + validateTypeDef( + Constructor, + childContextTypes, + ReactPropTypeLocations.childContext + ); + } + Constructor.childContextTypes = assign( + {}, + Constructor.childContextTypes, + childContextTypes + ); + }, + contextTypes: function(Constructor, contextTypes) { + if ("production" !== process.env.NODE_ENV) { + validateTypeDef( + Constructor, + contextTypes, + ReactPropTypeLocations.context + ); + } + Constructor.contextTypes = assign( + {}, + Constructor.contextTypes, + contextTypes + ); + }, + /** + * Special case getDefaultProps which should move into statics but requires + * automatic merging. + */ + getDefaultProps: function(Constructor, getDefaultProps) { + if (Constructor.getDefaultProps) { + Constructor.getDefaultProps = createMergedResultFunction( + Constructor.getDefaultProps, + getDefaultProps + ); + } else { + Constructor.getDefaultProps = getDefaultProps; + } + }, + propTypes: function(Constructor, propTypes) { + if ("production" !== process.env.NODE_ENV) { + validateTypeDef( + Constructor, + propTypes, + ReactPropTypeLocations.prop + ); + } + Constructor.propTypes = assign( + {}, + Constructor.propTypes, + propTypes + ); + }, + statics: function(Constructor, statics) { + mixStaticSpecIntoComponent(Constructor, statics); + } + }; + + function validateTypeDef(Constructor, typeDef, location) { + for (var propName in typeDef) { + if (typeDef.hasOwnProperty(propName)) { + // use a warning instead of an invariant so components + // don't show up in prod but not in __DEV__ + ("production" !== process.env.NODE_ENV ? warning( + typeof typeDef[propName] === 'function', + '%s: %s type `%s` is invalid; it must be a function, usually from ' + + 'React.PropTypes.', + Constructor.displayName || 'ReactClass', + ReactPropTypeLocationNames[location], + propName + ) : null); + } + } + } + + function validateMethodOverride(proto, name) { + var specPolicy = ReactClassInterface.hasOwnProperty(name) ? + ReactClassInterface[name] : + null; + + // Disallow overriding of base class methods unless explicitly allowed. + if (ReactClassMixin.hasOwnProperty(name)) { + ("production" !== process.env.NODE_ENV ? invariant( + specPolicy === SpecPolicy.OVERRIDE_BASE, + 'ReactClassInterface: You are attempting to override ' + + '`%s` from your class specification. Ensure that your method names ' + + 'do not overlap with React methods.', + name + ) : invariant(specPolicy === SpecPolicy.OVERRIDE_BASE)); + } + + // Disallow defining methods more than once unless explicitly allowed. + if (proto.hasOwnProperty(name)) { + ("production" !== process.env.NODE_ENV ? invariant( + specPolicy === SpecPolicy.DEFINE_MANY || + specPolicy === SpecPolicy.DEFINE_MANY_MERGED, + 'ReactClassInterface: You are attempting to define ' + + '`%s` on your component more than once. This conflict may be due ' + + 'to a mixin.', + name + ) : invariant(specPolicy === SpecPolicy.DEFINE_MANY || + specPolicy === SpecPolicy.DEFINE_MANY_MERGED)); + } + } + + /** + * Mixin helper which handles policy validation and reserved + * specification keys when building React classses. + */ + function mixSpecIntoComponent(Constructor, spec) { + if (!spec) { + return; + } + + ("production" !== process.env.NODE_ENV ? invariant( + typeof spec !== 'function', + 'ReactClass: You\'re attempting to ' + + 'use a component class as a mixin. Instead, just use a regular object.' + ) : invariant(typeof spec !== 'function')); + ("production" !== process.env.NODE_ENV ? invariant( + !ReactElement.isValidElement(spec), + 'ReactClass: You\'re attempting to ' + + 'use a component as a mixin. Instead, just use a regular object.' + ) : invariant(!ReactElement.isValidElement(spec))); + + var proto = Constructor.prototype; + + // By handling mixins before any other properties, we ensure the same + // chaining order is applied to methods with DEFINE_MANY policy, whether + // mixins are listed before or after these methods in the spec. + if (spec.hasOwnProperty(MIXINS_KEY)) { + RESERVED_SPEC_KEYS.mixins(Constructor, spec.mixins); + } + + for (var name in spec) { + if (!spec.hasOwnProperty(name)) { + continue; + } + + if (name === MIXINS_KEY) { + // We have already handled mixins in a special case above + continue; + } + + var property = spec[name]; + validateMethodOverride(proto, name); + + if (RESERVED_SPEC_KEYS.hasOwnProperty(name)) { + RESERVED_SPEC_KEYS[name](Constructor, property); + } else { + // Setup methods on prototype: + // The following member methods should not be automatically bound: + // 1. Expected ReactClass methods (in the "interface"). + // 2. Overridden methods (that were mixed in). + var isReactClassMethod = + ReactClassInterface.hasOwnProperty(name); + var isAlreadyDefined = proto.hasOwnProperty(name); + var markedDontBind = property && property.__reactDontBind; + var isFunction = typeof property === 'function'; + var shouldAutoBind = + isFunction && + !isReactClassMethod && + !isAlreadyDefined && + !markedDontBind; + + if (shouldAutoBind) { + if (!proto.__reactAutoBindMap) { + proto.__reactAutoBindMap = {}; + } + proto.__reactAutoBindMap[name] = property; + proto[name] = property; + } else { + if (isAlreadyDefined) { + var specPolicy = ReactClassInterface[name]; + + // These cases should already be caught by validateMethodOverride + ("production" !== process.env.NODE_ENV ? invariant( + isReactClassMethod && ( + (specPolicy === SpecPolicy.DEFINE_MANY_MERGED || specPolicy === SpecPolicy.DEFINE_MANY) + ), + 'ReactClass: Unexpected spec policy %s for key %s ' + + 'when mixing in component specs.', + specPolicy, + name + ) : invariant(isReactClassMethod && ( + (specPolicy === SpecPolicy.DEFINE_MANY_MERGED || specPolicy === SpecPolicy.DEFINE_MANY) + ))); + + // For methods which are defined more than once, call the existing + // methods before calling the new property, merging if appropriate. + if (specPolicy === SpecPolicy.DEFINE_MANY_MERGED) { + proto[name] = createMergedResultFunction(proto[name], property); + } else if (specPolicy === SpecPolicy.DEFINE_MANY) { + proto[name] = createChainedFunction(proto[name], property); + } + } else { + proto[name] = property; + if ("production" !== process.env.NODE_ENV) { + // Add verbose displayName to the function, which helps when looking + // at profiling tools. + if (typeof property === 'function' && spec.displayName) { + proto[name].displayName = spec.displayName + '_' + name; + } + } + } + } + } + } + } + + function mixStaticSpecIntoComponent(Constructor, statics) { + if (!statics) { + return; + } + for (var name in statics) { + var property = statics[name]; + if (!statics.hasOwnProperty(name)) { + continue; + } + + var isReserved = name in RESERVED_SPEC_KEYS; + ("production" !== process.env.NODE_ENV ? invariant( + !isReserved, + 'ReactClass: You are attempting to define a reserved ' + + 'property, `%s`, that shouldn\'t be on the "statics" key. Define it ' + + 'as an instance property instead; it will still be accessible on the ' + + 'constructor.', + name + ) : invariant(!isReserved)); + + var isInherited = name in Constructor; + ("production" !== process.env.NODE_ENV ? invariant( + !isInherited, + 'ReactClass: You are attempting to define ' + + '`%s` on your component more than once. This conflict may be ' + + 'due to a mixin.', + name + ) : invariant(!isInherited)); + Constructor[name] = property; + } + } + + /** + * Merge two objects, but throw if both contain the same key. + * + * @param {object} one The first object, which is mutated. + * @param {object} two The second object + * @return {object} one after it has been mutated to contain everything in two. + */ + function mergeIntoWithNoDuplicateKeys(one, two) { + ("production" !== process.env.NODE_ENV ? invariant( + one && two && typeof one === 'object' && typeof two === 'object', + 'mergeIntoWithNoDuplicateKeys(): Cannot merge non-objects.' + ) : invariant(one && two && typeof one === 'object' && typeof two === 'object')); + + for (var key in two) { + if (two.hasOwnProperty(key)) { + ("production" !== process.env.NODE_ENV ? invariant( + one[key] === undefined, + 'mergeIntoWithNoDuplicateKeys(): ' + + 'Tried to merge two objects with the same key: `%s`. This conflict ' + + 'may be due to a mixin; in particular, this may be caused by two ' + + 'getInitialState() or getDefaultProps() methods returning objects ' + + 'with clashing keys.', + key + ) : invariant(one[key] === undefined)); + one[key] = two[key]; + } + } + return one; + } + + /** + * Creates a function that invokes two functions and merges their return values. + * + * @param {function} one Function to invoke first. + * @param {function} two Function to invoke second. + * @return {function} Function that invokes the two argument functions. + * @private + */ + function createMergedResultFunction(one, two) { + return function mergedResult() { + var a = one.apply(this, arguments); + var b = two.apply(this, arguments); + if (a == null) { + return b; + } else if (b == null) { + return a; + } + var c = {}; + mergeIntoWithNoDuplicateKeys(c, a); + mergeIntoWithNoDuplicateKeys(c, b); + return c; + }; + } + + /** + * Creates a function that invokes two functions and ignores their return vales. + * + * @param {function} one Function to invoke first. + * @param {function} two Function to invoke second. + * @return {function} Function that invokes the two argument functions. + * @private + */ + function createChainedFunction(one, two) { + return function chainedFunction() { + one.apply(this, arguments); + two.apply(this, arguments); + }; + } + + /** + * Binds a method to the component. + * + * @param {object} component Component whose method is going to be bound. + * @param {function} method Method to be bound. + * @return {function} The bound method. + */ + function bindAutoBindMethod(component, method) { + var boundMethod = method.bind(component); + if ("production" !== process.env.NODE_ENV) { + boundMethod.__reactBoundContext = component; + boundMethod.__reactBoundMethod = method; + boundMethod.__reactBoundArguments = null; + var componentName = component.constructor.displayName; + var _bind = boundMethod.bind; + /* eslint-disable block-scoped-var, no-undef */ + boundMethod.bind = function(newThis ) {for (var args=[],$__0=1,$__1=arguments.length;$__0<$__1;$__0++) args.push(arguments[$__0]); + // User is trying to bind() an autobound method; we effectively will + // ignore the value of "this" that the user is trying to use, so + // let's warn. + if (newThis !== component && newThis !== null) { + ("production" !== process.env.NODE_ENV ? warning( + false, + 'bind(): React component methods may only be bound to the ' + + 'component instance. See %s', + componentName + ) : null); + } else if (!args.length) { + ("production" !== process.env.NODE_ENV ? warning( + false, + 'bind(): You are binding a component method to the component. ' + + 'React does this for you automatically in a high-performance ' + + 'way, so you can safely remove this call. See %s', + componentName + ) : null); + return boundMethod; + } + var reboundMethod = _bind.apply(boundMethod, arguments); + reboundMethod.__reactBoundContext = component; + reboundMethod.__reactBoundMethod = method; + reboundMethod.__reactBoundArguments = args; + return reboundMethod; + /* eslint-enable */ + }; + } + return boundMethod; + } + + /** + * Binds all auto-bound methods in a component. + * + * @param {object} component Component whose method is going to be bound. + */ + function bindAutoBindMethods(component) { + for (var autoBindKey in component.__reactAutoBindMap) { + if (component.__reactAutoBindMap.hasOwnProperty(autoBindKey)) { + var method = component.__reactAutoBindMap[autoBindKey]; + component[autoBindKey] = bindAutoBindMethod( + component, + ReactErrorUtils.guard( + method, + component.constructor.displayName + '.' + autoBindKey + ) + ); + } + } + } + + var typeDeprecationDescriptor = { + enumerable: false, + get: function() { + var displayName = this.displayName || this.name || 'Component'; + ("production" !== process.env.NODE_ENV ? warning( + false, + '%s.type is deprecated. Use %s directly to access the class.', + displayName, + displayName + ) : null); + Object.defineProperty(this, 'type', { + value: this + }); + return this; + } + }; + + /** + * Add more to the ReactClass base class. These are all legacy features and + * therefore not already part of the modern ReactComponent. + */ + var ReactClassMixin = { + + /** + * TODO: This will be deprecated because state should always keep a consistent + * type signature and the only use case for this, is to avoid that. + */ + replaceState: function(newState, callback) { + ReactUpdateQueue.enqueueReplaceState(this, newState); + if (callback) { + ReactUpdateQueue.enqueueCallback(this, callback); + } + }, + + /** + * Checks whether or not this composite component is mounted. + * @return {boolean} True if mounted, false otherwise. + * @protected + * @final + */ + isMounted: function() { + if ("production" !== process.env.NODE_ENV) { + var owner = ReactCurrentOwner.current; + if (owner !== null) { + ("production" !== process.env.NODE_ENV ? warning( + owner._warnedAboutRefsInRender, + '%s is accessing isMounted inside its render() function. ' + + 'render() should be a pure function of props and state. It should ' + + 'never access something that requires stale data from the previous ' + + 'render, such as refs. Move this logic to componentDidMount and ' + + 'componentDidUpdate instead.', + owner.getName() || 'A component' + ) : null); + owner._warnedAboutRefsInRender = true; + } + } + var internalInstance = ReactInstanceMap.get(this); + return ( + internalInstance && + internalInstance !== ReactLifeCycle.currentlyMountingInstance + ); + }, + + /** + * Sets a subset of the props. + * + * @param {object} partialProps Subset of the next props. + * @param {?function} callback Called after props are updated. + * @final + * @public + * @deprecated + */ + setProps: function(partialProps, callback) { + ReactUpdateQueue.enqueueSetProps(this, partialProps); + if (callback) { + ReactUpdateQueue.enqueueCallback(this, callback); + } + }, + + /** + * Replace all the props. + * + * @param {object} newProps Subset of the next props. + * @param {?function} callback Called after props are updated. + * @final + * @public + * @deprecated + */ + replaceProps: function(newProps, callback) { + ReactUpdateQueue.enqueueReplaceProps(this, newProps); + if (callback) { + ReactUpdateQueue.enqueueCallback(this, callback); + } + } + }; + + var ReactClassComponent = function() {}; + assign( + ReactClassComponent.prototype, + ReactComponent.prototype, + ReactClassMixin + ); + + /** + * Module for creating composite components. + * + * @class ReactClass + */ + var ReactClass = { + + /** + * Creates a composite component class given a class specification. + * + * @param {object} spec Class specification (which must define `render`). + * @return {function} Component constructor function. + * @public + */ + createClass: function(spec) { + var Constructor = function(props, context) { + // This constructor is overridden by mocks. The argument is used + // by mocks to assert on what gets mounted. + + if ("production" !== process.env.NODE_ENV) { + ("production" !== process.env.NODE_ENV ? warning( + this instanceof Constructor, + 'Something is calling a React component directly. Use a factory or ' + + 'JSX instead. See: https://fb.me/react-legacyfactory' + ) : null); + } + + // Wire up auto-binding + if (this.__reactAutoBindMap) { + bindAutoBindMethods(this); + } + + this.props = props; + this.context = context; + this.state = null; + + // ReactClasses doesn't have constructors. Instead, they use the + // getInitialState and componentWillMount methods for initialization. + + var initialState = this.getInitialState ? this.getInitialState() : null; + if ("production" !== process.env.NODE_ENV) { + // We allow auto-mocks to proceed as if they're returning null. + if (typeof initialState === 'undefined' && + this.getInitialState._isMockFunction) { + // This is probably bad practice. Consider warning here and + // deprecating this convenience. + initialState = null; + } + } + ("production" !== process.env.NODE_ENV ? invariant( + typeof initialState === 'object' && !Array.isArray(initialState), + '%s.getInitialState(): must return an object or null', + Constructor.displayName || 'ReactCompositeComponent' + ) : invariant(typeof initialState === 'object' && !Array.isArray(initialState))); + + this.state = initialState; + }; + Constructor.prototype = new ReactClassComponent(); + Constructor.prototype.constructor = Constructor; + + injectedMixins.forEach( + mixSpecIntoComponent.bind(null, Constructor) + ); + + mixSpecIntoComponent(Constructor, spec); + + // Initialize the defaultProps property after all mixins have been merged + if (Constructor.getDefaultProps) { + Constructor.defaultProps = Constructor.getDefaultProps(); + } + + if ("production" !== process.env.NODE_ENV) { + // This is a tag to indicate that the use of these method names is ok, + // since it's used with createClass. If it's not, then it's likely a + // mistake so we'll warn you to use the static property, property + // initializer or constructor respectively. + if (Constructor.getDefaultProps) { + Constructor.getDefaultProps.isReactClassApproved = {}; + } + if (Constructor.prototype.getInitialState) { + Constructor.prototype.getInitialState.isReactClassApproved = {}; + } + } + + ("production" !== process.env.NODE_ENV ? invariant( + Constructor.prototype.render, + 'createClass(...): Class specification must implement a `render` method.' + ) : invariant(Constructor.prototype.render)); + + if ("production" !== process.env.NODE_ENV) { + ("production" !== process.env.NODE_ENV ? warning( + !Constructor.prototype.componentShouldUpdate, + '%s has a method called ' + + 'componentShouldUpdate(). Did you mean shouldComponentUpdate()? ' + + 'The name is phrased as a question because the function is ' + + 'expected to return a value.', + spec.displayName || 'A component' + ) : null); + } + + // Reduce time spent doing lookups by setting these on the prototype. + for (var methodName in ReactClassInterface) { + if (!Constructor.prototype[methodName]) { + Constructor.prototype[methodName] = null; + } + } + + // Legacy hook + Constructor.type = Constructor; + if ("production" !== process.env.NODE_ENV) { + try { + Object.defineProperty(Constructor, 'type', typeDeprecationDescriptor); + } catch (x) { + // IE will fail on defineProperty (es5-shim/sham too) + } + } + + return Constructor; + }, + + injection: { + injectMixin: function(mixin) { + injectedMixins.push(mixin); + } + } + + }; + + module.exports = ReactClass; + + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(11))) + +/***/ }, +/* 45 */ +/***/ function(module, exports) { + + /** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactErrorUtils + * @typechecks + */ + + "use strict"; + + var ReactErrorUtils = { + /** + * Creates a guarded version of a function. This is supposed to make debugging + * of event handlers easier. To aid debugging with the browser's debugger, + * this currently simply returns the original function. + * + * @param {function} func Function to be executed + * @param {string} name The name of the guard + * @return {function} + */ + guard: function(func, name) { + return func; + } + }; + + module.exports = ReactErrorUtils; + + +/***/ }, +/* 46 */ +/***/ function(module, exports) { + + /** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule keyOf + */ + + /** + * Allows extraction of a minified key. Let's the build system minify keys + * without loosing the ability to dynamically use key strings as values + * themselves. Pass in an object with a single key/val pair and it will return + * you the string key of that single record. Suppose you want to grab the + * value for a key 'className' inside of an object. Key/val minification may + * have aliased that key to be 'xa12'. keyOf({className: null}) will return + * 'xa12' in that case. Resolve keys you want to use once at startup time, then + * reuse those resolutions. + */ + var keyOf = function(oneKeyObj) { + var key; + for (key in oneKeyObj) { + if (!oneKeyObj.hasOwnProperty(key)) { + continue; + } + return key; + } + return null; + }; + + + module.exports = keyOf; + + +/***/ }, +/* 47 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactDOM + * @typechecks static-only + */ + + 'use strict'; + + var ReactElement = __webpack_require__(19); + var ReactElementValidator = __webpack_require__(37); + + var mapObject = __webpack_require__(48); + + /** + * Create a factory that creates HTML tag elements. + * + * @param {string} tag Tag name (e.g. `div`). + * @private + */ + function createDOMFactory(tag) { + if ("production" !== process.env.NODE_ENV) { + return ReactElementValidator.createFactory(tag); + } + return ReactElement.createFactory(tag); + } + + /** + * Creates a mapping from supported HTML tags to `ReactDOMComponent` classes. + * This is also accessible via `React.DOM`. + * + * @public + */ + var ReactDOM = mapObject({ + a: 'a', + abbr: 'abbr', + address: 'address', + area: 'area', + article: 'article', + aside: 'aside', + audio: 'audio', + b: 'b', + base: 'base', + bdi: 'bdi', + bdo: 'bdo', + big: 'big', + blockquote: 'blockquote', + body: 'body', + br: 'br', + button: 'button', + canvas: 'canvas', + caption: 'caption', + cite: 'cite', + code: 'code', + col: 'col', + colgroup: 'colgroup', + data: 'data', + datalist: 'datalist', + dd: 'dd', + del: 'del', + details: 'details', + dfn: 'dfn', + dialog: 'dialog', + div: 'div', + dl: 'dl', + dt: 'dt', + em: 'em', + embed: 'embed', + fieldset: 'fieldset', + figcaption: 'figcaption', + figure: 'figure', + footer: 'footer', + form: 'form', + h1: 'h1', + h2: 'h2', + h3: 'h3', + h4: 'h4', + h5: 'h5', + h6: 'h6', + head: 'head', + header: 'header', + hr: 'hr', + html: 'html', + i: 'i', + iframe: 'iframe', + img: 'img', + input: 'input', + ins: 'ins', + kbd: 'kbd', + keygen: 'keygen', + label: 'label', + legend: 'legend', + li: 'li', + link: 'link', + main: 'main', + map: 'map', + mark: 'mark', + menu: 'menu', + menuitem: 'menuitem', + meta: 'meta', + meter: 'meter', + nav: 'nav', + noscript: 'noscript', + object: 'object', + ol: 'ol', + optgroup: 'optgroup', + option: 'option', + output: 'output', + p: 'p', + param: 'param', + picture: 'picture', + pre: 'pre', + progress: 'progress', + q: 'q', + rp: 'rp', + rt: 'rt', + ruby: 'ruby', + s: 's', + samp: 'samp', + script: 'script', + section: 'section', + select: 'select', + small: 'small', + source: 'source', + span: 'span', + strong: 'strong', + style: 'style', + sub: 'sub', + summary: 'summary', + sup: 'sup', + table: 'table', + tbody: 'tbody', + td: 'td', + textarea: 'textarea', + tfoot: 'tfoot', + th: 'th', + thead: 'thead', + time: 'time', + title: 'title', + tr: 'tr', + track: 'track', + u: 'u', + ul: 'ul', + 'var': 'var', + video: 'video', + wbr: 'wbr', + + // SVG + circle: 'circle', + clipPath: 'clipPath', + defs: 'defs', + ellipse: 'ellipse', + g: 'g', + line: 'line', + linearGradient: 'linearGradient', + mask: 'mask', + path: 'path', + pattern: 'pattern', + polygon: 'polygon', + polyline: 'polyline', + radialGradient: 'radialGradient', + rect: 'rect', + stop: 'stop', + svg: 'svg', + text: 'text', + tspan: 'tspan' + + }, createDOMFactory); + + module.exports = ReactDOM; + + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(11))) + +/***/ }, +/* 48 */ +/***/ function(module, exports) { + + /** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule mapObject + */ + + 'use strict'; + + var hasOwnProperty = Object.prototype.hasOwnProperty; + + /** + * Executes the provided `callback` once for each enumerable own property in the + * object and constructs a new object from the results. The `callback` is + * invoked with three arguments: + * + * - the property value + * - the property name + * - the object being traversed + * + * Properties that are added after the call to `mapObject` will not be visited + * by `callback`. If the values of existing properties are changed, the value + * passed to `callback` will be the value at the time `mapObject` visits them. + * Properties that are deleted before being visited are not visited. + * + * @grep function objectMap() + * @grep function objMap() + * + * @param {?object} object + * @param {function} callback + * @param {*} context + * @return {?object} + */ + function mapObject(object, callback, context) { + if (!object) { + return null; + } + var result = {}; + for (var name in object) { + if (hasOwnProperty.call(object, name)) { + result[name] = callback.call(context, object[name], name, object); + } + } + return result; + } + + module.exports = mapObject; + + +/***/ }, +/* 49 */ +/***/ function(module, exports, __webpack_require__) { + + /** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactDOMTextComponent + * @typechecks static-only + */ + + 'use strict'; + + var DOMPropertyOperations = __webpack_require__(50); + var ReactComponentBrowserEnvironment = + __webpack_require__(54); + var ReactDOMComponent = __webpack_require__(94); + + var assign = __webpack_require__(8); + var escapeTextContentForBrowser = __webpack_require__(53); + + /** + * Text nodes violate a couple assumptions that React makes about components: + * + * - When mounting text into the DOM, adjacent text nodes are merged. + * - Text nodes cannot be assigned a React root ID. + * + * This component is used to wrap strings in elements so that they can undergo + * the same reconciliation that is applied to elements. + * + * TODO: Investigate representing React components in the DOM with text nodes. + * + * @class ReactDOMTextComponent + * @extends ReactComponent + * @internal + */ + var ReactDOMTextComponent = function(props) { + // This constructor and its argument is currently used by mocks. + }; + + assign(ReactDOMTextComponent.prototype, { + + /** + * @param {ReactText} text + * @internal + */ + construct: function(text) { + // TODO: This is really a ReactText (ReactNode), not a ReactElement + this._currentElement = text; + this._stringText = '' + text; + + // Properties + this._rootNodeID = null; + this._mountIndex = 0; + }, + + /** + * Creates the markup for this text node. This node is not intended to have + * any features besides containing text content. + * + * @param {string} rootID DOM ID of the root node. + * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction + * @return {string} Markup for this text node. + * @internal + */ + mountComponent: function(rootID, transaction, context) { + this._rootNodeID = rootID; + var escapedText = escapeTextContentForBrowser(this._stringText); + + if (transaction.renderToStaticMarkup) { + // Normally we'd wrap this in a `span` for the reasons stated above, but + // since this is a situation where React won't take over (static pages), + // we can simply return the text as it is. + return escapedText; + } + + return ( + '' + + escapedText + + '' + ); + }, + + /** + * Updates this component by updating the text content. + * + * @param {ReactText} nextText The next text content + * @param {ReactReconcileTransaction} transaction + * @internal + */ + receiveComponent: function(nextText, transaction) { + if (nextText !== this._currentElement) { + this._currentElement = nextText; + var nextStringText = '' + nextText; + if (nextStringText !== this._stringText) { + // TODO: Save this as pending props and use performUpdateIfNecessary + // and/or updateComponent to do the actual update for consistency with + // other component types? + this._stringText = nextStringText; + ReactDOMComponent.BackendIDOperations.updateTextContentByID( + this._rootNodeID, + nextStringText + ); + } + } + }, + + unmountComponent: function() { + ReactComponentBrowserEnvironment.unmountIDFromEnvironment(this._rootNodeID); + } + + }); + + module.exports = ReactDOMTextComponent; + + +/***/ }, +/* 50 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule DOMPropertyOperations + * @typechecks static-only + */ + + 'use strict'; + + var DOMProperty = __webpack_require__(51); + + var quoteAttributeValueForBrowser = __webpack_require__(52); + var warning = __webpack_require__(22); + + function shouldIgnoreValue(name, value) { + return value == null || + (DOMProperty.hasBooleanValue[name] && !value) || + (DOMProperty.hasNumericValue[name] && isNaN(value)) || + (DOMProperty.hasPositiveNumericValue[name] && (value < 1)) || + (DOMProperty.hasOverloadedBooleanValue[name] && value === false); + } + + if ("production" !== process.env.NODE_ENV) { + var reactProps = { + children: true, + dangerouslySetInnerHTML: true, + key: true, + ref: true + }; + var warnedProperties = {}; + + var warnUnknownProperty = function(name) { + if (reactProps.hasOwnProperty(name) && reactProps[name] || + warnedProperties.hasOwnProperty(name) && warnedProperties[name]) { + return; + } + + warnedProperties[name] = true; + var lowerCasedName = name.toLowerCase(); + + // data-* attributes should be lowercase; suggest the lowercase version + var standardName = ( + DOMProperty.isCustomAttribute(lowerCasedName) ? + lowerCasedName : + DOMProperty.getPossibleStandardName.hasOwnProperty(lowerCasedName) ? + DOMProperty.getPossibleStandardName[lowerCasedName] : + null + ); + + // For now, only warn when we have a suggested correction. This prevents + // logging too much when using transferPropsTo. + ("production" !== process.env.NODE_ENV ? warning( + standardName == null, + 'Unknown DOM property %s. Did you mean %s?', + name, + standardName + ) : null); + + }; + } + + /** + * Operations for dealing with DOM properties. + */ + var DOMPropertyOperations = { + + /** + * Creates markup for the ID property. + * + * @param {string} id Unescaped ID. + * @return {string} Markup string. + */ + createMarkupForID: function(id) { + return DOMProperty.ID_ATTRIBUTE_NAME + '=' + + quoteAttributeValueForBrowser(id); + }, + + /** + * Creates markup for a property. + * + * @param {string} name + * @param {*} value + * @return {?string} Markup string, or null if the property was invalid. + */ + createMarkupForProperty: function(name, value) { + if (DOMProperty.isStandardName.hasOwnProperty(name) && + DOMProperty.isStandardName[name]) { + if (shouldIgnoreValue(name, value)) { + return ''; + } + var attributeName = DOMProperty.getAttributeName[name]; + if (DOMProperty.hasBooleanValue[name] || + (DOMProperty.hasOverloadedBooleanValue[name] && value === true)) { + return attributeName; + } + return attributeName + '=' + quoteAttributeValueForBrowser(value); + } else if (DOMProperty.isCustomAttribute(name)) { + if (value == null) { + return ''; + } + return name + '=' + quoteAttributeValueForBrowser(value); + } else if ("production" !== process.env.NODE_ENV) { + warnUnknownProperty(name); + } + return null; + }, + + /** + * Sets the value for a property on a node. + * + * @param {DOMElement} node + * @param {string} name + * @param {*} value + */ + setValueForProperty: function(node, name, value) { + if (DOMProperty.isStandardName.hasOwnProperty(name) && + DOMProperty.isStandardName[name]) { + var mutationMethod = DOMProperty.getMutationMethod[name]; + if (mutationMethod) { + mutationMethod(node, value); + } else if (shouldIgnoreValue(name, value)) { + this.deleteValueForProperty(node, name); + } else if (DOMProperty.mustUseAttribute[name]) { + // `setAttribute` with objects becomes only `[object]` in IE8/9, + // ('' + value) makes it output the correct toString()-value. + node.setAttribute(DOMProperty.getAttributeName[name], '' + value); + } else { + var propName = DOMProperty.getPropertyName[name]; + // Must explicitly cast values for HAS_SIDE_EFFECTS-properties to the + // property type before comparing; only `value` does and is string. + if (!DOMProperty.hasSideEffects[name] || + ('' + node[propName]) !== ('' + value)) { + // Contrary to `setAttribute`, object properties are properly + // `toString`ed by IE8/9. + node[propName] = value; + } + } + } else if (DOMProperty.isCustomAttribute(name)) { + if (value == null) { + node.removeAttribute(name); + } else { + node.setAttribute(name, '' + value); + } + } else if ("production" !== process.env.NODE_ENV) { + warnUnknownProperty(name); + } + }, + + /** + * Deletes the value for a property on a node. + * + * @param {DOMElement} node + * @param {string} name + */ + deleteValueForProperty: function(node, name) { + if (DOMProperty.isStandardName.hasOwnProperty(name) && + DOMProperty.isStandardName[name]) { + var mutationMethod = DOMProperty.getMutationMethod[name]; + if (mutationMethod) { + mutationMethod(node, undefined); + } else if (DOMProperty.mustUseAttribute[name]) { + node.removeAttribute(DOMProperty.getAttributeName[name]); + } else { + var propName = DOMProperty.getPropertyName[name]; + var defaultValue = DOMProperty.getDefaultValueForProperty( + node.nodeName, + propName + ); + if (!DOMProperty.hasSideEffects[name] || + ('' + node[propName]) !== defaultValue) { + node[propName] = defaultValue; + } + } + } else if (DOMProperty.isCustomAttribute(name)) { + node.removeAttribute(name); + } else if ("production" !== process.env.NODE_ENV) { + warnUnknownProperty(name); + } + } + + }; + + module.exports = DOMPropertyOperations; + + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(11))) + +/***/ }, +/* 51 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule DOMProperty + * @typechecks static-only + */ + + /*jslint bitwise: true */ + + 'use strict'; + + var invariant = __webpack_require__(15); + + function checkMask(value, bitmask) { + return (value & bitmask) === bitmask; + } + + var DOMPropertyInjection = { + /** + * Mapping from normalized, camelcased property names to a configuration that + * specifies how the associated DOM property should be accessed or rendered. + */ + MUST_USE_ATTRIBUTE: 0x1, + MUST_USE_PROPERTY: 0x2, + HAS_SIDE_EFFECTS: 0x4, + HAS_BOOLEAN_VALUE: 0x8, + HAS_NUMERIC_VALUE: 0x10, + HAS_POSITIVE_NUMERIC_VALUE: 0x20 | 0x10, + HAS_OVERLOADED_BOOLEAN_VALUE: 0x40, + + /** + * Inject some specialized knowledge about the DOM. This takes a config object + * with the following properties: + * + * isCustomAttribute: function that given an attribute name will return true + * if it can be inserted into the DOM verbatim. Useful for data-* or aria-* + * attributes where it's impossible to enumerate all of the possible + * attribute names, + * + * Properties: object mapping DOM property name to one of the + * DOMPropertyInjection constants or null. If your attribute isn't in here, + * it won't get written to the DOM. + * + * DOMAttributeNames: object mapping React attribute name to the DOM + * attribute name. Attribute names not specified use the **lowercase** + * normalized name. + * + * DOMPropertyNames: similar to DOMAttributeNames but for DOM properties. + * Property names not specified use the normalized name. + * + * DOMMutationMethods: Properties that require special mutation methods. If + * `value` is undefined, the mutation method should unset the property. + * + * @param {object} domPropertyConfig the config as described above. + */ + injectDOMPropertyConfig: function(domPropertyConfig) { + var Properties = domPropertyConfig.Properties || {}; + var DOMAttributeNames = domPropertyConfig.DOMAttributeNames || {}; + var DOMPropertyNames = domPropertyConfig.DOMPropertyNames || {}; + var DOMMutationMethods = domPropertyConfig.DOMMutationMethods || {}; + + if (domPropertyConfig.isCustomAttribute) { + DOMProperty._isCustomAttributeFunctions.push( + domPropertyConfig.isCustomAttribute + ); + } + + for (var propName in Properties) { + ("production" !== process.env.NODE_ENV ? invariant( + !DOMProperty.isStandardName.hasOwnProperty(propName), + 'injectDOMPropertyConfig(...): You\'re trying to inject DOM property ' + + '\'%s\' which has already been injected. You may be accidentally ' + + 'injecting the same DOM property config twice, or you may be ' + + 'injecting two configs that have conflicting property names.', + propName + ) : invariant(!DOMProperty.isStandardName.hasOwnProperty(propName))); + + DOMProperty.isStandardName[propName] = true; + + var lowerCased = propName.toLowerCase(); + DOMProperty.getPossibleStandardName[lowerCased] = propName; + + if (DOMAttributeNames.hasOwnProperty(propName)) { + var attributeName = DOMAttributeNames[propName]; + DOMProperty.getPossibleStandardName[attributeName] = propName; + DOMProperty.getAttributeName[propName] = attributeName; + } else { + DOMProperty.getAttributeName[propName] = lowerCased; + } + + DOMProperty.getPropertyName[propName] = + DOMPropertyNames.hasOwnProperty(propName) ? + DOMPropertyNames[propName] : + propName; + + if (DOMMutationMethods.hasOwnProperty(propName)) { + DOMProperty.getMutationMethod[propName] = DOMMutationMethods[propName]; + } else { + DOMProperty.getMutationMethod[propName] = null; + } + + var propConfig = Properties[propName]; + DOMProperty.mustUseAttribute[propName] = + checkMask(propConfig, DOMPropertyInjection.MUST_USE_ATTRIBUTE); + DOMProperty.mustUseProperty[propName] = + checkMask(propConfig, DOMPropertyInjection.MUST_USE_PROPERTY); + DOMProperty.hasSideEffects[propName] = + checkMask(propConfig, DOMPropertyInjection.HAS_SIDE_EFFECTS); + DOMProperty.hasBooleanValue[propName] = + checkMask(propConfig, DOMPropertyInjection.HAS_BOOLEAN_VALUE); + DOMProperty.hasNumericValue[propName] = + checkMask(propConfig, DOMPropertyInjection.HAS_NUMERIC_VALUE); + DOMProperty.hasPositiveNumericValue[propName] = + checkMask(propConfig, DOMPropertyInjection.HAS_POSITIVE_NUMERIC_VALUE); + DOMProperty.hasOverloadedBooleanValue[propName] = + checkMask(propConfig, DOMPropertyInjection.HAS_OVERLOADED_BOOLEAN_VALUE); + + ("production" !== process.env.NODE_ENV ? invariant( + !DOMProperty.mustUseAttribute[propName] || + !DOMProperty.mustUseProperty[propName], + 'DOMProperty: Cannot require using both attribute and property: %s', + propName + ) : invariant(!DOMProperty.mustUseAttribute[propName] || + !DOMProperty.mustUseProperty[propName])); + ("production" !== process.env.NODE_ENV ? invariant( + DOMProperty.mustUseProperty[propName] || + !DOMProperty.hasSideEffects[propName], + 'DOMProperty: Properties that have side effects must use property: %s', + propName + ) : invariant(DOMProperty.mustUseProperty[propName] || + !DOMProperty.hasSideEffects[propName])); + ("production" !== process.env.NODE_ENV ? invariant( + !!DOMProperty.hasBooleanValue[propName] + + !!DOMProperty.hasNumericValue[propName] + + !!DOMProperty.hasOverloadedBooleanValue[propName] <= 1, + 'DOMProperty: Value can be one of boolean, overloaded boolean, or ' + + 'numeric value, but not a combination: %s', + propName + ) : invariant(!!DOMProperty.hasBooleanValue[propName] + + !!DOMProperty.hasNumericValue[propName] + + !!DOMProperty.hasOverloadedBooleanValue[propName] <= 1)); + } + } + }; + var defaultValueCache = {}; + + /** + * DOMProperty exports lookup objects that can be used like functions: + * + * > DOMProperty.isValid['id'] + * true + * > DOMProperty.isValid['foobar'] + * undefined + * + * Although this may be confusing, it performs better in general. + * + * @see http://jsperf.com/key-exists + * @see http://jsperf.com/key-missing + */ + var DOMProperty = { + + ID_ATTRIBUTE_NAME: 'data-reactid', + + /** + * Checks whether a property name is a standard property. + * @type {Object} + */ + isStandardName: {}, + + /** + * Mapping from lowercase property names to the properly cased version, used + * to warn in the case of missing properties. + * @type {Object} + */ + getPossibleStandardName: {}, + + /** + * Mapping from normalized names to attribute names that differ. Attribute + * names are used when rendering markup or with `*Attribute()`. + * @type {Object} + */ + getAttributeName: {}, + + /** + * Mapping from normalized names to properties on DOM node instances. + * (This includes properties that mutate due to external factors.) + * @type {Object} + */ + getPropertyName: {}, + + /** + * Mapping from normalized names to mutation methods. This will only exist if + * mutation cannot be set simply by the property or `setAttribute()`. + * @type {Object} + */ + getMutationMethod: {}, + + /** + * Whether the property must be accessed and mutated as an object property. + * @type {Object} + */ + mustUseAttribute: {}, + + /** + * Whether the property must be accessed and mutated using `*Attribute()`. + * (This includes anything that fails ` in `.) + * @type {Object} + */ + mustUseProperty: {}, + + /** + * Whether or not setting a value causes side effects such as triggering + * resources to be loaded or text selection changes. We must ensure that + * the value is only set if it has changed. + * @type {Object} + */ + hasSideEffects: {}, + + /** + * Whether the property should be removed when set to a falsey value. + * @type {Object} + */ + hasBooleanValue: {}, + + /** + * Whether the property must be numeric or parse as a + * numeric and should be removed when set to a falsey value. + * @type {Object} + */ + hasNumericValue: {}, + + /** + * Whether the property must be positive numeric or parse as a positive + * numeric and should be removed when set to a falsey value. + * @type {Object} + */ + hasPositiveNumericValue: {}, + + /** + * Whether the property can be used as a flag as well as with a value. Removed + * when strictly equal to false; present without a value when strictly equal + * to true; present with a value otherwise. + * @type {Object} + */ + hasOverloadedBooleanValue: {}, + + /** + * All of the isCustomAttribute() functions that have been injected. + */ + _isCustomAttributeFunctions: [], + + /** + * Checks whether a property name is a custom attribute. + * @method + */ + isCustomAttribute: function(attributeName) { + for (var i = 0; i < DOMProperty._isCustomAttributeFunctions.length; i++) { + var isCustomAttributeFn = DOMProperty._isCustomAttributeFunctions[i]; + if (isCustomAttributeFn(attributeName)) { + return true; + } + } + return false; + }, + + /** + * Returns the default property value for a DOM property (i.e., not an + * attribute). Most default values are '' or false, but not all. Worse yet, + * some (in particular, `type`) vary depending on the type of element. + * + * TODO: Is it better to grab all the possible properties when creating an + * element to avoid having to create the same element twice? + */ + getDefaultValueForProperty: function(nodeName, prop) { + var nodeDefaults = defaultValueCache[nodeName]; + var testElement; + if (!nodeDefaults) { + defaultValueCache[nodeName] = nodeDefaults = {}; + } + if (!(prop in nodeDefaults)) { + testElement = document.createElement(nodeName); + nodeDefaults[prop] = testElement[prop]; + } + return nodeDefaults[prop]; + }, + + injection: DOMPropertyInjection + }; + + module.exports = DOMProperty; + + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(11))) + +/***/ }, +/* 52 */ +/***/ function(module, exports, __webpack_require__) { + + /** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule quoteAttributeValueForBrowser + */ + + 'use strict'; + + var escapeTextContentForBrowser = __webpack_require__(53); + + /** + * Escapes attribute value to prevent scripting attacks. + * + * @param {*} value Value to escape. + * @return {string} An escaped string. + */ + function quoteAttributeValueForBrowser(value) { + return '"' + escapeTextContentForBrowser(value) + '"'; + } + + module.exports = quoteAttributeValueForBrowser; + + +/***/ }, +/* 53 */ +/***/ function(module, exports) { + + /** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule escapeTextContentForBrowser + */ + + 'use strict'; + + var ESCAPE_LOOKUP = { + '&': '&', + '>': '>', + '<': '<', + '"': '"', + '\'': ''' + }; + + var ESCAPE_REGEX = /[&><"']/g; + + function escaper(match) { + return ESCAPE_LOOKUP[match]; + } + + /** + * Escapes text to prevent scripting attacks. + * + * @param {*} text Text value to escape. + * @return {string} An escaped string. + */ + function escapeTextContentForBrowser(text) { + return ('' + text).replace(ESCAPE_REGEX, escaper); + } + + module.exports = escapeTextContentForBrowser; + + +/***/ }, +/* 54 */ +/***/ function(module, exports, __webpack_require__) { + + /** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactComponentBrowserEnvironment + */ + + /*jslint evil: true */ + + 'use strict'; + + var ReactDOMIDOperations = __webpack_require__(55); + var ReactMount = __webpack_require__(74); + + /** + * Abstracts away all functionality of the reconciler that requires knowledge of + * the browser context. TODO: These callers should be refactored to avoid the + * need for this injection. + */ + var ReactComponentBrowserEnvironment = { + + processChildrenUpdates: + ReactDOMIDOperations.dangerouslyProcessChildrenUpdates, + + replaceNodeWithMarkupByID: + ReactDOMIDOperations.dangerouslyReplaceNodeWithMarkupByID, + + /** + * If a particular environment requires that some resources be cleaned up, + * specify this in the injected Mixin. In the DOM, we would likely want to + * purge any cached node ID lookups. + * + * @private + */ + unmountIDFromEnvironment: function(rootNodeID) { + ReactMount.purgeID(rootNodeID); + } + + }; + + module.exports = ReactComponentBrowserEnvironment; + + +/***/ }, +/* 55 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactDOMIDOperations + * @typechecks static-only + */ + + /*jslint evil: true */ + + 'use strict'; + + var CSSPropertyOperations = __webpack_require__(56); + var DOMChildrenOperations = __webpack_require__(65); + var DOMPropertyOperations = __webpack_require__(50); + var ReactMount = __webpack_require__(74); + var ReactPerf = __webpack_require__(33); + + var invariant = __webpack_require__(15); + var setInnerHTML = __webpack_require__(73); + + /** + * Errors for properties that should not be updated with `updatePropertyById()`. + * + * @type {object} + * @private + */ + var INVALID_PROPERTY_ERRORS = { + dangerouslySetInnerHTML: + '`dangerouslySetInnerHTML` must be set using `updateInnerHTMLByID()`.', + style: '`style` must be set using `updateStylesByID()`.' + }; + + /** + * Operations used to process updates to DOM nodes. This is made injectable via + * `ReactDOMComponent.BackendIDOperations`. + */ + var ReactDOMIDOperations = { + + /** + * Updates a DOM node with new property values. This should only be used to + * update DOM properties in `DOMProperty`. + * + * @param {string} id ID of the node to update. + * @param {string} name A valid property name, see `DOMProperty`. + * @param {*} value New value of the property. + * @internal + */ + updatePropertyByID: function(id, name, value) { + var node = ReactMount.getNode(id); + ("production" !== process.env.NODE_ENV ? invariant( + !INVALID_PROPERTY_ERRORS.hasOwnProperty(name), + 'updatePropertyByID(...): %s', + INVALID_PROPERTY_ERRORS[name] + ) : invariant(!INVALID_PROPERTY_ERRORS.hasOwnProperty(name))); + + // If we're updating to null or undefined, we should remove the property + // from the DOM node instead of inadvertantly setting to a string. This + // brings us in line with the same behavior we have on initial render. + if (value != null) { + DOMPropertyOperations.setValueForProperty(node, name, value); + } else { + DOMPropertyOperations.deleteValueForProperty(node, name); + } + }, + + /** + * Updates a DOM node to remove a property. This should only be used to remove + * DOM properties in `DOMProperty`. + * + * @param {string} id ID of the node to update. + * @param {string} name A property name to remove, see `DOMProperty`. + * @internal + */ + deletePropertyByID: function(id, name, value) { + var node = ReactMount.getNode(id); + ("production" !== process.env.NODE_ENV ? invariant( + !INVALID_PROPERTY_ERRORS.hasOwnProperty(name), + 'updatePropertyByID(...): %s', + INVALID_PROPERTY_ERRORS[name] + ) : invariant(!INVALID_PROPERTY_ERRORS.hasOwnProperty(name))); + DOMPropertyOperations.deleteValueForProperty(node, name, value); + }, + + /** + * Updates a DOM node with new style values. If a value is specified as '', + * the corresponding style property will be unset. + * + * @param {string} id ID of the node to update. + * @param {object} styles Mapping from styles to values. + * @internal + */ + updateStylesByID: function(id, styles) { + var node = ReactMount.getNode(id); + CSSPropertyOperations.setValueForStyles(node, styles); + }, + + /** + * Updates a DOM node's innerHTML. + * + * @param {string} id ID of the node to update. + * @param {string} html An HTML string. + * @internal + */ + updateInnerHTMLByID: function(id, html) { + var node = ReactMount.getNode(id); + setInnerHTML(node, html); + }, + + /** + * Updates a DOM node's text content set by `props.content`. + * + * @param {string} id ID of the node to update. + * @param {string} content Text content. + * @internal + */ + updateTextContentByID: function(id, content) { + var node = ReactMount.getNode(id); + DOMChildrenOperations.updateTextContent(node, content); + }, + + /** + * Replaces a DOM node that exists in the document with markup. + * + * @param {string} id ID of child to be replaced. + * @param {string} markup Dangerous markup to inject in place of child. + * @internal + * @see {Danger.dangerouslyReplaceNodeWithMarkup} + */ + dangerouslyReplaceNodeWithMarkupByID: function(id, markup) { + var node = ReactMount.getNode(id); + DOMChildrenOperations.dangerouslyReplaceNodeWithMarkup(node, markup); + }, + + /** + * Updates a component's children by processing a series of updates. + * + * @param {array} updates List of update configurations. + * @param {array} markup List of markup strings. + * @internal + */ + dangerouslyProcessChildrenUpdates: function(updates, markup) { + for (var i = 0; i < updates.length; i++) { + updates[i].parentNode = ReactMount.getNode(updates[i].parentID); + } + DOMChildrenOperations.processUpdates(updates, markup); + } + }; + + ReactPerf.measureMethods(ReactDOMIDOperations, 'ReactDOMIDOperations', { + updatePropertyByID: 'updatePropertyByID', + deletePropertyByID: 'deletePropertyByID', + updateStylesByID: 'updateStylesByID', + updateInnerHTMLByID: 'updateInnerHTMLByID', + updateTextContentByID: 'updateTextContentByID', + dangerouslyReplaceNodeWithMarkupByID: 'dangerouslyReplaceNodeWithMarkupByID', + dangerouslyProcessChildrenUpdates: 'dangerouslyProcessChildrenUpdates' + }); + + module.exports = ReactDOMIDOperations; + + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(11))) + +/***/ }, +/* 56 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule CSSPropertyOperations + * @typechecks static-only + */ + + 'use strict'; + + var CSSProperty = __webpack_require__(57); + var ExecutionEnvironment = __webpack_require__(58); + + var camelizeStyleName = __webpack_require__(59); + var dangerousStyleValue = __webpack_require__(61); + var hyphenateStyleName = __webpack_require__(62); + var memoizeStringOnly = __webpack_require__(64); + var warning = __webpack_require__(22); + + var processStyleName = memoizeStringOnly(function(styleName) { + return hyphenateStyleName(styleName); + }); + + var styleFloatAccessor = 'cssFloat'; + if (ExecutionEnvironment.canUseDOM) { + // IE8 only supports accessing cssFloat (standard) as styleFloat + if (document.documentElement.style.cssFloat === undefined) { + styleFloatAccessor = 'styleFloat'; + } + } + + if ("production" !== process.env.NODE_ENV) { + // 'msTransform' is correct, but the other prefixes should be capitalized + var badVendoredStyleNamePattern = /^(?:webkit|moz|o)[A-Z]/; + + // style values shouldn't contain a semicolon + var badStyleValueWithSemicolonPattern = /;\s*$/; + + var warnedStyleNames = {}; + var warnedStyleValues = {}; + + var warnHyphenatedStyleName = function(name) { + if (warnedStyleNames.hasOwnProperty(name) && warnedStyleNames[name]) { + return; + } + + warnedStyleNames[name] = true; + ("production" !== process.env.NODE_ENV ? warning( + false, + 'Unsupported style property %s. Did you mean %s?', + name, + camelizeStyleName(name) + ) : null); + }; + + var warnBadVendoredStyleName = function(name) { + if (warnedStyleNames.hasOwnProperty(name) && warnedStyleNames[name]) { + return; + } + + warnedStyleNames[name] = true; + ("production" !== process.env.NODE_ENV ? warning( + false, + 'Unsupported vendor-prefixed style property %s. Did you mean %s?', + name, + name.charAt(0).toUpperCase() + name.slice(1) + ) : null); + }; + + var warnStyleValueWithSemicolon = function(name, value) { + if (warnedStyleValues.hasOwnProperty(value) && warnedStyleValues[value]) { + return; + } + + warnedStyleValues[value] = true; + ("production" !== process.env.NODE_ENV ? warning( + false, + 'Style property values shouldn\'t contain a semicolon. ' + + 'Try "%s: %s" instead.', + name, + value.replace(badStyleValueWithSemicolonPattern, '') + ) : null); + }; + + /** + * @param {string} name + * @param {*} value + */ + var warnValidStyle = function(name, value) { + if (name.indexOf('-') > -1) { + warnHyphenatedStyleName(name); + } else if (badVendoredStyleNamePattern.test(name)) { + warnBadVendoredStyleName(name); + } else if (badStyleValueWithSemicolonPattern.test(value)) { + warnStyleValueWithSemicolon(name, value); + } + }; + } + + /** + * Operations for dealing with CSS properties. + */ + var CSSPropertyOperations = { + + /** + * Serializes a mapping of style properties for use as inline styles: + * + * > createMarkupForStyles({width: '200px', height: 0}) + * "width:200px;height:0;" + * + * Undefined values are ignored so that declarative programming is easier. + * The result should be HTML-escaped before insertion into the DOM. + * + * @param {object} styles + * @return {?string} + */ + createMarkupForStyles: function(styles) { + var serialized = ''; + for (var styleName in styles) { + if (!styles.hasOwnProperty(styleName)) { + continue; + } + var styleValue = styles[styleName]; + if ("production" !== process.env.NODE_ENV) { + warnValidStyle(styleName, styleValue); + } + if (styleValue != null) { + serialized += processStyleName(styleName) + ':'; + serialized += dangerousStyleValue(styleName, styleValue) + ';'; + } + } + return serialized || null; + }, + + /** + * Sets the value for multiple styles on a node. If a value is specified as + * '' (empty string), the corresponding style property will be unset. + * + * @param {DOMElement} node + * @param {object} styles + */ + setValueForStyles: function(node, styles) { + var style = node.style; + for (var styleName in styles) { + if (!styles.hasOwnProperty(styleName)) { + continue; + } + if ("production" !== process.env.NODE_ENV) { + warnValidStyle(styleName, styles[styleName]); + } + var styleValue = dangerousStyleValue(styleName, styles[styleName]); + if (styleName === 'float') { + styleName = styleFloatAccessor; + } + if (styleValue) { + style[styleName] = styleValue; + } else { + var expansion = CSSProperty.shorthandPropertyExpansions[styleName]; + if (expansion) { + // Shorthand property that IE8 won't like unsetting, so unset each + // component to placate it + for (var individualStyleName in expansion) { + style[individualStyleName] = ''; + } + } else { + style[styleName] = ''; + } + } + } + } + + }; + + module.exports = CSSPropertyOperations; + + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(11))) + +/***/ }, +/* 57 */ +/***/ function(module, exports) { + + /** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule CSSProperty + */ + + 'use strict'; + + /** + * CSS properties which accept numbers but are not in units of "px". + */ + var isUnitlessNumber = { + boxFlex: true, + boxFlexGroup: true, + columnCount: true, + flex: true, + flexGrow: true, + flexPositive: true, + flexShrink: true, + flexNegative: true, + fontWeight: true, + lineClamp: true, + lineHeight: true, + opacity: true, + order: true, + orphans: true, + widows: true, + zIndex: true, + zoom: true, + + // SVG-related properties + fillOpacity: true, + strokeDashoffset: true, + strokeOpacity: true, + strokeWidth: true + }; + + /** + * @param {string} prefix vendor-specific prefix, eg: Webkit + * @param {string} key style name, eg: transitionDuration + * @return {string} style name prefixed with `prefix`, properly camelCased, eg: + * WebkitTransitionDuration + */ + function prefixKey(prefix, key) { + return prefix + key.charAt(0).toUpperCase() + key.substring(1); + } + + /** + * Support style names that may come passed in prefixed by adding permutations + * of vendor prefixes. + */ + var prefixes = ['Webkit', 'ms', 'Moz', 'O']; + + // Using Object.keys here, or else the vanilla for-in loop makes IE8 go into an + // infinite loop, because it iterates over the newly added props too. + Object.keys(isUnitlessNumber).forEach(function(prop) { + prefixes.forEach(function(prefix) { + isUnitlessNumber[prefixKey(prefix, prop)] = isUnitlessNumber[prop]; + }); + }); + + /** + * Most style properties can be unset by doing .style[prop] = '' but IE8 + * doesn't like doing that with shorthand properties so for the properties that + * IE8 breaks on, which are listed here, we instead unset each of the + * individual properties. See http://bugs.jquery.com/ticket/12385. + * The 4-value 'clock' properties like margin, padding, border-width seem to + * behave without any problems. Curiously, list-style works too without any + * special prodding. + */ + var shorthandPropertyExpansions = { + background: { + backgroundImage: true, + backgroundPosition: true, + backgroundRepeat: true, + backgroundColor: true + }, + border: { + borderWidth: true, + borderStyle: true, + borderColor: true + }, + borderBottom: { + borderBottomWidth: true, + borderBottomStyle: true, + borderBottomColor: true + }, + borderLeft: { + borderLeftWidth: true, + borderLeftStyle: true, + borderLeftColor: true + }, + borderRight: { + borderRightWidth: true, + borderRightStyle: true, + borderRightColor: true + }, + borderTop: { + borderTopWidth: true, + borderTopStyle: true, + borderTopColor: true + }, + font: { + fontStyle: true, + fontVariant: true, + fontWeight: true, + fontSize: true, + lineHeight: true, + fontFamily: true + } + }; + + var CSSProperty = { + isUnitlessNumber: isUnitlessNumber, + shorthandPropertyExpansions: shorthandPropertyExpansions + }; + + module.exports = CSSProperty; + + +/***/ }, +/* 58 */ +/***/ function(module, exports) { + + /** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ExecutionEnvironment + */ + + /*jslint evil: true */ + + "use strict"; + + var canUseDOM = !!( + (typeof window !== 'undefined' && + window.document && window.document.createElement) + ); + + /** + * Simple, lightweight module assisting with the detection and context of + * Worker. Helps avoid circular dependencies and allows code to reason about + * whether or not they are in a Worker, even if they never include the main + * `ReactWorker` dependency. + */ + var ExecutionEnvironment = { + + canUseDOM: canUseDOM, + + canUseWorkers: typeof Worker !== 'undefined', + + canUseEventListeners: + canUseDOM && !!(window.addEventListener || window.attachEvent), + + canUseViewport: canUseDOM && !!window.screen, + + isInWorker: !canUseDOM // For now, this is true - might change in the future. + + }; + + module.exports = ExecutionEnvironment; + + +/***/ }, +/* 59 */ +/***/ function(module, exports, __webpack_require__) { + + /** + * Copyright 2014-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule camelizeStyleName + * @typechecks + */ + + "use strict"; + + var camelize = __webpack_require__(60); + + var msPattern = /^-ms-/; + + /** + * Camelcases a hyphenated CSS property name, for example: + * + * > camelizeStyleName('background-color') + * < "backgroundColor" + * > camelizeStyleName('-moz-transition') + * < "MozTransition" + * > camelizeStyleName('-ms-transition') + * < "msTransition" + * + * As Andi Smith suggests + * (http://www.andismith.com/blog/2012/02/modernizr-prefixed/), an `-ms` prefix + * is converted to lowercase `ms`. + * + * @param {string} string + * @return {string} + */ + function camelizeStyleName(string) { + return camelize(string.replace(msPattern, 'ms-')); + } + + module.exports = camelizeStyleName; + + +/***/ }, +/* 60 */ +/***/ function(module, exports) { + + /** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule camelize + * @typechecks + */ + + var _hyphenPattern = /-(.)/g; + + /** + * Camelcases a hyphenated string, for example: + * + * > camelize('background-color') + * < "backgroundColor" + * + * @param {string} string + * @return {string} + */ + function camelize(string) { + return string.replace(_hyphenPattern, function(_, character) { + return character.toUpperCase(); + }); + } + + module.exports = camelize; + + +/***/ }, +/* 61 */ +/***/ function(module, exports, __webpack_require__) { + + /** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule dangerousStyleValue + * @typechecks static-only + */ + + 'use strict'; + + var CSSProperty = __webpack_require__(57); + + var isUnitlessNumber = CSSProperty.isUnitlessNumber; + + /** + * Convert a value into the proper css writable value. The style name `name` + * should be logical (no hyphens), as specified + * in `CSSProperty.isUnitlessNumber`. + * + * @param {string} name CSS property name such as `topMargin`. + * @param {*} value CSS property value such as `10px`. + * @return {string} Normalized style value with dimensions applied. + */ + function dangerousStyleValue(name, value) { + // Note that we've removed escapeTextForBrowser() calls here since the + // whole string will be escaped when the attribute is injected into + // the markup. If you provide unsafe user data here they can inject + // arbitrary CSS which may be problematic (I couldn't repro this): + // https://www.owasp.org/index.php/XSS_Filter_Evasion_Cheat_Sheet + // http://www.thespanner.co.uk/2007/11/26/ultimate-xss-css-injection/ + // This is not an XSS hole but instead a potential CSS injection issue + // which has lead to a greater discussion about how we're going to + // trust URLs moving forward. See #2115901 + + var isEmpty = value == null || typeof value === 'boolean' || value === ''; + if (isEmpty) { + return ''; + } + + var isNonNumeric = isNaN(value); + if (isNonNumeric || value === 0 || + isUnitlessNumber.hasOwnProperty(name) && isUnitlessNumber[name]) { + return '' + value; // cast to string + } + + if (typeof value === 'string') { + value = value.trim(); + } + return value + 'px'; + } + + module.exports = dangerousStyleValue; + + +/***/ }, +/* 62 */ +/***/ function(module, exports, __webpack_require__) { + + /** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule hyphenateStyleName + * @typechecks + */ + + "use strict"; + + var hyphenate = __webpack_require__(63); + + var msPattern = /^ms-/; + + /** + * Hyphenates a camelcased CSS property name, for example: + * + * > hyphenateStyleName('backgroundColor') + * < "background-color" + * > hyphenateStyleName('MozTransition') + * < "-moz-transition" + * > hyphenateStyleName('msTransition') + * < "-ms-transition" + * + * As Modernizr suggests (http://modernizr.com/docs/#prefixed), an `ms` prefix + * is converted to `-ms-`. + * + * @param {string} string + * @return {string} + */ + function hyphenateStyleName(string) { + return hyphenate(string).replace(msPattern, '-ms-'); + } + + module.exports = hyphenateStyleName; + + +/***/ }, +/* 63 */ +/***/ function(module, exports) { + + /** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule hyphenate + * @typechecks + */ + + var _uppercasePattern = /([A-Z])/g; + + /** + * Hyphenates a camelcased string, for example: + * + * > hyphenate('backgroundColor') + * < "background-color" + * + * For CSS style names, use `hyphenateStyleName` instead which works properly + * with all vendor prefixes, including `ms`. + * + * @param {string} string + * @return {string} + */ + function hyphenate(string) { + return string.replace(_uppercasePattern, '-$1').toLowerCase(); + } + + module.exports = hyphenate; + + +/***/ }, +/* 64 */ +/***/ function(module, exports) { + + /** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule memoizeStringOnly + * @typechecks static-only + */ + + 'use strict'; + + /** + * Memoizes the return value of a function that accepts one string argument. + * + * @param {function} callback + * @return {function} + */ + function memoizeStringOnly(callback) { + var cache = {}; + return function(string) { + if (!cache.hasOwnProperty(string)) { + cache[string] = callback.call(this, string); + } + return cache[string]; + }; + } + + module.exports = memoizeStringOnly; + + +/***/ }, +/* 65 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule DOMChildrenOperations + * @typechecks static-only + */ + + 'use strict'; + + var Danger = __webpack_require__(66); + var ReactMultiChildUpdateTypes = __webpack_require__(71); + + var setTextContent = __webpack_require__(72); + var invariant = __webpack_require__(15); + + /** + * Inserts `childNode` as a child of `parentNode` at the `index`. + * + * @param {DOMElement} parentNode Parent node in which to insert. + * @param {DOMElement} childNode Child node to insert. + * @param {number} index Index at which to insert the child. + * @internal + */ + function insertChildAt(parentNode, childNode, index) { + // By exploiting arrays returning `undefined` for an undefined index, we can + // rely exclusively on `insertBefore(node, null)` instead of also using + // `appendChild(node)`. However, using `undefined` is not allowed by all + // browsers so we must replace it with `null`. + parentNode.insertBefore( + childNode, + parentNode.childNodes[index] || null + ); + } + + /** + * Operations for updating with DOM children. + */ + var DOMChildrenOperations = { + + dangerouslyReplaceNodeWithMarkup: Danger.dangerouslyReplaceNodeWithMarkup, + + updateTextContent: setTextContent, + + /** + * Updates a component's children by processing a series of updates. The + * update configurations are each expected to have a `parentNode` property. + * + * @param {array} updates List of update configurations. + * @param {array} markupList List of markup strings. + * @internal + */ + processUpdates: function(updates, markupList) { + var update; + // Mapping from parent IDs to initial child orderings. + var initialChildren = null; + // List of children that will be moved or removed. + var updatedChildren = null; + + for (var i = 0; i < updates.length; i++) { + update = updates[i]; + if (update.type === ReactMultiChildUpdateTypes.MOVE_EXISTING || + update.type === ReactMultiChildUpdateTypes.REMOVE_NODE) { + var updatedIndex = update.fromIndex; + var updatedChild = update.parentNode.childNodes[updatedIndex]; + var parentID = update.parentID; + + ("production" !== process.env.NODE_ENV ? invariant( + updatedChild, + 'processUpdates(): Unable to find child %s of element. This ' + + 'probably means the DOM was unexpectedly mutated (e.g., by the ' + + 'browser), usually due to forgetting a when using tables, ' + + 'nesting tags like
,

, or , or using non-SVG elements ' + + 'in an parent. Try inspecting the child nodes of the element ' + + 'with React ID `%s`.', + updatedIndex, + parentID + ) : invariant(updatedChild)); + + initialChildren = initialChildren || {}; + initialChildren[parentID] = initialChildren[parentID] || []; + initialChildren[parentID][updatedIndex] = updatedChild; + + updatedChildren = updatedChildren || []; + updatedChildren.push(updatedChild); + } + } + + var renderedMarkup = Danger.dangerouslyRenderMarkup(markupList); + + // Remove updated children first so that `toIndex` is consistent. + if (updatedChildren) { + for (var j = 0; j < updatedChildren.length; j++) { + updatedChildren[j].parentNode.removeChild(updatedChildren[j]); + } + } + + for (var k = 0; k < updates.length; k++) { + update = updates[k]; + switch (update.type) { + case ReactMultiChildUpdateTypes.INSERT_MARKUP: + insertChildAt( + update.parentNode, + renderedMarkup[update.markupIndex], + update.toIndex + ); + break; + case ReactMultiChildUpdateTypes.MOVE_EXISTING: + insertChildAt( + update.parentNode, + initialChildren[update.parentID][update.fromIndex], + update.toIndex + ); + break; + case ReactMultiChildUpdateTypes.TEXT_CONTENT: + setTextContent( + update.parentNode, + update.textContent + ); + break; + case ReactMultiChildUpdateTypes.REMOVE_NODE: + // Already removed by the for-loop above. + break; + } + } + } + + }; + + module.exports = DOMChildrenOperations; + + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(11))) + +/***/ }, +/* 66 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule Danger + * @typechecks static-only + */ + + /*jslint evil: true, sub: true */ + + 'use strict'; + + var ExecutionEnvironment = __webpack_require__(58); + + var createNodesFromMarkup = __webpack_require__(67); + var emptyFunction = __webpack_require__(23); + var getMarkupWrap = __webpack_require__(70); + var invariant = __webpack_require__(15); + + var OPEN_TAG_NAME_EXP = /^(<[^ \/>]+)/; + var RESULT_INDEX_ATTR = 'data-danger-index'; + + /** + * Extracts the `nodeName` from a string of markup. + * + * NOTE: Extracting the `nodeName` does not require a regular expression match + * because we make assumptions about React-generated markup (i.e. there are no + * spaces surrounding the opening tag and there is at least one attribute). + * + * @param {string} markup String of markup. + * @return {string} Node name of the supplied markup. + * @see http://jsperf.com/extract-nodename + */ + function getNodeName(markup) { + return markup.substring(1, markup.indexOf(' ')); + } + + var Danger = { + + /** + * Renders markup into an array of nodes. The markup is expected to render + * into a list of root nodes. Also, the length of `resultList` and + * `markupList` should be the same. + * + * @param {array} markupList List of markup strings to render. + * @return {array} List of rendered nodes. + * @internal + */ + dangerouslyRenderMarkup: function(markupList) { + ("production" !== process.env.NODE_ENV ? invariant( + ExecutionEnvironment.canUseDOM, + 'dangerouslyRenderMarkup(...): Cannot render markup in a worker ' + + 'thread. Make sure `window` and `document` are available globally ' + + 'before requiring React when unit testing or use ' + + 'React.renderToString for server rendering.' + ) : invariant(ExecutionEnvironment.canUseDOM)); + var nodeName; + var markupByNodeName = {}; + // Group markup by `nodeName` if a wrap is necessary, else by '*'. + for (var i = 0; i < markupList.length; i++) { + ("production" !== process.env.NODE_ENV ? invariant( + markupList[i], + 'dangerouslyRenderMarkup(...): Missing markup.' + ) : invariant(markupList[i])); + nodeName = getNodeName(markupList[i]); + nodeName = getMarkupWrap(nodeName) ? nodeName : '*'; + markupByNodeName[nodeName] = markupByNodeName[nodeName] || []; + markupByNodeName[nodeName][i] = markupList[i]; + } + var resultList = []; + var resultListAssignmentCount = 0; + for (nodeName in markupByNodeName) { + if (!markupByNodeName.hasOwnProperty(nodeName)) { + continue; + } + var markupListByNodeName = markupByNodeName[nodeName]; + + // This for-in loop skips the holes of the sparse array. The order of + // iteration should follow the order of assignment, which happens to match + // numerical index order, but we don't rely on that. + var resultIndex; + for (resultIndex in markupListByNodeName) { + if (markupListByNodeName.hasOwnProperty(resultIndex)) { + var markup = markupListByNodeName[resultIndex]; + + // Push the requested markup with an additional RESULT_INDEX_ATTR + // attribute. If the markup does not start with a < character, it + // will be discarded below (with an appropriate console.error). + markupListByNodeName[resultIndex] = markup.replace( + OPEN_TAG_NAME_EXP, + // This index will be parsed back out below. + '$1 ' + RESULT_INDEX_ATTR + '="' + resultIndex + '" ' + ); + } + } + + // Render each group of markup with similar wrapping `nodeName`. + var renderNodes = createNodesFromMarkup( + markupListByNodeName.join(''), + emptyFunction // Do nothing special with

, + // they will be initialized in the wrong namespace (and will not display). + 'circle': true, + 'clipPath': true, + 'defs': true, + 'ellipse': true, + 'g': true, + 'line': true, + 'linearGradient': true, + 'path': true, + 'polygon': true, + 'polyline': true, + 'radialGradient': true, + 'rect': true, + 'stop': true, + 'text': true + }; + + var selectWrap = [1, '']; + var tableWrap = [1, '', '
']; + var trWrap = [3, '', '
']; + + var svgWrap = [1, '', '']; + + var markupWrap = { + '*': [1, '?
', '
'], + + 'area': [1, '', ''], + 'col': [2, '', '
'], + 'legend': [1, '
', '
'], + 'param': [1, '', ''], + 'tr': [2, '', '
'], + + 'optgroup': selectWrap, + 'option': selectWrap, + + 'caption': tableWrap, + 'colgroup': tableWrap, + 'tbody': tableWrap, + 'tfoot': tableWrap, + 'thead': tableWrap, + + 'td': trWrap, + 'th': trWrap, + + 'circle': svgWrap, + 'clipPath': svgWrap, + 'defs': svgWrap, + 'ellipse': svgWrap, + 'g': svgWrap, + 'line': svgWrap, + 'linearGradient': svgWrap, + 'path': svgWrap, + 'polygon': svgWrap, + 'polyline': svgWrap, + 'radialGradient': svgWrap, + 'rect': svgWrap, + 'stop': svgWrap, + 'text': svgWrap + }; + + /** + * Gets the markup wrap configuration for the supplied `nodeName`. + * + * NOTE: This lazily detects which wraps are necessary for the current browser. + * + * @param {string} nodeName Lowercase `nodeName`. + * @return {?array} Markup wrap configuration, if applicable. + */ + function getMarkupWrap(nodeName) { + ("production" !== process.env.NODE_ENV ? invariant(!!dummyNode, 'Markup wrapping node not initialized') : invariant(!!dummyNode)); + if (!markupWrap.hasOwnProperty(nodeName)) { + nodeName = '*'; + } + if (!shouldWrap.hasOwnProperty(nodeName)) { + if (nodeName === '*') { + dummyNode.innerHTML = ''; + } else { + dummyNode.innerHTML = '<' + nodeName + '>'; + } + shouldWrap[nodeName] = !dummyNode.firstChild; + } + return shouldWrap[nodeName] ? markupWrap[nodeName] : null; + } + + + module.exports = getMarkupWrap; + + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(11))) + +/***/ }, +/* 71 */ +/***/ function(module, exports, __webpack_require__) { + + /** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactMultiChildUpdateTypes + */ + + 'use strict'; + + var keyMirror = __webpack_require__(14); + + /** + * When a component's children are updated, a series of update configuration + * objects are created in order to batch and serialize the required changes. + * + * Enumerates all the possible types of update configurations. + * + * @internal + */ + var ReactMultiChildUpdateTypes = keyMirror({ + INSERT_MARKUP: null, + MOVE_EXISTING: null, + REMOVE_NODE: null, + TEXT_CONTENT: null + }); + + module.exports = ReactMultiChildUpdateTypes; + + +/***/ }, +/* 72 */ +/***/ function(module, exports, __webpack_require__) { + + /** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule setTextContent + */ + + 'use strict'; + + var ExecutionEnvironment = __webpack_require__(58); + var escapeTextContentForBrowser = __webpack_require__(53); + var setInnerHTML = __webpack_require__(73); + + /** + * Set the textContent property of a node, ensuring that whitespace is preserved + * even in IE8. innerText is a poor substitute for textContent and, among many + * issues, inserts
instead of the literal newline chars. innerHTML behaves + * as it should. + * + * @param {DOMElement} node + * @param {string} text + * @internal + */ + var setTextContent = function(node, text) { + node.textContent = text; + }; + + if (ExecutionEnvironment.canUseDOM) { + if (!('textContent' in document.documentElement)) { + setTextContent = function(node, text) { + setInnerHTML(node, escapeTextContentForBrowser(text)); + }; + } + } + + module.exports = setTextContent; + + +/***/ }, +/* 73 */ +/***/ function(module, exports, __webpack_require__) { + + /** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule setInnerHTML + */ + + /* globals MSApp */ + + 'use strict'; + + var ExecutionEnvironment = __webpack_require__(58); + + var WHITESPACE_TEST = /^[ \r\n\t\f]/; + var NONVISIBLE_TEST = /<(!--|link|noscript|meta|script|style)[ \r\n\t\f\/>]/; + + /** + * Set the innerHTML property of a node, ensuring that whitespace is preserved + * even in IE8. + * + * @param {DOMElement} node + * @param {string} html + * @internal + */ + var setInnerHTML = function(node, html) { + node.innerHTML = html; + }; + + // Win8 apps: Allow all html to be inserted + if (typeof MSApp !== 'undefined' && MSApp.execUnsafeLocalFunction) { + setInnerHTML = function(node, html) { + MSApp.execUnsafeLocalFunction(function() { + node.innerHTML = html; + }); + }; + } + + if (ExecutionEnvironment.canUseDOM) { + // IE8: When updating a just created node with innerHTML only leading + // whitespace is removed. When updating an existing node with innerHTML + // whitespace in root TextNodes is also collapsed. + // @see quirksmode.org/bugreports/archives/2004/11/innerhtml_and_t.html + + // Feature detection; only IE8 is known to behave improperly like this. + var testElement = document.createElement('div'); + testElement.innerHTML = ' '; + if (testElement.innerHTML === '') { + setInnerHTML = function(node, html) { + // Magic theory: IE8 supposedly differentiates between added and updated + // nodes when processing innerHTML, innerHTML on updated nodes suffers + // from worse whitespace behavior. Re-adding a node like this triggers + // the initial and more favorable whitespace behavior. + // TODO: What to do on a detached node? + if (node.parentNode) { + node.parentNode.replaceChild(node, node); + } + + // We also implement a workaround for non-visible tags disappearing into + // thin air on IE8, this only happens if there is no visible text + // in-front of the non-visible tags. Piggyback on the whitespace fix + // and simply check if any non-visible tags appear in the source. + if (WHITESPACE_TEST.test(html) || + html[0] === '<' && NONVISIBLE_TEST.test(html)) { + // Recover leading whitespace by temporarily prepending any character. + // \uFEFF has the potential advantage of being zero-width/invisible. + node.innerHTML = '\uFEFF' + html; + + // deleteData leaves an empty `TextNode` which offsets the index of all + // children. Definitely want to avoid this. + var textNode = node.firstChild; + if (textNode.data.length === 1) { + node.removeChild(textNode); + } else { + textNode.deleteData(0, 1); + } + } else { + node.innerHTML = html; + } + }; + } + } + + module.exports = setInnerHTML; + + +/***/ }, +/* 74 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactMount + */ + + 'use strict'; + + var DOMProperty = __webpack_require__(51); + var ReactBrowserEventEmitter = __webpack_require__(75); + var ReactCurrentOwner = __webpack_require__(24); + var ReactElement = __webpack_require__(19); + var ReactElementValidator = __webpack_require__(37); + var ReactEmptyComponent = __webpack_require__(83); + var ReactInstanceHandles = __webpack_require__(27); + var ReactInstanceMap = __webpack_require__(43); + var ReactMarkupChecksum = __webpack_require__(84); + var ReactPerf = __webpack_require__(33); + var ReactReconciler = __webpack_require__(34); + var ReactUpdateQueue = __webpack_require__(30); + var ReactUpdates = __webpack_require__(31); + + var emptyObject = __webpack_require__(21); + var containsNode = __webpack_require__(86); + var getReactRootElementInContainer = __webpack_require__(89); + var instantiateReactComponent = __webpack_require__(90); + var invariant = __webpack_require__(15); + var setInnerHTML = __webpack_require__(73); + var shouldUpdateReactComponent = __webpack_require__(93); + var warning = __webpack_require__(22); + + var SEPARATOR = ReactInstanceHandles.SEPARATOR; + + var ATTR_NAME = DOMProperty.ID_ATTRIBUTE_NAME; + var nodeCache = {}; + + var ELEMENT_NODE_TYPE = 1; + var DOC_NODE_TYPE = 9; + + /** Mapping from reactRootID to React component instance. */ + var instancesByReactRootID = {}; + + /** Mapping from reactRootID to `container` nodes. */ + var containersByReactRootID = {}; + + if ("production" !== process.env.NODE_ENV) { + /** __DEV__-only mapping from reactRootID to root elements. */ + var rootElementsByReactRootID = {}; + } + + // Used to store breadth-first search state in findComponentRoot. + var findComponentRootReusableArray = []; + + /** + * Finds the index of the first character + * that's not common between the two given strings. + * + * @return {number} the index of the character where the strings diverge + */ + function firstDifferenceIndex(string1, string2) { + var minLen = Math.min(string1.length, string2.length); + for (var i = 0; i < minLen; i++) { + if (string1.charAt(i) !== string2.charAt(i)) { + return i; + } + } + return string1.length === string2.length ? -1 : minLen; + } + + /** + * @param {DOMElement} container DOM element that may contain a React component. + * @return {?string} A "reactRoot" ID, if a React component is rendered. + */ + function getReactRootID(container) { + var rootElement = getReactRootElementInContainer(container); + return rootElement && ReactMount.getID(rootElement); + } + + /** + * Accessing node[ATTR_NAME] or calling getAttribute(ATTR_NAME) on a form + * element can return its control whose name or ID equals ATTR_NAME. All + * DOM nodes support `getAttributeNode` but this can also get called on + * other objects so just return '' if we're given something other than a + * DOM node (such as window). + * + * @param {?DOMElement|DOMWindow|DOMDocument|DOMTextNode} node DOM node. + * @return {string} ID of the supplied `domNode`. + */ + function getID(node) { + var id = internalGetID(node); + if (id) { + if (nodeCache.hasOwnProperty(id)) { + var cached = nodeCache[id]; + if (cached !== node) { + ("production" !== process.env.NODE_ENV ? invariant( + !isValid(cached, id), + 'ReactMount: Two valid but unequal nodes with the same `%s`: %s', + ATTR_NAME, id + ) : invariant(!isValid(cached, id))); + + nodeCache[id] = node; + } + } else { + nodeCache[id] = node; + } + } + + return id; + } + + function internalGetID(node) { + // If node is something like a window, document, or text node, none of + // which support attributes or a .getAttribute method, gracefully return + // the empty string, as if the attribute were missing. + return node && node.getAttribute && node.getAttribute(ATTR_NAME) || ''; + } + + /** + * Sets the React-specific ID of the given node. + * + * @param {DOMElement} node The DOM node whose ID will be set. + * @param {string} id The value of the ID attribute. + */ + function setID(node, id) { + var oldID = internalGetID(node); + if (oldID !== id) { + delete nodeCache[oldID]; + } + node.setAttribute(ATTR_NAME, id); + nodeCache[id] = node; + } + + /** + * Finds the node with the supplied React-generated DOM ID. + * + * @param {string} id A React-generated DOM ID. + * @return {DOMElement} DOM node with the suppled `id`. + * @internal + */ + function getNode(id) { + if (!nodeCache.hasOwnProperty(id) || !isValid(nodeCache[id], id)) { + nodeCache[id] = ReactMount.findReactNodeByID(id); + } + return nodeCache[id]; + } + + /** + * Finds the node with the supplied public React instance. + * + * @param {*} instance A public React instance. + * @return {?DOMElement} DOM node with the suppled `id`. + * @internal + */ + function getNodeFromInstance(instance) { + var id = ReactInstanceMap.get(instance)._rootNodeID; + if (ReactEmptyComponent.isNullComponentID(id)) { + return null; + } + if (!nodeCache.hasOwnProperty(id) || !isValid(nodeCache[id], id)) { + nodeCache[id] = ReactMount.findReactNodeByID(id); + } + return nodeCache[id]; + } + + /** + * A node is "valid" if it is contained by a currently mounted container. + * + * This means that the node does not have to be contained by a document in + * order to be considered valid. + * + * @param {?DOMElement} node The candidate DOM node. + * @param {string} id The expected ID of the node. + * @return {boolean} Whether the node is contained by a mounted container. + */ + function isValid(node, id) { + if (node) { + ("production" !== process.env.NODE_ENV ? invariant( + internalGetID(node) === id, + 'ReactMount: Unexpected modification of `%s`', + ATTR_NAME + ) : invariant(internalGetID(node) === id)); + + var container = ReactMount.findReactContainerForID(id); + if (container && containsNode(container, node)) { + return true; + } + } + + return false; + } + + /** + * Causes the cache to forget about one React-specific ID. + * + * @param {string} id The ID to forget. + */ + function purgeID(id) { + delete nodeCache[id]; + } + + var deepestNodeSoFar = null; + function findDeepestCachedAncestorImpl(ancestorID) { + var ancestor = nodeCache[ancestorID]; + if (ancestor && isValid(ancestor, ancestorID)) { + deepestNodeSoFar = ancestor; + } else { + // This node isn't populated in the cache, so presumably none of its + // descendants are. Break out of the loop. + return false; + } + } + + /** + * Return the deepest cached node whose ID is a prefix of `targetID`. + */ + function findDeepestCachedAncestor(targetID) { + deepestNodeSoFar = null; + ReactInstanceHandles.traverseAncestors( + targetID, + findDeepestCachedAncestorImpl + ); + + var foundNode = deepestNodeSoFar; + deepestNodeSoFar = null; + return foundNode; + } + + /** + * Mounts this component and inserts it into the DOM. + * + * @param {ReactComponent} componentInstance The instance to mount. + * @param {string} rootID DOM ID of the root node. + * @param {DOMElement} container DOM element to mount into. + * @param {ReactReconcileTransaction} transaction + * @param {boolean} shouldReuseMarkup If true, do not insert markup + */ + function mountComponentIntoNode( + componentInstance, + rootID, + container, + transaction, + shouldReuseMarkup) { + var markup = ReactReconciler.mountComponent( + componentInstance, rootID, transaction, emptyObject + ); + componentInstance._isTopLevel = true; + ReactMount._mountImageIntoNode(markup, container, shouldReuseMarkup); + } + + /** + * Batched mount. + * + * @param {ReactComponent} componentInstance The instance to mount. + * @param {string} rootID DOM ID of the root node. + * @param {DOMElement} container DOM element to mount into. + * @param {boolean} shouldReuseMarkup If true, do not insert markup + */ + function batchedMountComponentIntoNode( + componentInstance, + rootID, + container, + shouldReuseMarkup) { + var transaction = ReactUpdates.ReactReconcileTransaction.getPooled(); + transaction.perform( + mountComponentIntoNode, + null, + componentInstance, + rootID, + container, + transaction, + shouldReuseMarkup + ); + ReactUpdates.ReactReconcileTransaction.release(transaction); + } + + /** + * Mounting is the process of initializing a React component by creating its + * representative DOM elements and inserting them into a supplied `container`. + * Any prior content inside `container` is destroyed in the process. + * + * ReactMount.render( + * component, + * document.getElementById('container') + * ); + * + *
<-- Supplied `container`. + *
<-- Rendered reactRoot of React + * // ... component. + *
+ *
+ * + * Inside of `container`, the first element rendered is the "reactRoot". + */ + var ReactMount = { + /** Exposed for debugging purposes **/ + _instancesByReactRootID: instancesByReactRootID, + + /** + * This is a hook provided to support rendering React components while + * ensuring that the apparent scroll position of its `container` does not + * change. + * + * @param {DOMElement} container The `container` being rendered into. + * @param {function} renderCallback This must be called once to do the render. + */ + scrollMonitor: function(container, renderCallback) { + renderCallback(); + }, + + /** + * Take a component that's already mounted into the DOM and replace its props + * @param {ReactComponent} prevComponent component instance already in the DOM + * @param {ReactElement} nextElement component instance to render + * @param {DOMElement} container container to render into + * @param {?function} callback function triggered on completion + */ + _updateRootComponent: function( + prevComponent, + nextElement, + container, + callback) { + if ("production" !== process.env.NODE_ENV) { + ReactElementValidator.checkAndWarnForMutatedProps(nextElement); + } + + ReactMount.scrollMonitor(container, function() { + ReactUpdateQueue.enqueueElementInternal(prevComponent, nextElement); + if (callback) { + ReactUpdateQueue.enqueueCallbackInternal(prevComponent, callback); + } + }); + + if ("production" !== process.env.NODE_ENV) { + // Record the root element in case it later gets transplanted. + rootElementsByReactRootID[getReactRootID(container)] = + getReactRootElementInContainer(container); + } + + return prevComponent; + }, + + /** + * Register a component into the instance map and starts scroll value + * monitoring + * @param {ReactComponent} nextComponent component instance to render + * @param {DOMElement} container container to render into + * @return {string} reactRoot ID prefix + */ + _registerComponent: function(nextComponent, container) { + ("production" !== process.env.NODE_ENV ? invariant( + container && ( + (container.nodeType === ELEMENT_NODE_TYPE || container.nodeType === DOC_NODE_TYPE) + ), + '_registerComponent(...): Target container is not a DOM element.' + ) : invariant(container && ( + (container.nodeType === ELEMENT_NODE_TYPE || container.nodeType === DOC_NODE_TYPE) + ))); + + ReactBrowserEventEmitter.ensureScrollValueMonitoring(); + + var reactRootID = ReactMount.registerContainer(container); + instancesByReactRootID[reactRootID] = nextComponent; + return reactRootID; + }, + + /** + * Render a new component into the DOM. + * @param {ReactElement} nextElement element to render + * @param {DOMElement} container container to render into + * @param {boolean} shouldReuseMarkup if we should skip the markup insertion + * @return {ReactComponent} nextComponent + */ + _renderNewRootComponent: function( + nextElement, + container, + shouldReuseMarkup + ) { + // Various parts of our code (such as ReactCompositeComponent's + // _renderValidatedComponent) assume that calls to render aren't nested; + // verify that that's the case. + ("production" !== process.env.NODE_ENV ? warning( + ReactCurrentOwner.current == null, + '_renderNewRootComponent(): Render methods should be a pure function ' + + 'of props and state; triggering nested component updates from ' + + 'render is not allowed. If necessary, trigger nested updates in ' + + 'componentDidUpdate.' + ) : null); + + var componentInstance = instantiateReactComponent(nextElement, null); + var reactRootID = ReactMount._registerComponent( + componentInstance, + container + ); + + // The initial render is synchronous but any updates that happen during + // rendering, in componentWillMount or componentDidMount, will be batched + // according to the current batching strategy. + + ReactUpdates.batchedUpdates( + batchedMountComponentIntoNode, + componentInstance, + reactRootID, + container, + shouldReuseMarkup + ); + + if ("production" !== process.env.NODE_ENV) { + // Record the root element in case it later gets transplanted. + rootElementsByReactRootID[reactRootID] = + getReactRootElementInContainer(container); + } + + return componentInstance; + }, + + /** + * Renders a React component into the DOM in the supplied `container`. + * + * If the React component was previously rendered into `container`, this will + * perform an update on it and only mutate the DOM as necessary to reflect the + * latest React component. + * + * @param {ReactElement} nextElement Component element to render. + * @param {DOMElement} container DOM element to render into. + * @param {?function} callback function triggered on completion + * @return {ReactComponent} Component instance rendered in `container`. + */ + render: function(nextElement, container, callback) { + ("production" !== process.env.NODE_ENV ? invariant( + ReactElement.isValidElement(nextElement), + 'React.render(): Invalid component element.%s', + ( + typeof nextElement === 'string' ? + ' Instead of passing an element string, make sure to instantiate ' + + 'it by passing it to React.createElement.' : + typeof nextElement === 'function' ? + ' Instead of passing a component class, make sure to instantiate ' + + 'it by passing it to React.createElement.' : + // Check if it quacks like an element + nextElement != null && nextElement.props !== undefined ? + ' This may be caused by unintentionally loading two independent ' + + 'copies of React.' : + '' + ) + ) : invariant(ReactElement.isValidElement(nextElement))); + + var prevComponent = instancesByReactRootID[getReactRootID(container)]; + + if (prevComponent) { + var prevElement = prevComponent._currentElement; + if (shouldUpdateReactComponent(prevElement, nextElement)) { + return ReactMount._updateRootComponent( + prevComponent, + nextElement, + container, + callback + ).getPublicInstance(); + } else { + ReactMount.unmountComponentAtNode(container); + } + } + + var reactRootElement = getReactRootElementInContainer(container); + var containerHasReactMarkup = + reactRootElement && ReactMount.isRenderedByReact(reactRootElement); + + if ("production" !== process.env.NODE_ENV) { + if (!containerHasReactMarkup || reactRootElement.nextSibling) { + var rootElementSibling = reactRootElement; + while (rootElementSibling) { + if (ReactMount.isRenderedByReact(rootElementSibling)) { + ("production" !== process.env.NODE_ENV ? warning( + false, + 'render(): Target node has markup rendered by React, but there ' + + 'are unrelated nodes as well. This is most commonly caused by ' + + 'white-space inserted around server-rendered markup.' + ) : null); + break; + } + + rootElementSibling = rootElementSibling.nextSibling; + } + } + } + + var shouldReuseMarkup = containerHasReactMarkup && !prevComponent; + + var component = ReactMount._renderNewRootComponent( + nextElement, + container, + shouldReuseMarkup + ).getPublicInstance(); + if (callback) { + callback.call(component); + } + return component; + }, + + /** + * Constructs a component instance of `constructor` with `initialProps` and + * renders it into the supplied `container`. + * + * @param {function} constructor React component constructor. + * @param {?object} props Initial props of the component instance. + * @param {DOMElement} container DOM element to render into. + * @return {ReactComponent} Component instance rendered in `container`. + */ + constructAndRenderComponent: function(constructor, props, container) { + var element = ReactElement.createElement(constructor, props); + return ReactMount.render(element, container); + }, + + /** + * Constructs a component instance of `constructor` with `initialProps` and + * renders it into a container node identified by supplied `id`. + * + * @param {function} componentConstructor React component constructor + * @param {?object} props Initial props of the component instance. + * @param {string} id ID of the DOM element to render into. + * @return {ReactComponent} Component instance rendered in the container node. + */ + constructAndRenderComponentByID: function(constructor, props, id) { + var domNode = document.getElementById(id); + ("production" !== process.env.NODE_ENV ? invariant( + domNode, + 'Tried to get element with id of "%s" but it is not present on the page.', + id + ) : invariant(domNode)); + return ReactMount.constructAndRenderComponent(constructor, props, domNode); + }, + + /** + * Registers a container node into which React components will be rendered. + * This also creates the "reactRoot" ID that will be assigned to the element + * rendered within. + * + * @param {DOMElement} container DOM element to register as a container. + * @return {string} The "reactRoot" ID of elements rendered within. + */ + registerContainer: function(container) { + var reactRootID = getReactRootID(container); + if (reactRootID) { + // If one exists, make sure it is a valid "reactRoot" ID. + reactRootID = ReactInstanceHandles.getReactRootIDFromNodeID(reactRootID); + } + if (!reactRootID) { + // No valid "reactRoot" ID found, create one. + reactRootID = ReactInstanceHandles.createReactRootID(); + } + containersByReactRootID[reactRootID] = container; + return reactRootID; + }, + + /** + * Unmounts and destroys the React component rendered in the `container`. + * + * @param {DOMElement} container DOM element containing a React component. + * @return {boolean} True if a component was found in and unmounted from + * `container` + */ + unmountComponentAtNode: function(container) { + // Various parts of our code (such as ReactCompositeComponent's + // _renderValidatedComponent) assume that calls to render aren't nested; + // verify that that's the case. (Strictly speaking, unmounting won't cause a + // render but we still don't expect to be in a render call here.) + ("production" !== process.env.NODE_ENV ? warning( + ReactCurrentOwner.current == null, + 'unmountComponentAtNode(): Render methods should be a pure function of ' + + 'props and state; triggering nested component updates from render is ' + + 'not allowed. If necessary, trigger nested updates in ' + + 'componentDidUpdate.' + ) : null); + + ("production" !== process.env.NODE_ENV ? invariant( + container && ( + (container.nodeType === ELEMENT_NODE_TYPE || container.nodeType === DOC_NODE_TYPE) + ), + 'unmountComponentAtNode(...): Target container is not a DOM element.' + ) : invariant(container && ( + (container.nodeType === ELEMENT_NODE_TYPE || container.nodeType === DOC_NODE_TYPE) + ))); + + var reactRootID = getReactRootID(container); + var component = instancesByReactRootID[reactRootID]; + if (!component) { + return false; + } + ReactMount.unmountComponentFromNode(component, container); + delete instancesByReactRootID[reactRootID]; + delete containersByReactRootID[reactRootID]; + if ("production" !== process.env.NODE_ENV) { + delete rootElementsByReactRootID[reactRootID]; + } + return true; + }, + + /** + * Unmounts a component and removes it from the DOM. + * + * @param {ReactComponent} instance React component instance. + * @param {DOMElement} container DOM element to unmount from. + * @final + * @internal + * @see {ReactMount.unmountComponentAtNode} + */ + unmountComponentFromNode: function(instance, container) { + ReactReconciler.unmountComponent(instance); + + if (container.nodeType === DOC_NODE_TYPE) { + container = container.documentElement; + } + + // http://jsperf.com/emptying-a-node + while (container.lastChild) { + container.removeChild(container.lastChild); + } + }, + + /** + * Finds the container DOM element that contains React component to which the + * supplied DOM `id` belongs. + * + * @param {string} id The ID of an element rendered by a React component. + * @return {?DOMElement} DOM element that contains the `id`. + */ + findReactContainerForID: function(id) { + var reactRootID = ReactInstanceHandles.getReactRootIDFromNodeID(id); + var container = containersByReactRootID[reactRootID]; + + if ("production" !== process.env.NODE_ENV) { + var rootElement = rootElementsByReactRootID[reactRootID]; + if (rootElement && rootElement.parentNode !== container) { + ("production" !== process.env.NODE_ENV ? invariant( + // Call internalGetID here because getID calls isValid which calls + // findReactContainerForID (this function). + internalGetID(rootElement) === reactRootID, + 'ReactMount: Root element ID differed from reactRootID.' + ) : invariant(// Call internalGetID here because getID calls isValid which calls + // findReactContainerForID (this function). + internalGetID(rootElement) === reactRootID)); + + var containerChild = container.firstChild; + if (containerChild && + reactRootID === internalGetID(containerChild)) { + // If the container has a new child with the same ID as the old + // root element, then rootElementsByReactRootID[reactRootID] is + // just stale and needs to be updated. The case that deserves a + // warning is when the container is empty. + rootElementsByReactRootID[reactRootID] = containerChild; + } else { + ("production" !== process.env.NODE_ENV ? warning( + false, + 'ReactMount: Root element has been removed from its original ' + + 'container. New container:', rootElement.parentNode + ) : null); + } + } + } + + return container; + }, + + /** + * Finds an element rendered by React with the supplied ID. + * + * @param {string} id ID of a DOM node in the React component. + * @return {DOMElement} Root DOM node of the React component. + */ + findReactNodeByID: function(id) { + var reactRoot = ReactMount.findReactContainerForID(id); + return ReactMount.findComponentRoot(reactRoot, id); + }, + + /** + * True if the supplied `node` is rendered by React. + * + * @param {*} node DOM Element to check. + * @return {boolean} True if the DOM Element appears to be rendered by React. + * @internal + */ + isRenderedByReact: function(node) { + if (node.nodeType !== 1) { + // Not a DOMElement, therefore not a React component + return false; + } + var id = ReactMount.getID(node); + return id ? id.charAt(0) === SEPARATOR : false; + }, + + /** + * Traverses up the ancestors of the supplied node to find a node that is a + * DOM representation of a React component. + * + * @param {*} node + * @return {?DOMEventTarget} + * @internal + */ + getFirstReactDOM: function(node) { + var current = node; + while (current && current.parentNode !== current) { + if (ReactMount.isRenderedByReact(current)) { + return current; + } + current = current.parentNode; + } + return null; + }, + + /** + * Finds a node with the supplied `targetID` inside of the supplied + * `ancestorNode`. Exploits the ID naming scheme to perform the search + * quickly. + * + * @param {DOMEventTarget} ancestorNode Search from this root. + * @pararm {string} targetID ID of the DOM representation of the component. + * @return {DOMEventTarget} DOM node with the supplied `targetID`. + * @internal + */ + findComponentRoot: function(ancestorNode, targetID) { + var firstChildren = findComponentRootReusableArray; + var childIndex = 0; + + var deepestAncestor = findDeepestCachedAncestor(targetID) || ancestorNode; + + firstChildren[0] = deepestAncestor.firstChild; + firstChildren.length = 1; + + while (childIndex < firstChildren.length) { + var child = firstChildren[childIndex++]; + var targetChild; + + while (child) { + var childID = ReactMount.getID(child); + if (childID) { + // Even if we find the node we're looking for, we finish looping + // through its siblings to ensure they're cached so that we don't have + // to revisit this node again. Otherwise, we make n^2 calls to getID + // when visiting the many children of a single node in order. + + if (targetID === childID) { + targetChild = child; + } else if (ReactInstanceHandles.isAncestorIDOf(childID, targetID)) { + // If we find a child whose ID is an ancestor of the given ID, + // then we can be sure that we only want to search the subtree + // rooted at this child, so we can throw out the rest of the + // search state. + firstChildren.length = childIndex = 0; + firstChildren.push(child.firstChild); + } + + } else { + // If this child had no ID, then there's a chance that it was + // injected automatically by the browser, as when a `` + // element sprouts an extra `` child as a side effect of + // `.innerHTML` parsing. Optimistically continue down this + // branch, but not before examining the other siblings. + firstChildren.push(child.firstChild); + } + + child = child.nextSibling; + } + + if (targetChild) { + // Emptying firstChildren/findComponentRootReusableArray is + // not necessary for correctness, but it helps the GC reclaim + // any nodes that were left at the end of the search. + firstChildren.length = 0; + + return targetChild; + } + } + + firstChildren.length = 0; + + ("production" !== process.env.NODE_ENV ? invariant( + false, + 'findComponentRoot(..., %s): Unable to find element. This probably ' + + 'means the DOM was unexpectedly mutated (e.g., by the browser), ' + + 'usually due to forgetting a when using tables, nesting tags ' + + 'like ,

, or , or using non-SVG elements in an ' + + 'parent. ' + + 'Try inspecting the child nodes of the element with React ID `%s`.', + targetID, + ReactMount.getID(ancestorNode) + ) : invariant(false)); + }, + + _mountImageIntoNode: function(markup, container, shouldReuseMarkup) { + ("production" !== process.env.NODE_ENV ? invariant( + container && ( + (container.nodeType === ELEMENT_NODE_TYPE || container.nodeType === DOC_NODE_TYPE) + ), + 'mountComponentIntoNode(...): Target container is not valid.' + ) : invariant(container && ( + (container.nodeType === ELEMENT_NODE_TYPE || container.nodeType === DOC_NODE_TYPE) + ))); + + if (shouldReuseMarkup) { + var rootElement = getReactRootElementInContainer(container); + if (ReactMarkupChecksum.canReuseMarkup(markup, rootElement)) { + return; + } else { + var checksum = rootElement.getAttribute( + ReactMarkupChecksum.CHECKSUM_ATTR_NAME + ); + rootElement.removeAttribute(ReactMarkupChecksum.CHECKSUM_ATTR_NAME); + + var rootMarkup = rootElement.outerHTML; + rootElement.setAttribute( + ReactMarkupChecksum.CHECKSUM_ATTR_NAME, + checksum + ); + + var diffIndex = firstDifferenceIndex(markup, rootMarkup); + var difference = ' (client) ' + + markup.substring(diffIndex - 20, diffIndex + 20) + + '\n (server) ' + rootMarkup.substring(diffIndex - 20, diffIndex + 20); + + ("production" !== process.env.NODE_ENV ? invariant( + container.nodeType !== DOC_NODE_TYPE, + 'You\'re trying to render a component to the document using ' + + 'server rendering but the checksum was invalid. This usually ' + + 'means you rendered a different component type or props on ' + + 'the client from the one on the server, or your render() ' + + 'methods are impure. React cannot handle this case due to ' + + 'cross-browser quirks by rendering at the document root. You ' + + 'should look for environment dependent code in your components ' + + 'and ensure the props are the same client and server side:\n%s', + difference + ) : invariant(container.nodeType !== DOC_NODE_TYPE)); + + if ("production" !== process.env.NODE_ENV) { + ("production" !== process.env.NODE_ENV ? warning( + false, + 'React attempted to reuse markup in a container but the ' + + 'checksum was invalid. This generally means that you are ' + + 'using server rendering and the markup generated on the ' + + 'server was not what the client was expecting. React injected ' + + 'new markup to compensate which works but you have lost many ' + + 'of the benefits of server rendering. Instead, figure out ' + + 'why the markup being generated is different on the client ' + + 'or server:\n%s', + difference + ) : null); + } + } + } + + ("production" !== process.env.NODE_ENV ? invariant( + container.nodeType !== DOC_NODE_TYPE, + 'You\'re trying to render a component to the document but ' + + 'you didn\'t use server rendering. We can\'t do this ' + + 'without using server rendering due to cross-browser quirks. ' + + 'See React.renderToString() for server rendering.' + ) : invariant(container.nodeType !== DOC_NODE_TYPE)); + + setInnerHTML(container, markup); + }, + + /** + * React ID utilities. + */ + + getReactRootID: getReactRootID, + + getID: getID, + + setID: setID, + + getNode: getNode, + + getNodeFromInstance: getNodeFromInstance, + + purgeID: purgeID + }; + + ReactPerf.measureMethods(ReactMount, 'ReactMount', { + _renderNewRootComponent: '_renderNewRootComponent', + _mountImageIntoNode: '_mountImageIntoNode' + }); + + module.exports = ReactMount; + + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(11))) + +/***/ }, +/* 75 */ +/***/ function(module, exports, __webpack_require__) { + + /** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactBrowserEventEmitter + * @typechecks static-only + */ + + 'use strict'; + + var EventConstants = __webpack_require__(13); + var EventPluginHub = __webpack_require__(76); + var EventPluginRegistry = __webpack_require__(77); + var ReactEventEmitterMixin = __webpack_require__(80); + var ViewportMetrics = __webpack_require__(81); + + var assign = __webpack_require__(8); + var isEventSupported = __webpack_require__(82); + + /** + * Summary of `ReactBrowserEventEmitter` event handling: + * + * - Top-level delegation is used to trap most native browser events. This + * may only occur in the main thread and is the responsibility of + * ReactEventListener, which is injected and can therefore support pluggable + * event sources. This is the only work that occurs in the main thread. + * + * - We normalize and de-duplicate events to account for browser quirks. This + * may be done in the worker thread. + * + * - Forward these native events (with the associated top-level type used to + * trap it) to `EventPluginHub`, which in turn will ask plugins if they want + * to extract any synthetic events. + * + * - The `EventPluginHub` will then process each event by annotating them with + * "dispatches", a sequence of listeners and IDs that care about that event. + * + * - The `EventPluginHub` then dispatches the events. + * + * Overview of React and the event system: + * + * +------------+ . + * | DOM | . + * +------------+ . + * | . + * v . + * +------------+ . + * | ReactEvent | . + * | Listener | . + * +------------+ . +-----------+ + * | . +--------+|SimpleEvent| + * | . | |Plugin | + * +-----|------+ . v +-----------+ + * | | | . +--------------+ +------------+ + * | +-----------.--->|EventPluginHub| | Event | + * | | . | | +-----------+ | Propagators| + * | ReactEvent | . | | |TapEvent | |------------| + * | Emitter | . | |<---+|Plugin | |other plugin| + * | | . | | +-----------+ | utilities | + * | +-----------.--->| | +------------+ + * | | | . +--------------+ + * +-----|------+ . ^ +-----------+ + * | . | |Enter/Leave| + * + . +-------+|Plugin | + * +-------------+ . +-----------+ + * | application | . + * |-------------| . + * | | . + * | | . + * +-------------+ . + * . + * React Core . General Purpose Event Plugin System + */ + + var alreadyListeningTo = {}; + var isMonitoringScrollValue = false; + var reactTopListenersCounter = 0; + + // For events like 'submit' which don't consistently bubble (which we trap at a + // lower node than `document`), binding at `document` would cause duplicate + // events so we don't include them here + var topEventMapping = { + topBlur: 'blur', + topChange: 'change', + topClick: 'click', + topCompositionEnd: 'compositionend', + topCompositionStart: 'compositionstart', + topCompositionUpdate: 'compositionupdate', + topContextMenu: 'contextmenu', + topCopy: 'copy', + topCut: 'cut', + topDoubleClick: 'dblclick', + topDrag: 'drag', + topDragEnd: 'dragend', + topDragEnter: 'dragenter', + topDragExit: 'dragexit', + topDragLeave: 'dragleave', + topDragOver: 'dragover', + topDragStart: 'dragstart', + topDrop: 'drop', + topFocus: 'focus', + topInput: 'input', + topKeyDown: 'keydown', + topKeyPress: 'keypress', + topKeyUp: 'keyup', + topMouseDown: 'mousedown', + topMouseMove: 'mousemove', + topMouseOut: 'mouseout', + topMouseOver: 'mouseover', + topMouseUp: 'mouseup', + topPaste: 'paste', + topScroll: 'scroll', + topSelectionChange: 'selectionchange', + topTextInput: 'textInput', + topTouchCancel: 'touchcancel', + topTouchEnd: 'touchend', + topTouchMove: 'touchmove', + topTouchStart: 'touchstart', + topWheel: 'wheel' + }; + + /** + * To ensure no conflicts with other potential React instances on the page + */ + var topListenersIDKey = '_reactListenersID' + String(Math.random()).slice(2); + + function getListeningForDocument(mountAt) { + // In IE8, `mountAt` is a host object and doesn't have `hasOwnProperty` + // directly. + if (!Object.prototype.hasOwnProperty.call(mountAt, topListenersIDKey)) { + mountAt[topListenersIDKey] = reactTopListenersCounter++; + alreadyListeningTo[mountAt[topListenersIDKey]] = {}; + } + return alreadyListeningTo[mountAt[topListenersIDKey]]; + } + + /** + * `ReactBrowserEventEmitter` is used to attach top-level event listeners. For + * example: + * + * ReactBrowserEventEmitter.putListener('myID', 'onClick', myFunction); + * + * This would allocate a "registration" of `('onClick', myFunction)` on 'myID'. + * + * @internal + */ + var ReactBrowserEventEmitter = assign({}, ReactEventEmitterMixin, { + + /** + * Injectable event backend + */ + ReactEventListener: null, + + injection: { + /** + * @param {object} ReactEventListener + */ + injectReactEventListener: function(ReactEventListener) { + ReactEventListener.setHandleTopLevel( + ReactBrowserEventEmitter.handleTopLevel + ); + ReactBrowserEventEmitter.ReactEventListener = ReactEventListener; + } + }, + + /** + * Sets whether or not any created callbacks should be enabled. + * + * @param {boolean} enabled True if callbacks should be enabled. + */ + setEnabled: function(enabled) { + if (ReactBrowserEventEmitter.ReactEventListener) { + ReactBrowserEventEmitter.ReactEventListener.setEnabled(enabled); + } + }, + + /** + * @return {boolean} True if callbacks are enabled. + */ + isEnabled: function() { + return !!( + (ReactBrowserEventEmitter.ReactEventListener && ReactBrowserEventEmitter.ReactEventListener.isEnabled()) + ); + }, + + /** + * We listen for bubbled touch events on the document object. + * + * Firefox v8.01 (and possibly others) exhibited strange behavior when + * mounting `onmousemove` events at some node that was not the document + * element. The symptoms were that if your mouse is not moving over something + * contained within that mount point (for example on the background) the + * top-level listeners for `onmousemove` won't be called. However, if you + * register the `mousemove` on the document object, then it will of course + * catch all `mousemove`s. This along with iOS quirks, justifies restricting + * top-level listeners to the document object only, at least for these + * movement types of events and possibly all events. + * + * @see http://www.quirksmode.org/blog/archives/2010/09/click_event_del.html + * + * Also, `keyup`/`keypress`/`keydown` do not bubble to the window on IE, but + * they bubble to document. + * + * @param {string} registrationName Name of listener (e.g. `onClick`). + * @param {object} contentDocumentHandle Document which owns the container + */ + listenTo: function(registrationName, contentDocumentHandle) { + var mountAt = contentDocumentHandle; + var isListening = getListeningForDocument(mountAt); + var dependencies = EventPluginRegistry. + registrationNameDependencies[registrationName]; + + var topLevelTypes = EventConstants.topLevelTypes; + for (var i = 0, l = dependencies.length; i < l; i++) { + var dependency = dependencies[i]; + if (!( + (isListening.hasOwnProperty(dependency) && isListening[dependency]) + )) { + if (dependency === topLevelTypes.topWheel) { + if (isEventSupported('wheel')) { + ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent( + topLevelTypes.topWheel, + 'wheel', + mountAt + ); + } else if (isEventSupported('mousewheel')) { + ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent( + topLevelTypes.topWheel, + 'mousewheel', + mountAt + ); + } else { + // Firefox needs to capture a different mouse scroll event. + // @see http://www.quirksmode.org/dom/events/tests/scroll.html + ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent( + topLevelTypes.topWheel, + 'DOMMouseScroll', + mountAt + ); + } + } else if (dependency === topLevelTypes.topScroll) { + + if (isEventSupported('scroll', true)) { + ReactBrowserEventEmitter.ReactEventListener.trapCapturedEvent( + topLevelTypes.topScroll, + 'scroll', + mountAt + ); + } else { + ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent( + topLevelTypes.topScroll, + 'scroll', + ReactBrowserEventEmitter.ReactEventListener.WINDOW_HANDLE + ); + } + } else if (dependency === topLevelTypes.topFocus || + dependency === topLevelTypes.topBlur) { + + if (isEventSupported('focus', true)) { + ReactBrowserEventEmitter.ReactEventListener.trapCapturedEvent( + topLevelTypes.topFocus, + 'focus', + mountAt + ); + ReactBrowserEventEmitter.ReactEventListener.trapCapturedEvent( + topLevelTypes.topBlur, + 'blur', + mountAt + ); + } else if (isEventSupported('focusin')) { + // IE has `focusin` and `focusout` events which bubble. + // @see http://www.quirksmode.org/blog/archives/2008/04/delegating_the.html + ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent( + topLevelTypes.topFocus, + 'focusin', + mountAt + ); + ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent( + topLevelTypes.topBlur, + 'focusout', + mountAt + ); + } + + // to make sure blur and focus event listeners are only attached once + isListening[topLevelTypes.topBlur] = true; + isListening[topLevelTypes.topFocus] = true; + } else if (topEventMapping.hasOwnProperty(dependency)) { + ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent( + dependency, + topEventMapping[dependency], + mountAt + ); + } + + isListening[dependency] = true; + } + } + }, + + trapBubbledEvent: function(topLevelType, handlerBaseName, handle) { + return ReactBrowserEventEmitter.ReactEventListener.trapBubbledEvent( + topLevelType, + handlerBaseName, + handle + ); + }, + + trapCapturedEvent: function(topLevelType, handlerBaseName, handle) { + return ReactBrowserEventEmitter.ReactEventListener.trapCapturedEvent( + topLevelType, + handlerBaseName, + handle + ); + }, + + /** + * Listens to window scroll and resize events. We cache scroll values so that + * application code can access them without triggering reflows. + * + * NOTE: Scroll events do not bubble. + * + * @see http://www.quirksmode.org/dom/events/scroll.html + */ + ensureScrollValueMonitoring: function() { + if (!isMonitoringScrollValue) { + var refresh = ViewportMetrics.refreshScrollValues; + ReactBrowserEventEmitter.ReactEventListener.monitorScrollValue(refresh); + isMonitoringScrollValue = true; + } + }, + + eventNameDispatchConfigs: EventPluginHub.eventNameDispatchConfigs, + + registrationNameModules: EventPluginHub.registrationNameModules, + + putListener: EventPluginHub.putListener, + + getListener: EventPluginHub.getListener, + + deleteListener: EventPluginHub.deleteListener, + + deleteAllListeners: EventPluginHub.deleteAllListeners + + }); + + module.exports = ReactBrowserEventEmitter; + + +/***/ }, +/* 76 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule EventPluginHub + */ + + 'use strict'; + + var EventPluginRegistry = __webpack_require__(77); + var EventPluginUtils = __webpack_require__(12); + + var accumulateInto = __webpack_require__(78); + var forEachAccumulated = __webpack_require__(79); + var invariant = __webpack_require__(15); + + /** + * Internal store for event listeners + */ + var listenerBank = {}; + + /** + * Internal queue of events that have accumulated their dispatches and are + * waiting to have their dispatches executed. + */ + var eventQueue = null; + + /** + * Dispatches an event and releases it back into the pool, unless persistent. + * + * @param {?object} event Synthetic event to be dispatched. + * @private + */ + var executeDispatchesAndRelease = function(event) { + if (event) { + var executeDispatch = EventPluginUtils.executeDispatch; + // Plugins can provide custom behavior when dispatching events. + var PluginModule = EventPluginRegistry.getPluginModuleForEvent(event); + if (PluginModule && PluginModule.executeDispatch) { + executeDispatch = PluginModule.executeDispatch; + } + EventPluginUtils.executeDispatchesInOrder(event, executeDispatch); + + if (!event.isPersistent()) { + event.constructor.release(event); + } + } + }; + + /** + * - `InstanceHandle`: [required] Module that performs logical traversals of DOM + * hierarchy given ids of the logical DOM elements involved. + */ + var InstanceHandle = null; + + function validateInstanceHandle() { + var valid = + InstanceHandle && + InstanceHandle.traverseTwoPhase && + InstanceHandle.traverseEnterLeave; + ("production" !== process.env.NODE_ENV ? invariant( + valid, + 'InstanceHandle not injected before use!' + ) : invariant(valid)); + } + + /** + * This is a unified interface for event plugins to be installed and configured. + * + * Event plugins can implement the following properties: + * + * `extractEvents` {function(string, DOMEventTarget, string, object): *} + * Required. When a top-level event is fired, this method is expected to + * extract synthetic events that will in turn be queued and dispatched. + * + * `eventTypes` {object} + * Optional, plugins that fire events must publish a mapping of registration + * names that are used to register listeners. Values of this mapping must + * be objects that contain `registrationName` or `phasedRegistrationNames`. + * + * `executeDispatch` {function(object, function, string)} + * Optional, allows plugins to override how an event gets dispatched. By + * default, the listener is simply invoked. + * + * Each plugin that is injected into `EventsPluginHub` is immediately operable. + * + * @public + */ + var EventPluginHub = { + + /** + * Methods for injecting dependencies. + */ + injection: { + + /** + * @param {object} InjectedMount + * @public + */ + injectMount: EventPluginUtils.injection.injectMount, + + /** + * @param {object} InjectedInstanceHandle + * @public + */ + injectInstanceHandle: function(InjectedInstanceHandle) { + InstanceHandle = InjectedInstanceHandle; + if ("production" !== process.env.NODE_ENV) { + validateInstanceHandle(); + } + }, + + getInstanceHandle: function() { + if ("production" !== process.env.NODE_ENV) { + validateInstanceHandle(); + } + return InstanceHandle; + }, + + /** + * @param {array} InjectedEventPluginOrder + * @public + */ + injectEventPluginOrder: EventPluginRegistry.injectEventPluginOrder, + + /** + * @param {object} injectedNamesToPlugins Map from names to plugin modules. + */ + injectEventPluginsByName: EventPluginRegistry.injectEventPluginsByName + + }, + + eventNameDispatchConfigs: EventPluginRegistry.eventNameDispatchConfigs, + + registrationNameModules: EventPluginRegistry.registrationNameModules, + + /** + * Stores `listener` at `listenerBank[registrationName][id]`. Is idempotent. + * + * @param {string} id ID of the DOM element. + * @param {string} registrationName Name of listener (e.g. `onClick`). + * @param {?function} listener The callback to store. + */ + putListener: function(id, registrationName, listener) { + ("production" !== process.env.NODE_ENV ? invariant( + !listener || typeof listener === 'function', + 'Expected %s listener to be a function, instead got type %s', + registrationName, typeof listener + ) : invariant(!listener || typeof listener === 'function')); + + var bankForRegistrationName = + listenerBank[registrationName] || (listenerBank[registrationName] = {}); + bankForRegistrationName[id] = listener; + }, + + /** + * @param {string} id ID of the DOM element. + * @param {string} registrationName Name of listener (e.g. `onClick`). + * @return {?function} The stored callback. + */ + getListener: function(id, registrationName) { + var bankForRegistrationName = listenerBank[registrationName]; + return bankForRegistrationName && bankForRegistrationName[id]; + }, + + /** + * Deletes a listener from the registration bank. + * + * @param {string} id ID of the DOM element. + * @param {string} registrationName Name of listener (e.g. `onClick`). + */ + deleteListener: function(id, registrationName) { + var bankForRegistrationName = listenerBank[registrationName]; + if (bankForRegistrationName) { + delete bankForRegistrationName[id]; + } + }, + + /** + * Deletes all listeners for the DOM element with the supplied ID. + * + * @param {string} id ID of the DOM element. + */ + deleteAllListeners: function(id) { + for (var registrationName in listenerBank) { + delete listenerBank[registrationName][id]; + } + }, + + /** + * Allows registered plugins an opportunity to extract events from top-level + * native browser events. + * + * @param {string} topLevelType Record from `EventConstants`. + * @param {DOMEventTarget} topLevelTarget The listening component root node. + * @param {string} topLevelTargetID ID of `topLevelTarget`. + * @param {object} nativeEvent Native browser event. + * @return {*} An accumulation of synthetic events. + * @internal + */ + extractEvents: function( + topLevelType, + topLevelTarget, + topLevelTargetID, + nativeEvent) { + var events; + var plugins = EventPluginRegistry.plugins; + for (var i = 0, l = plugins.length; i < l; i++) { + // Not every plugin in the ordering may be loaded at runtime. + var possiblePlugin = plugins[i]; + if (possiblePlugin) { + var extractedEvents = possiblePlugin.extractEvents( + topLevelType, + topLevelTarget, + topLevelTargetID, + nativeEvent + ); + if (extractedEvents) { + events = accumulateInto(events, extractedEvents); + } + } + } + return events; + }, + + /** + * Enqueues a synthetic event that should be dispatched when + * `processEventQueue` is invoked. + * + * @param {*} events An accumulation of synthetic events. + * @internal + */ + enqueueEvents: function(events) { + if (events) { + eventQueue = accumulateInto(eventQueue, events); + } + }, + + /** + * Dispatches all synthetic events on the event queue. + * + * @internal + */ + processEventQueue: function() { + // Set `eventQueue` to null before processing it so that we can tell if more + // events get enqueued while processing. + var processingEventQueue = eventQueue; + eventQueue = null; + forEachAccumulated(processingEventQueue, executeDispatchesAndRelease); + ("production" !== process.env.NODE_ENV ? invariant( + !eventQueue, + 'processEventQueue(): Additional events were enqueued while processing ' + + 'an event queue. Support for this has not yet been implemented.' + ) : invariant(!eventQueue)); + }, + + /** + * These are needed for tests only. Do not use! + */ + __purge: function() { + listenerBank = {}; + }, + + __getListenerBank: function() { + return listenerBank; + } + + }; + + module.exports = EventPluginHub; + + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(11))) + +/***/ }, +/* 77 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule EventPluginRegistry + * @typechecks static-only + */ + + 'use strict'; + + var invariant = __webpack_require__(15); + + /** + * Injectable ordering of event plugins. + */ + var EventPluginOrder = null; + + /** + * Injectable mapping from names to event plugin modules. + */ + var namesToPlugins = {}; + + /** + * Recomputes the plugin list using the injected plugins and plugin ordering. + * + * @private + */ + function recomputePluginOrdering() { + if (!EventPluginOrder) { + // Wait until an `EventPluginOrder` is injected. + return; + } + for (var pluginName in namesToPlugins) { + var PluginModule = namesToPlugins[pluginName]; + var pluginIndex = EventPluginOrder.indexOf(pluginName); + ("production" !== process.env.NODE_ENV ? invariant( + pluginIndex > -1, + 'EventPluginRegistry: Cannot inject event plugins that do not exist in ' + + 'the plugin ordering, `%s`.', + pluginName + ) : invariant(pluginIndex > -1)); + if (EventPluginRegistry.plugins[pluginIndex]) { + continue; + } + ("production" !== process.env.NODE_ENV ? invariant( + PluginModule.extractEvents, + 'EventPluginRegistry: Event plugins must implement an `extractEvents` ' + + 'method, but `%s` does not.', + pluginName + ) : invariant(PluginModule.extractEvents)); + EventPluginRegistry.plugins[pluginIndex] = PluginModule; + var publishedEvents = PluginModule.eventTypes; + for (var eventName in publishedEvents) { + ("production" !== process.env.NODE_ENV ? invariant( + publishEventForPlugin( + publishedEvents[eventName], + PluginModule, + eventName + ), + 'EventPluginRegistry: Failed to publish event `%s` for plugin `%s`.', + eventName, + pluginName + ) : invariant(publishEventForPlugin( + publishedEvents[eventName], + PluginModule, + eventName + ))); + } + } + } + + /** + * Publishes an event so that it can be dispatched by the supplied plugin. + * + * @param {object} dispatchConfig Dispatch configuration for the event. + * @param {object} PluginModule Plugin publishing the event. + * @return {boolean} True if the event was successfully published. + * @private + */ + function publishEventForPlugin(dispatchConfig, PluginModule, eventName) { + ("production" !== process.env.NODE_ENV ? invariant( + !EventPluginRegistry.eventNameDispatchConfigs.hasOwnProperty(eventName), + 'EventPluginHub: More than one plugin attempted to publish the same ' + + 'event name, `%s`.', + eventName + ) : invariant(!EventPluginRegistry.eventNameDispatchConfigs.hasOwnProperty(eventName))); + EventPluginRegistry.eventNameDispatchConfigs[eventName] = dispatchConfig; + + var phasedRegistrationNames = dispatchConfig.phasedRegistrationNames; + if (phasedRegistrationNames) { + for (var phaseName in phasedRegistrationNames) { + if (phasedRegistrationNames.hasOwnProperty(phaseName)) { + var phasedRegistrationName = phasedRegistrationNames[phaseName]; + publishRegistrationName( + phasedRegistrationName, + PluginModule, + eventName + ); + } + } + return true; + } else if (dispatchConfig.registrationName) { + publishRegistrationName( + dispatchConfig.registrationName, + PluginModule, + eventName + ); + return true; + } + return false; + } + + /** + * Publishes a registration name that is used to identify dispatched events and + * can be used with `EventPluginHub.putListener` to register listeners. + * + * @param {string} registrationName Registration name to add. + * @param {object} PluginModule Plugin publishing the event. + * @private + */ + function publishRegistrationName(registrationName, PluginModule, eventName) { + ("production" !== process.env.NODE_ENV ? invariant( + !EventPluginRegistry.registrationNameModules[registrationName], + 'EventPluginHub: More than one plugin attempted to publish the same ' + + 'registration name, `%s`.', + registrationName + ) : invariant(!EventPluginRegistry.registrationNameModules[registrationName])); + EventPluginRegistry.registrationNameModules[registrationName] = PluginModule; + EventPluginRegistry.registrationNameDependencies[registrationName] = + PluginModule.eventTypes[eventName].dependencies; + } + + /** + * Registers plugins so that they can extract and dispatch events. + * + * @see {EventPluginHub} + */ + var EventPluginRegistry = { + + /** + * Ordered list of injected plugins. + */ + plugins: [], + + /** + * Mapping from event name to dispatch config + */ + eventNameDispatchConfigs: {}, + + /** + * Mapping from registration name to plugin module + */ + registrationNameModules: {}, + + /** + * Mapping from registration name to event name + */ + registrationNameDependencies: {}, + + /** + * Injects an ordering of plugins (by plugin name). This allows the ordering + * to be decoupled from injection of the actual plugins so that ordering is + * always deterministic regardless of packaging, on-the-fly injection, etc. + * + * @param {array} InjectedEventPluginOrder + * @internal + * @see {EventPluginHub.injection.injectEventPluginOrder} + */ + injectEventPluginOrder: function(InjectedEventPluginOrder) { + ("production" !== process.env.NODE_ENV ? invariant( + !EventPluginOrder, + 'EventPluginRegistry: Cannot inject event plugin ordering more than ' + + 'once. You are likely trying to load more than one copy of React.' + ) : invariant(!EventPluginOrder)); + // Clone the ordering so it cannot be dynamically mutated. + EventPluginOrder = Array.prototype.slice.call(InjectedEventPluginOrder); + recomputePluginOrdering(); + }, + + /** + * Injects plugins to be used by `EventPluginHub`. The plugin names must be + * in the ordering injected by `injectEventPluginOrder`. + * + * Plugins can be injected as part of page initialization or on-the-fly. + * + * @param {object} injectedNamesToPlugins Map from names to plugin modules. + * @internal + * @see {EventPluginHub.injection.injectEventPluginsByName} + */ + injectEventPluginsByName: function(injectedNamesToPlugins) { + var isOrderingDirty = false; + for (var pluginName in injectedNamesToPlugins) { + if (!injectedNamesToPlugins.hasOwnProperty(pluginName)) { + continue; + } + var PluginModule = injectedNamesToPlugins[pluginName]; + if (!namesToPlugins.hasOwnProperty(pluginName) || + namesToPlugins[pluginName] !== PluginModule) { + ("production" !== process.env.NODE_ENV ? invariant( + !namesToPlugins[pluginName], + 'EventPluginRegistry: Cannot inject two different event plugins ' + + 'using the same name, `%s`.', + pluginName + ) : invariant(!namesToPlugins[pluginName])); + namesToPlugins[pluginName] = PluginModule; + isOrderingDirty = true; + } + } + if (isOrderingDirty) { + recomputePluginOrdering(); + } + }, + + /** + * Looks up the plugin for the supplied event. + * + * @param {object} event A synthetic event. + * @return {?object} The plugin that created the supplied event. + * @internal + */ + getPluginModuleForEvent: function(event) { + var dispatchConfig = event.dispatchConfig; + if (dispatchConfig.registrationName) { + return EventPluginRegistry.registrationNameModules[ + dispatchConfig.registrationName + ] || null; + } + for (var phase in dispatchConfig.phasedRegistrationNames) { + if (!dispatchConfig.phasedRegistrationNames.hasOwnProperty(phase)) { + continue; + } + var PluginModule = EventPluginRegistry.registrationNameModules[ + dispatchConfig.phasedRegistrationNames[phase] + ]; + if (PluginModule) { + return PluginModule; + } + } + return null; + }, + + /** + * Exposed for unit testing. + * @private + */ + _resetEventPlugins: function() { + EventPluginOrder = null; + for (var pluginName in namesToPlugins) { + if (namesToPlugins.hasOwnProperty(pluginName)) { + delete namesToPlugins[pluginName]; + } + } + EventPluginRegistry.plugins.length = 0; + + var eventNameDispatchConfigs = EventPluginRegistry.eventNameDispatchConfigs; + for (var eventName in eventNameDispatchConfigs) { + if (eventNameDispatchConfigs.hasOwnProperty(eventName)) { + delete eventNameDispatchConfigs[eventName]; + } + } + + var registrationNameModules = EventPluginRegistry.registrationNameModules; + for (var registrationName in registrationNameModules) { + if (registrationNameModules.hasOwnProperty(registrationName)) { + delete registrationNameModules[registrationName]; + } + } + } + + }; + + module.exports = EventPluginRegistry; + + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(11))) + +/***/ }, +/* 78 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2014-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule accumulateInto + */ + + 'use strict'; + + var invariant = __webpack_require__(15); + + /** + * + * Accumulates items that must not be null or undefined into the first one. This + * is used to conserve memory by avoiding array allocations, and thus sacrifices + * API cleanness. Since `current` can be null before being passed in and not + * null after this function, make sure to assign it back to `current`: + * + * `a = accumulateInto(a, b);` + * + * This API should be sparingly used. Try `accumulate` for something cleaner. + * + * @return {*|array<*>} An accumulation of items. + */ + + function accumulateInto(current, next) { + ("production" !== process.env.NODE_ENV ? invariant( + next != null, + 'accumulateInto(...): Accumulated items must not be null or undefined.' + ) : invariant(next != null)); + if (current == null) { + return next; + } + + // Both are not empty. Warning: Never call x.concat(y) when you are not + // certain that x is an Array (x could be a string with concat method). + var currentIsArray = Array.isArray(current); + var nextIsArray = Array.isArray(next); + + if (currentIsArray && nextIsArray) { + current.push.apply(current, next); + return current; + } + + if (currentIsArray) { + current.push(next); + return current; + } + + if (nextIsArray) { + // A bit too dangerous to mutate `next`. + return [current].concat(next); + } + + return [current, next]; + } + + module.exports = accumulateInto; + + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(11))) + +/***/ }, +/* 79 */ +/***/ function(module, exports) { + + /** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule forEachAccumulated + */ + + 'use strict'; + + /** + * @param {array} an "accumulation" of items which is either an Array or + * a single item. Useful when paired with the `accumulate` module. This is a + * simple utility that allows us to reason about a collection of items, but + * handling the case when there is exactly one item (and we do not need to + * allocate an array). + */ + var forEachAccumulated = function(arr, cb, scope) { + if (Array.isArray(arr)) { + arr.forEach(cb, scope); + } else if (arr) { + cb.call(scope, arr); + } + }; + + module.exports = forEachAccumulated; + + +/***/ }, +/* 80 */ +/***/ function(module, exports, __webpack_require__) { + + /** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactEventEmitterMixin + */ + + 'use strict'; + + var EventPluginHub = __webpack_require__(76); + + function runEventQueueInBatch(events) { + EventPluginHub.enqueueEvents(events); + EventPluginHub.processEventQueue(); + } + + var ReactEventEmitterMixin = { + + /** + * Streams a fired top-level event to `EventPluginHub` where plugins have the + * opportunity to create `ReactEvent`s to be dispatched. + * + * @param {string} topLevelType Record from `EventConstants`. + * @param {object} topLevelTarget The listening component root node. + * @param {string} topLevelTargetID ID of `topLevelTarget`. + * @param {object} nativeEvent Native environment event. + */ + handleTopLevel: function( + topLevelType, + topLevelTarget, + topLevelTargetID, + nativeEvent) { + var events = EventPluginHub.extractEvents( + topLevelType, + topLevelTarget, + topLevelTargetID, + nativeEvent + ); + + runEventQueueInBatch(events); + } + }; + + module.exports = ReactEventEmitterMixin; + + +/***/ }, +/* 81 */ +/***/ function(module, exports) { + + /** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ViewportMetrics + */ + + 'use strict'; + + var ViewportMetrics = { + + currentScrollLeft: 0, + + currentScrollTop: 0, + + refreshScrollValues: function(scrollPosition) { + ViewportMetrics.currentScrollLeft = scrollPosition.x; + ViewportMetrics.currentScrollTop = scrollPosition.y; + } + + }; + + module.exports = ViewportMetrics; + + +/***/ }, +/* 82 */ +/***/ function(module, exports, __webpack_require__) { + + /** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule isEventSupported + */ + + 'use strict'; + + var ExecutionEnvironment = __webpack_require__(58); + + var useHasFeature; + if (ExecutionEnvironment.canUseDOM) { + useHasFeature = + document.implementation && + document.implementation.hasFeature && + // always returns true in newer browsers as per the standard. + // @see http://dom.spec.whatwg.org/#dom-domimplementation-hasfeature + document.implementation.hasFeature('', '') !== true; + } + + /** + * Checks if an event is supported in the current execution environment. + * + * NOTE: This will not work correctly for non-generic events such as `change`, + * `reset`, `load`, `error`, and `select`. + * + * Borrows from Modernizr. + * + * @param {string} eventNameSuffix Event name, e.g. "click". + * @param {?boolean} capture Check if the capture phase is supported. + * @return {boolean} True if the event is supported. + * @internal + * @license Modernizr 3.0.0pre (Custom Build) | MIT + */ + function isEventSupported(eventNameSuffix, capture) { + if (!ExecutionEnvironment.canUseDOM || + capture && !('addEventListener' in document)) { + return false; + } + + var eventName = 'on' + eventNameSuffix; + var isSupported = eventName in document; + + if (!isSupported) { + var element = document.createElement('div'); + element.setAttribute(eventName, 'return;'); + isSupported = typeof element[eventName] === 'function'; + } + + if (!isSupported && useHasFeature && eventNameSuffix === 'wheel') { + // This is the only way to test support for the `wheel` event in IE9+. + isSupported = document.implementation.hasFeature('Events.wheel', '3.0'); + } + + return isSupported; + } + + module.exports = isEventSupported; + + +/***/ }, +/* 83 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2014-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactEmptyComponent + */ + + 'use strict'; + + var ReactElement = __webpack_require__(19); + var ReactInstanceMap = __webpack_require__(43); + + var invariant = __webpack_require__(15); + + var component; + // This registry keeps track of the React IDs of the components that rendered to + // `null` (in reality a placeholder such as `noscript`) + var nullComponentIDsRegistry = {}; + + var ReactEmptyComponentInjection = { + injectEmptyComponent: function(emptyComponent) { + component = ReactElement.createFactory(emptyComponent); + } + }; + + var ReactEmptyComponentType = function() {}; + ReactEmptyComponentType.prototype.componentDidMount = function() { + var internalInstance = ReactInstanceMap.get(this); + // TODO: Make sure we run these methods in the correct order, we shouldn't + // need this check. We're going to assume if we're here it means we ran + // componentWillUnmount already so there is no internal instance (it gets + // removed as part of the unmounting process). + if (!internalInstance) { + return; + } + registerNullComponentID(internalInstance._rootNodeID); + }; + ReactEmptyComponentType.prototype.componentWillUnmount = function() { + var internalInstance = ReactInstanceMap.get(this); + // TODO: Get rid of this check. See TODO in componentDidMount. + if (!internalInstance) { + return; + } + deregisterNullComponentID(internalInstance._rootNodeID); + }; + ReactEmptyComponentType.prototype.render = function() { + ("production" !== process.env.NODE_ENV ? invariant( + component, + 'Trying to return null from a render, but no null placeholder component ' + + 'was injected.' + ) : invariant(component)); + return component(); + }; + + var emptyElement = ReactElement.createElement(ReactEmptyComponentType); + + /** + * Mark the component as having rendered to null. + * @param {string} id Component's `_rootNodeID`. + */ + function registerNullComponentID(id) { + nullComponentIDsRegistry[id] = true; + } + + /** + * Unmark the component as having rendered to null: it renders to something now. + * @param {string} id Component's `_rootNodeID`. + */ + function deregisterNullComponentID(id) { + delete nullComponentIDsRegistry[id]; + } + + /** + * @param {string} id Component's `_rootNodeID`. + * @return {boolean} True if the component is rendered to null. + */ + function isNullComponentID(id) { + return !!nullComponentIDsRegistry[id]; + } + + var ReactEmptyComponent = { + emptyElement: emptyElement, + injection: ReactEmptyComponentInjection, + isNullComponentID: isNullComponentID + }; + + module.exports = ReactEmptyComponent; + + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(11))) + +/***/ }, +/* 84 */ +/***/ function(module, exports, __webpack_require__) { + + /** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactMarkupChecksum + */ + + 'use strict'; + + var adler32 = __webpack_require__(85); + + var ReactMarkupChecksum = { + CHECKSUM_ATTR_NAME: 'data-react-checksum', + + /** + * @param {string} markup Markup string + * @return {string} Markup string with checksum attribute attached + */ + addChecksumToMarkup: function(markup) { + var checksum = adler32(markup); + return markup.replace( + '>', + ' ' + ReactMarkupChecksum.CHECKSUM_ATTR_NAME + '="' + checksum + '">' + ); + }, + + /** + * @param {string} markup to use + * @param {DOMElement} element root React element + * @returns {boolean} whether or not the markup is the same + */ + canReuseMarkup: function(markup, element) { + var existingChecksum = element.getAttribute( + ReactMarkupChecksum.CHECKSUM_ATTR_NAME + ); + existingChecksum = existingChecksum && parseInt(existingChecksum, 10); + var markupChecksum = adler32(markup); + return markupChecksum === existingChecksum; + } + }; + + module.exports = ReactMarkupChecksum; + + +/***/ }, +/* 85 */ +/***/ function(module, exports) { + + /** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule adler32 + */ + + /* jslint bitwise:true */ + + 'use strict'; + + var MOD = 65521; + + // This is a clean-room implementation of adler32 designed for detecting + // if markup is not what we expect it to be. It does not need to be + // cryptographically strong, only reasonably good at detecting if markup + // generated on the server is different than that on the client. + function adler32(data) { + var a = 1; + var b = 0; + for (var i = 0; i < data.length; i++) { + a = (a + data.charCodeAt(i)) % MOD; + b = (b + a) % MOD; + } + return a | (b << 16); + } + + module.exports = adler32; + + +/***/ }, +/* 86 */ +/***/ function(module, exports, __webpack_require__) { + + /** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule containsNode + * @typechecks + */ + + var isTextNode = __webpack_require__(87); + + /*jslint bitwise:true */ + + /** + * Checks if a given DOM node contains or is another DOM node. + * + * @param {?DOMNode} outerNode Outer DOM node. + * @param {?DOMNode} innerNode Inner DOM node. + * @return {boolean} True if `outerNode` contains or is `innerNode`. + */ + function containsNode(outerNode, innerNode) { + if (!outerNode || !innerNode) { + return false; + } else if (outerNode === innerNode) { + return true; + } else if (isTextNode(outerNode)) { + return false; + } else if (isTextNode(innerNode)) { + return containsNode(outerNode, innerNode.parentNode); + } else if (outerNode.contains) { + return outerNode.contains(innerNode); + } else if (outerNode.compareDocumentPosition) { + return !!(outerNode.compareDocumentPosition(innerNode) & 16); + } else { + return false; + } + } + + module.exports = containsNode; + + +/***/ }, +/* 87 */ +/***/ function(module, exports, __webpack_require__) { + + /** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule isTextNode + * @typechecks + */ + + var isNode = __webpack_require__(88); + + /** + * @param {*} object The object to check. + * @return {boolean} Whether or not the object is a DOM text node. + */ + function isTextNode(object) { + return isNode(object) && object.nodeType == 3; + } + + module.exports = isTextNode; + + +/***/ }, +/* 88 */ +/***/ function(module, exports) { + + /** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule isNode + * @typechecks + */ + + /** + * @param {*} object The object to check. + * @return {boolean} Whether or not the object is a DOM node. + */ + function isNode(object) { + return !!(object && ( + ((typeof Node === 'function' ? object instanceof Node : typeof object === 'object' && + typeof object.nodeType === 'number' && + typeof object.nodeName === 'string')) + )); + } + + module.exports = isNode; + + +/***/ }, +/* 89 */ +/***/ function(module, exports) { + + /** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule getReactRootElementInContainer + */ + + 'use strict'; + + var DOC_NODE_TYPE = 9; + + /** + * @param {DOMElement|DOMDocument} container DOM element that may contain + * a React component + * @return {?*} DOM element that may have the reactRoot ID, or null. + */ + function getReactRootElementInContainer(container) { + if (!container) { + return null; + } + + if (container.nodeType === DOC_NODE_TYPE) { + return container.documentElement; + } else { + return container.firstChild; + } + } + + module.exports = getReactRootElementInContainer; + + +/***/ }, +/* 90 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule instantiateReactComponent + * @typechecks static-only + */ + + 'use strict'; + + var ReactCompositeComponent = __webpack_require__(91); + var ReactEmptyComponent = __webpack_require__(83); + var ReactNativeComponent = __webpack_require__(40); + + var assign = __webpack_require__(8); + var invariant = __webpack_require__(15); + var warning = __webpack_require__(22); + + // To avoid a cyclic dependency, we create the final class in this module + var ReactCompositeComponentWrapper = function() { }; + assign( + ReactCompositeComponentWrapper.prototype, + ReactCompositeComponent.Mixin, + { + _instantiateReactComponent: instantiateReactComponent + } + ); + + /** + * Check if the type reference is a known internal type. I.e. not a user + * provided composite type. + * + * @param {function} type + * @return {boolean} Returns true if this is a valid internal type. + */ + function isInternalComponentType(type) { + return ( + typeof type === 'function' && + typeof type.prototype !== 'undefined' && + typeof type.prototype.mountComponent === 'function' && + typeof type.prototype.receiveComponent === 'function' + ); + } + + /** + * Given a ReactNode, create an instance that will actually be mounted. + * + * @param {ReactNode} node + * @param {*} parentCompositeType The composite type that resolved this. + * @return {object} A new instance of the element's constructor. + * @protected + */ + function instantiateReactComponent(node, parentCompositeType) { + var instance; + + if (node === null || node === false) { + node = ReactEmptyComponent.emptyElement; + } + + if (typeof node === 'object') { + var element = node; + if ("production" !== process.env.NODE_ENV) { + ("production" !== process.env.NODE_ENV ? warning( + element && (typeof element.type === 'function' || + typeof element.type === 'string'), + 'Only functions or strings can be mounted as React components.' + ) : null); + } + + // Special case string values + if (parentCompositeType === element.type && + typeof element.type === 'string') { + // Avoid recursion if the wrapper renders itself. + instance = ReactNativeComponent.createInternalComponent(element); + // All native components are currently wrapped in a composite so we're + // safe to assume that this is what we should instantiate. + } else if (isInternalComponentType(element.type)) { + // This is temporarily available for custom components that are not string + // represenations. I.e. ART. Once those are updated to use the string + // representation, we can drop this code path. + instance = new element.type(element); + } else { + instance = new ReactCompositeComponentWrapper(); + } + } else if (typeof node === 'string' || typeof node === 'number') { + instance = ReactNativeComponent.createInstanceForText(node); + } else { + ("production" !== process.env.NODE_ENV ? invariant( + false, + 'Encountered invalid React node of type %s', + typeof node + ) : invariant(false)); + } + + if ("production" !== process.env.NODE_ENV) { + ("production" !== process.env.NODE_ENV ? warning( + typeof instance.construct === 'function' && + typeof instance.mountComponent === 'function' && + typeof instance.receiveComponent === 'function' && + typeof instance.unmountComponent === 'function', + 'Only React Components can be mounted.' + ) : null); + } + + // Sets up the instance. This can probably just move into the constructor now. + instance.construct(node); + + // These two fields are used by the DOM and ART diffing algorithms + // respectively. Instead of using expandos on components, we should be + // storing the state needed by the diffing algorithms elsewhere. + instance._mountIndex = 0; + instance._mountImage = null; + + if ("production" !== process.env.NODE_ENV) { + instance._isOwnerNecessary = false; + instance._warnedAboutRefsInRender = false; + } + + // Internal instances should fully constructed at this point, so they should + // not get any new fields added to them at this point. + if ("production" !== process.env.NODE_ENV) { + if (Object.preventExtensions) { + Object.preventExtensions(instance); + } + } + + return instance; + } + + module.exports = instantiateReactComponent; + + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(11))) + +/***/ }, +/* 91 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactCompositeComponent + */ + + 'use strict'; + + var ReactComponentEnvironment = __webpack_require__(92); + var ReactContext = __webpack_require__(20); + var ReactCurrentOwner = __webpack_require__(24); + var ReactElement = __webpack_require__(19); + var ReactElementValidator = __webpack_require__(37); + var ReactInstanceMap = __webpack_require__(43); + var ReactLifeCycle = __webpack_require__(42); + var ReactNativeComponent = __webpack_require__(40); + var ReactPerf = __webpack_require__(33); + var ReactPropTypeLocations = __webpack_require__(38); + var ReactPropTypeLocationNames = __webpack_require__(39); + var ReactReconciler = __webpack_require__(34); + var ReactUpdates = __webpack_require__(31); + + var assign = __webpack_require__(8); + var emptyObject = __webpack_require__(21); + var invariant = __webpack_require__(15); + var shouldUpdateReactComponent = __webpack_require__(93); + var warning = __webpack_require__(22); + + function getDeclarationErrorAddendum(component) { + var owner = component._currentElement._owner || null; + if (owner) { + var name = owner.getName(); + if (name) { + return ' Check the render method of `' + name + '`.'; + } + } + return ''; + } + + /** + * ------------------ The Life-Cycle of a Composite Component ------------------ + * + * - constructor: Initialization of state. The instance is now retained. + * - componentWillMount + * - render + * - [children's constructors] + * - [children's componentWillMount and render] + * - [children's componentDidMount] + * - componentDidMount + * + * Update Phases: + * - componentWillReceiveProps (only called if parent updated) + * - shouldComponentUpdate + * - componentWillUpdate + * - render + * - [children's constructors or receive props phases] + * - componentDidUpdate + * + * - componentWillUnmount + * - [children's componentWillUnmount] + * - [children destroyed] + * - (destroyed): The instance is now blank, released by React and ready for GC. + * + * ----------------------------------------------------------------------------- + */ + + /** + * An incrementing ID assigned to each component when it is mounted. This is + * used to enforce the order in which `ReactUpdates` updates dirty components. + * + * @private + */ + var nextMountID = 1; + + /** + * @lends {ReactCompositeComponent.prototype} + */ + var ReactCompositeComponentMixin = { + + /** + * Base constructor for all composite component. + * + * @param {ReactElement} element + * @final + * @internal + */ + construct: function(element) { + this._currentElement = element; + this._rootNodeID = null; + this._instance = null; + + // See ReactUpdateQueue + this._pendingElement = null; + this._pendingStateQueue = null; + this._pendingReplaceState = false; + this._pendingForceUpdate = false; + + this._renderedComponent = null; + + this._context = null; + this._mountOrder = 0; + this._isTopLevel = false; + + // See ReactUpdates and ReactUpdateQueue. + this._pendingCallbacks = null; + }, + + /** + * Initializes the component, renders markup, and registers event listeners. + * + * @param {string} rootID DOM ID of the root node. + * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction + * @return {?string} Rendered markup to be inserted into the DOM. + * @final + * @internal + */ + mountComponent: function(rootID, transaction, context) { + this._context = context; + this._mountOrder = nextMountID++; + this._rootNodeID = rootID; + + var publicProps = this._processProps(this._currentElement.props); + var publicContext = this._processContext(this._currentElement._context); + + var Component = ReactNativeComponent.getComponentClassForElement( + this._currentElement + ); + + // Initialize the public class + var inst = new Component(publicProps, publicContext); + + if ("production" !== process.env.NODE_ENV) { + // This will throw later in _renderValidatedComponent, but add an early + // warning now to help debugging + ("production" !== process.env.NODE_ENV ? warning( + inst.render != null, + '%s(...): No `render` method found on the returned component ' + + 'instance: you may have forgotten to define `render` in your ' + + 'component or you may have accidentally tried to render an element ' + + 'whose type is a function that isn\'t a React component.', + Component.displayName || Component.name || 'Component' + ) : null); + } + + // These should be set up in the constructor, but as a convenience for + // simpler class abstractions, we set them up after the fact. + inst.props = publicProps; + inst.context = publicContext; + inst.refs = emptyObject; + + this._instance = inst; + + // Store a reference from the instance back to the internal representation + ReactInstanceMap.set(inst, this); + + if ("production" !== process.env.NODE_ENV) { + this._warnIfContextsDiffer(this._currentElement._context, context); + } + + if ("production" !== process.env.NODE_ENV) { + // Since plain JS classes are defined without any special initialization + // logic, we can not catch common errors early. Therefore, we have to + // catch them here, at initialization time, instead. + ("production" !== process.env.NODE_ENV ? warning( + !inst.getInitialState || + inst.getInitialState.isReactClassApproved, + 'getInitialState was defined on %s, a plain JavaScript class. ' + + 'This is only supported for classes created using React.createClass. ' + + 'Did you mean to define a state property instead?', + this.getName() || 'a component' + ) : null); + ("production" !== process.env.NODE_ENV ? warning( + !inst.getDefaultProps || + inst.getDefaultProps.isReactClassApproved, + 'getDefaultProps was defined on %s, a plain JavaScript class. ' + + 'This is only supported for classes created using React.createClass. ' + + 'Use a static property to define defaultProps instead.', + this.getName() || 'a component' + ) : null); + ("production" !== process.env.NODE_ENV ? warning( + !inst.propTypes, + 'propTypes was defined as an instance property on %s. Use a static ' + + 'property to define propTypes instead.', + this.getName() || 'a component' + ) : null); + ("production" !== process.env.NODE_ENV ? warning( + !inst.contextTypes, + 'contextTypes was defined as an instance property on %s. Use a ' + + 'static property to define contextTypes instead.', + this.getName() || 'a component' + ) : null); + ("production" !== process.env.NODE_ENV ? warning( + typeof inst.componentShouldUpdate !== 'function', + '%s has a method called ' + + 'componentShouldUpdate(). Did you mean shouldComponentUpdate()? ' + + 'The name is phrased as a question because the function is ' + + 'expected to return a value.', + (this.getName() || 'A component') + ) : null); + } + + var initialState = inst.state; + if (initialState === undefined) { + inst.state = initialState = null; + } + ("production" !== process.env.NODE_ENV ? invariant( + typeof initialState === 'object' && !Array.isArray(initialState), + '%s.state: must be set to an object or null', + this.getName() || 'ReactCompositeComponent' + ) : invariant(typeof initialState === 'object' && !Array.isArray(initialState))); + + this._pendingStateQueue = null; + this._pendingReplaceState = false; + this._pendingForceUpdate = false; + + var childContext; + var renderedElement; + + var previouslyMounting = ReactLifeCycle.currentlyMountingInstance; + ReactLifeCycle.currentlyMountingInstance = this; + try { + if (inst.componentWillMount) { + inst.componentWillMount(); + // When mounting, calls to `setState` by `componentWillMount` will set + // `this._pendingStateQueue` without triggering a re-render. + if (this._pendingStateQueue) { + inst.state = this._processPendingState(inst.props, inst.context); + } + } + + childContext = this._getValidatedChildContext(context); + renderedElement = this._renderValidatedComponent(childContext); + } finally { + ReactLifeCycle.currentlyMountingInstance = previouslyMounting; + } + + this._renderedComponent = this._instantiateReactComponent( + renderedElement, + this._currentElement.type // The wrapping type + ); + + var markup = ReactReconciler.mountComponent( + this._renderedComponent, + rootID, + transaction, + this._mergeChildContext(context, childContext) + ); + if (inst.componentDidMount) { + transaction.getReactMountReady().enqueue(inst.componentDidMount, inst); + } + + return markup; + }, + + /** + * Releases any resources allocated by `mountComponent`. + * + * @final + * @internal + */ + unmountComponent: function() { + var inst = this._instance; + + if (inst.componentWillUnmount) { + var previouslyUnmounting = ReactLifeCycle.currentlyUnmountingInstance; + ReactLifeCycle.currentlyUnmountingInstance = this; + try { + inst.componentWillUnmount(); + } finally { + ReactLifeCycle.currentlyUnmountingInstance = previouslyUnmounting; + } + } + + ReactReconciler.unmountComponent(this._renderedComponent); + this._renderedComponent = null; + + // Reset pending fields + this._pendingStateQueue = null; + this._pendingReplaceState = false; + this._pendingForceUpdate = false; + this._pendingCallbacks = null; + this._pendingElement = null; + + // These fields do not really need to be reset since this object is no + // longer accessible. + this._context = null; + this._rootNodeID = null; + + // Delete the reference from the instance to this internal representation + // which allow the internals to be properly cleaned up even if the user + // leaks a reference to the public instance. + ReactInstanceMap.remove(inst); + + // Some existing components rely on inst.props even after they've been + // destroyed (in event handlers). + // TODO: inst.props = null; + // TODO: inst.state = null; + // TODO: inst.context = null; + }, + + /** + * Schedule a partial update to the props. Only used for internal testing. + * + * @param {object} partialProps Subset of the next props. + * @param {?function} callback Called after props are updated. + * @final + * @internal + */ + _setPropsInternal: function(partialProps, callback) { + // This is a deoptimized path. We optimize for always having an element. + // This creates an extra internal element. + var element = this._pendingElement || this._currentElement; + this._pendingElement = ReactElement.cloneAndReplaceProps( + element, + assign({}, element.props, partialProps) + ); + ReactUpdates.enqueueUpdate(this, callback); + }, + + /** + * Filters the context object to only contain keys specified in + * `contextTypes` + * + * @param {object} context + * @return {?object} + * @private + */ + _maskContext: function(context) { + var maskedContext = null; + // This really should be getting the component class for the element, + // but we know that we're not going to need it for built-ins. + if (typeof this._currentElement.type === 'string') { + return emptyObject; + } + var contextTypes = this._currentElement.type.contextTypes; + if (!contextTypes) { + return emptyObject; + } + maskedContext = {}; + for (var contextName in contextTypes) { + maskedContext[contextName] = context[contextName]; + } + return maskedContext; + }, + + /** + * Filters the context object to only contain keys specified in + * `contextTypes`, and asserts that they are valid. + * + * @param {object} context + * @return {?object} + * @private + */ + _processContext: function(context) { + var maskedContext = this._maskContext(context); + if ("production" !== process.env.NODE_ENV) { + var Component = ReactNativeComponent.getComponentClassForElement( + this._currentElement + ); + if (Component.contextTypes) { + this._checkPropTypes( + Component.contextTypes, + maskedContext, + ReactPropTypeLocations.context + ); + } + } + return maskedContext; + }, + + /** + * @param {object} currentContext + * @return {object} + * @private + */ + _getValidatedChildContext: function(currentContext) { + var inst = this._instance; + var childContext = inst.getChildContext && inst.getChildContext(); + if (childContext) { + ("production" !== process.env.NODE_ENV ? invariant( + typeof inst.constructor.childContextTypes === 'object', + '%s.getChildContext(): childContextTypes must be defined in order to ' + + 'use getChildContext().', + this.getName() || 'ReactCompositeComponent' + ) : invariant(typeof inst.constructor.childContextTypes === 'object')); + if ("production" !== process.env.NODE_ENV) { + this._checkPropTypes( + inst.constructor.childContextTypes, + childContext, + ReactPropTypeLocations.childContext + ); + } + for (var name in childContext) { + ("production" !== process.env.NODE_ENV ? invariant( + name in inst.constructor.childContextTypes, + '%s.getChildContext(): key "%s" is not defined in childContextTypes.', + this.getName() || 'ReactCompositeComponent', + name + ) : invariant(name in inst.constructor.childContextTypes)); + } + return childContext; + } + return null; + }, + + _mergeChildContext: function(currentContext, childContext) { + if (childContext) { + return assign({}, currentContext, childContext); + } + return currentContext; + }, + + /** + * Processes props by setting default values for unspecified props and + * asserting that the props are valid. Does not mutate its argument; returns + * a new props object with defaults merged in. + * + * @param {object} newProps + * @return {object} + * @private + */ + _processProps: function(newProps) { + if ("production" !== process.env.NODE_ENV) { + var Component = ReactNativeComponent.getComponentClassForElement( + this._currentElement + ); + if (Component.propTypes) { + this._checkPropTypes( + Component.propTypes, + newProps, + ReactPropTypeLocations.prop + ); + } + } + return newProps; + }, + + /** + * Assert that the props are valid + * + * @param {object} propTypes Map of prop name to a ReactPropType + * @param {object} props + * @param {string} location e.g. "prop", "context", "child context" + * @private + */ + _checkPropTypes: function(propTypes, props, location) { + // TODO: Stop validating prop types here and only use the element + // validation. + var componentName = this.getName(); + for (var propName in propTypes) { + if (propTypes.hasOwnProperty(propName)) { + var error; + try { + // This is intentionally an invariant that gets caught. It's the same + // behavior as without this statement except with a better message. + ("production" !== process.env.NODE_ENV ? invariant( + typeof propTypes[propName] === 'function', + '%s: %s type `%s` is invalid; it must be a function, usually ' + + 'from React.PropTypes.', + componentName || 'React class', + ReactPropTypeLocationNames[location], + propName + ) : invariant(typeof propTypes[propName] === 'function')); + error = propTypes[propName](props, propName, componentName, location); + } catch (ex) { + error = ex; + } + if (error instanceof Error) { + // We may want to extend this logic for similar errors in + // React.render calls, so I'm abstracting it away into + // a function to minimize refactoring in the future + var addendum = getDeclarationErrorAddendum(this); + + if (location === ReactPropTypeLocations.prop) { + // Preface gives us something to blacklist in warning module + ("production" !== process.env.NODE_ENV ? warning( + false, + 'Failed Composite propType: %s%s', + error.message, + addendum + ) : null); + } else { + ("production" !== process.env.NODE_ENV ? warning( + false, + 'Failed Context Types: %s%s', + error.message, + addendum + ) : null); + } + } + } + } + }, + + receiveComponent: function(nextElement, transaction, nextContext) { + var prevElement = this._currentElement; + var prevContext = this._context; + + this._pendingElement = null; + + this.updateComponent( + transaction, + prevElement, + nextElement, + prevContext, + nextContext + ); + }, + + /** + * If any of `_pendingElement`, `_pendingStateQueue`, or `_pendingForceUpdate` + * is set, update the component. + * + * @param {ReactReconcileTransaction} transaction + * @internal + */ + performUpdateIfNecessary: function(transaction) { + if (this._pendingElement != null) { + ReactReconciler.receiveComponent( + this, + this._pendingElement || this._currentElement, + transaction, + this._context + ); + } + + if (this._pendingStateQueue !== null || this._pendingForceUpdate) { + if ("production" !== process.env.NODE_ENV) { + ReactElementValidator.checkAndWarnForMutatedProps( + this._currentElement + ); + } + + this.updateComponent( + transaction, + this._currentElement, + this._currentElement, + this._context, + this._context + ); + } + }, + + /** + * Compare two contexts, warning if they are different + * TODO: Remove this check when owner-context is removed + */ + _warnIfContextsDiffer: function(ownerBasedContext, parentBasedContext) { + ownerBasedContext = this._maskContext(ownerBasedContext); + parentBasedContext = this._maskContext(parentBasedContext); + var parentKeys = Object.keys(parentBasedContext).sort(); + var displayName = this.getName() || 'ReactCompositeComponent'; + for (var i = 0; i < parentKeys.length; i++) { + var key = parentKeys[i]; + ("production" !== process.env.NODE_ENV ? warning( + ownerBasedContext[key] === parentBasedContext[key], + 'owner-based and parent-based contexts differ ' + + '(values: `%s` vs `%s`) for key (%s) while mounting %s ' + + '(see: http://fb.me/react-context-by-parent)', + ownerBasedContext[key], + parentBasedContext[key], + key, + displayName + ) : null); + } + }, + + /** + * Perform an update to a mounted component. The componentWillReceiveProps and + * shouldComponentUpdate methods are called, then (assuming the update isn't + * skipped) the remaining update lifecycle methods are called and the DOM + * representation is updated. + * + * By default, this implements React's rendering and reconciliation algorithm. + * Sophisticated clients may wish to override this. + * + * @param {ReactReconcileTransaction} transaction + * @param {ReactElement} prevParentElement + * @param {ReactElement} nextParentElement + * @internal + * @overridable + */ + updateComponent: function( + transaction, + prevParentElement, + nextParentElement, + prevUnmaskedContext, + nextUnmaskedContext + ) { + var inst = this._instance; + + var nextContext = inst.context; + var nextProps = inst.props; + + // Distinguish between a props update versus a simple state update + if (prevParentElement !== nextParentElement) { + nextContext = this._processContext(nextParentElement._context); + nextProps = this._processProps(nextParentElement.props); + + if ("production" !== process.env.NODE_ENV) { + if (nextUnmaskedContext != null) { + this._warnIfContextsDiffer( + nextParentElement._context, + nextUnmaskedContext + ); + } + } + + // An update here will schedule an update but immediately set + // _pendingStateQueue which will ensure that any state updates gets + // immediately reconciled instead of waiting for the next batch. + + if (inst.componentWillReceiveProps) { + inst.componentWillReceiveProps(nextProps, nextContext); + } + } + + var nextState = this._processPendingState(nextProps, nextContext); + + var shouldUpdate = + this._pendingForceUpdate || + !inst.shouldComponentUpdate || + inst.shouldComponentUpdate(nextProps, nextState, nextContext); + + if ("production" !== process.env.NODE_ENV) { + ("production" !== process.env.NODE_ENV ? warning( + typeof shouldUpdate !== 'undefined', + '%s.shouldComponentUpdate(): Returned undefined instead of a ' + + 'boolean value. Make sure to return true or false.', + this.getName() || 'ReactCompositeComponent' + ) : null); + } + + if (shouldUpdate) { + this._pendingForceUpdate = false; + // Will set `this.props`, `this.state` and `this.context`. + this._performComponentUpdate( + nextParentElement, + nextProps, + nextState, + nextContext, + transaction, + nextUnmaskedContext + ); + } else { + // If it's determined that a component should not update, we still want + // to set props and state but we shortcut the rest of the update. + this._currentElement = nextParentElement; + this._context = nextUnmaskedContext; + inst.props = nextProps; + inst.state = nextState; + inst.context = nextContext; + } + }, + + _processPendingState: function(props, context) { + var inst = this._instance; + var queue = this._pendingStateQueue; + var replace = this._pendingReplaceState; + this._pendingReplaceState = false; + this._pendingStateQueue = null; + + if (!queue) { + return inst.state; + } + + if (replace && queue.length === 1) { + return queue[0]; + } + + var nextState = assign({}, replace ? queue[0] : inst.state); + for (var i = replace ? 1 : 0; i < queue.length; i++) { + var partial = queue[i]; + assign( + nextState, + typeof partial === 'function' ? + partial.call(inst, nextState, props, context) : + partial + ); + } + + return nextState; + }, + + /** + * Merges new props and state, notifies delegate methods of update and + * performs update. + * + * @param {ReactElement} nextElement Next element + * @param {object} nextProps Next public object to set as properties. + * @param {?object} nextState Next object to set as state. + * @param {?object} nextContext Next public object to set as context. + * @param {ReactReconcileTransaction} transaction + * @param {?object} unmaskedContext + * @private + */ + _performComponentUpdate: function( + nextElement, + nextProps, + nextState, + nextContext, + transaction, + unmaskedContext + ) { + var inst = this._instance; + + var prevProps = inst.props; + var prevState = inst.state; + var prevContext = inst.context; + + if (inst.componentWillUpdate) { + inst.componentWillUpdate(nextProps, nextState, nextContext); + } + + this._currentElement = nextElement; + this._context = unmaskedContext; + inst.props = nextProps; + inst.state = nextState; + inst.context = nextContext; + + this._updateRenderedComponent(transaction, unmaskedContext); + + if (inst.componentDidUpdate) { + transaction.getReactMountReady().enqueue( + inst.componentDidUpdate.bind(inst, prevProps, prevState, prevContext), + inst + ); + } + }, + + /** + * Call the component's `render` method and update the DOM accordingly. + * + * @param {ReactReconcileTransaction} transaction + * @internal + */ + _updateRenderedComponent: function(transaction, context) { + var prevComponentInstance = this._renderedComponent; + var prevRenderedElement = prevComponentInstance._currentElement; + var childContext = this._getValidatedChildContext(); + var nextRenderedElement = this._renderValidatedComponent(childContext); + if (shouldUpdateReactComponent(prevRenderedElement, nextRenderedElement)) { + ReactReconciler.receiveComponent( + prevComponentInstance, + nextRenderedElement, + transaction, + this._mergeChildContext(context, childContext) + ); + } else { + // These two IDs are actually the same! But nothing should rely on that. + var thisID = this._rootNodeID; + var prevComponentID = prevComponentInstance._rootNodeID; + ReactReconciler.unmountComponent(prevComponentInstance); + + this._renderedComponent = this._instantiateReactComponent( + nextRenderedElement, + this._currentElement.type + ); + var nextMarkup = ReactReconciler.mountComponent( + this._renderedComponent, + thisID, + transaction, + this._mergeChildContext(context, childContext) + ); + this._replaceNodeWithMarkupByID(prevComponentID, nextMarkup); + } + }, + + /** + * @protected + */ + _replaceNodeWithMarkupByID: function(prevComponentID, nextMarkup) { + ReactComponentEnvironment.replaceNodeWithMarkupByID( + prevComponentID, + nextMarkup + ); + }, + + /** + * @protected + */ + _renderValidatedComponentWithoutOwnerOrContext: function() { + var inst = this._instance; + var renderedComponent = inst.render(); + if ("production" !== process.env.NODE_ENV) { + // We allow auto-mocks to proceed as if they're returning null. + if (typeof renderedComponent === 'undefined' && + inst.render._isMockFunction) { + // This is probably bad practice. Consider warning here and + // deprecating this convenience. + renderedComponent = null; + } + } + + return renderedComponent; + }, + + /** + * @private + */ + _renderValidatedComponent: function(childContext) { + var renderedComponent; + var previousContext = ReactContext.current; + ReactContext.current = this._mergeChildContext( + this._currentElement._context, + childContext + ); + ReactCurrentOwner.current = this; + try { + renderedComponent = + this._renderValidatedComponentWithoutOwnerOrContext(); + } finally { + ReactContext.current = previousContext; + ReactCurrentOwner.current = null; + } + ("production" !== process.env.NODE_ENV ? invariant( + // TODO: An `isValidNode` function would probably be more appropriate + renderedComponent === null || renderedComponent === false || + ReactElement.isValidElement(renderedComponent), + '%s.render(): A valid ReactComponent must be returned. You may have ' + + 'returned undefined, an array or some other invalid object.', + this.getName() || 'ReactCompositeComponent' + ) : invariant(// TODO: An `isValidNode` function would probably be more appropriate + renderedComponent === null || renderedComponent === false || + ReactElement.isValidElement(renderedComponent))); + return renderedComponent; + }, + + /** + * Lazily allocates the refs object and stores `component` as `ref`. + * + * @param {string} ref Reference name. + * @param {component} component Component to store as `ref`. + * @final + * @private + */ + attachRef: function(ref, component) { + var inst = this.getPublicInstance(); + var refs = inst.refs === emptyObject ? (inst.refs = {}) : inst.refs; + refs[ref] = component.getPublicInstance(); + }, + + /** + * Detaches a reference name. + * + * @param {string} ref Name to dereference. + * @final + * @private + */ + detachRef: function(ref) { + var refs = this.getPublicInstance().refs; + delete refs[ref]; + }, + + /** + * Get a text description of the component that can be used to identify it + * in error messages. + * @return {string} The name or null. + * @internal + */ + getName: function() { + var type = this._currentElement.type; + var constructor = this._instance && this._instance.constructor; + return ( + type.displayName || (constructor && constructor.displayName) || + type.name || (constructor && constructor.name) || + null + ); + }, + + /** + * Get the publicly accessible representation of this component - i.e. what + * is exposed by refs and returned by React.render. Can be null for stateless + * components. + * + * @return {ReactComponent} the public component instance. + * @internal + */ + getPublicInstance: function() { + return this._instance; + }, + + // Stub + _instantiateReactComponent: null + + }; + + ReactPerf.measureMethods( + ReactCompositeComponentMixin, + 'ReactCompositeComponent', + { + mountComponent: 'mountComponent', + updateComponent: 'updateComponent', + _renderValidatedComponent: '_renderValidatedComponent' + } + ); + + var ReactCompositeComponent = { + + Mixin: ReactCompositeComponentMixin + + }; + + module.exports = ReactCompositeComponent; + + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(11))) + +/***/ }, +/* 92 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2014-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactComponentEnvironment + */ + + 'use strict'; + + var invariant = __webpack_require__(15); + + var injected = false; + + var ReactComponentEnvironment = { + + /** + * Optionally injectable environment dependent cleanup hook. (server vs. + * browser etc). Example: A browser system caches DOM nodes based on component + * ID and must remove that cache entry when this instance is unmounted. + */ + unmountIDFromEnvironment: null, + + /** + * Optionally injectable hook for swapping out mount images in the middle of + * the tree. + */ + replaceNodeWithMarkupByID: null, + + /** + * Optionally injectable hook for processing a queue of child updates. Will + * later move into MultiChildComponents. + */ + processChildrenUpdates: null, + + injection: { + injectEnvironment: function(environment) { + ("production" !== process.env.NODE_ENV ? invariant( + !injected, + 'ReactCompositeComponent: injectEnvironment() can only be called once.' + ) : invariant(!injected)); + ReactComponentEnvironment.unmountIDFromEnvironment = + environment.unmountIDFromEnvironment; + ReactComponentEnvironment.replaceNodeWithMarkupByID = + environment.replaceNodeWithMarkupByID; + ReactComponentEnvironment.processChildrenUpdates = + environment.processChildrenUpdates; + injected = true; + } + } + + }; + + module.exports = ReactComponentEnvironment; + + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(11))) + +/***/ }, +/* 93 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule shouldUpdateReactComponent + * @typechecks static-only + */ + + 'use strict'; + + var warning = __webpack_require__(22); + + /** + * Given a `prevElement` and `nextElement`, determines if the existing + * instance should be updated as opposed to being destroyed or replaced by a new + * instance. Both arguments are elements. This ensures that this logic can + * operate on stateless trees without any backing instance. + * + * @param {?object} prevElement + * @param {?object} nextElement + * @return {boolean} True if the existing instance should be updated. + * @protected + */ + function shouldUpdateReactComponent(prevElement, nextElement) { + if (prevElement != null && nextElement != null) { + var prevType = typeof prevElement; + var nextType = typeof nextElement; + if (prevType === 'string' || prevType === 'number') { + return (nextType === 'string' || nextType === 'number'); + } else { + if (nextType === 'object' && + prevElement.type === nextElement.type && + prevElement.key === nextElement.key) { + var ownersMatch = prevElement._owner === nextElement._owner; + var prevName = null; + var nextName = null; + var nextDisplayName = null; + if ("production" !== process.env.NODE_ENV) { + if (!ownersMatch) { + if (prevElement._owner != null && + prevElement._owner.getPublicInstance() != null && + prevElement._owner.getPublicInstance().constructor != null) { + prevName = + prevElement._owner.getPublicInstance().constructor.displayName; + } + if (nextElement._owner != null && + nextElement._owner.getPublicInstance() != null && + nextElement._owner.getPublicInstance().constructor != null) { + nextName = + nextElement._owner.getPublicInstance().constructor.displayName; + } + if (nextElement.type != null && + nextElement.type.displayName != null) { + nextDisplayName = nextElement.type.displayName; + } + if (nextElement.type != null && typeof nextElement.type === 'string') { + nextDisplayName = nextElement.type; + } + if (typeof nextElement.type !== 'string' || + nextElement.type === 'input' || + nextElement.type === 'textarea') { + if ((prevElement._owner != null && + prevElement._owner._isOwnerNecessary === false) || + (nextElement._owner != null && + nextElement._owner._isOwnerNecessary === false)) { + if (prevElement._owner != null) { + prevElement._owner._isOwnerNecessary = true; + } + if (nextElement._owner != null) { + nextElement._owner._isOwnerNecessary = true; + } + ("production" !== process.env.NODE_ENV ? warning( + false, + '<%s /> is being rendered by both %s and %s using the same ' + + 'key (%s) in the same place. Currently, this means that ' + + 'they don\'t preserve state. This behavior should be very ' + + 'rare so we\'re considering deprecating it. Please contact ' + + 'the React team and explain your use case so that we can ' + + 'take that into consideration.', + nextDisplayName || 'Unknown Component', + prevName || '[Unknown]', + nextName || '[Unknown]', + prevElement.key + ) : null); + } + } + } + } + return ownersMatch; + } + } + } + return false; + } + + module.exports = shouldUpdateReactComponent; + + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(11))) + +/***/ }, +/* 94 */ +/***/ function(module, exports, __webpack_require__) { + + /* WEBPACK VAR INJECTION */(function(process) {/** + * Copyright 2013-2015, Facebook, Inc. + * All rights reserved. + * + * This source code is licensed under the BSD-style license found in the + * LICENSE file in the root directory of this source tree. An additional grant + * of patent rights can be found in the PATENTS file in the same directory. + * + * @providesModule ReactDOMComponent + * @typechecks static-only + */ + + /* global hasOwnProperty:true */ + + 'use strict'; + + var CSSPropertyOperations = __webpack_require__(56); + var DOMProperty = __webpack_require__(51); + var DOMPropertyOperations = __webpack_require__(50); + var ReactBrowserEventEmitter = __webpack_require__(75); + var ReactComponentBrowserEnvironment = + __webpack_require__(54); + var ReactMount = __webpack_require__(74); + var ReactMultiChild = __webpack_require__(95); + var ReactPerf = __webpack_require__(33); + + var assign = __webpack_require__(8); + var escapeTextContentForBrowser = __webpack_require__(53); + var invariant = __webpack_require__(15); + var isEventSupported = __webpack_require__(82); + var keyOf = __webpack_require__(46); + var warning = __webpack_require__(22); + + var deleteListener = ReactBrowserEventEmitter.deleteListener; + var listenTo = ReactBrowserEventEmitter.listenTo; + var registrationNameModules = ReactBrowserEventEmitter.registrationNameModules; + + // For quickly matching children type, to test if can be treated as content. + var CONTENT_TYPES = {'string': true, 'number': true}; + + var STYLE = keyOf({style: null}); + + var ELEMENT_NODE_TYPE = 1; + + /** + * Optionally injectable operations for mutating the DOM + */ + var BackendIDOperations = null; + + /** + * @param {?object} props + */ + function assertValidProps(props) { + if (!props) { + return; + } + // Note the use of `==` which checks for null or undefined. + if (props.dangerouslySetInnerHTML != null) { + ("production" !== process.env.NODE_ENV ? invariant( + props.children == null, + 'Can only set one of `children` or `props.dangerouslySetInnerHTML`.' + ) : invariant(props.children == null)); + ("production" !== process.env.NODE_ENV ? invariant( + typeof props.dangerouslySetInnerHTML === 'object' && + '__html' in props.dangerouslySetInnerHTML, + '`props.dangerouslySetInnerHTML` must be in the form `{__html: ...}`. ' + + 'Please visit https://fb.me/react-invariant-dangerously-set-inner-html ' + + 'for more information.' + ) : invariant(typeof props.dangerouslySetInnerHTML === 'object' && + '__html' in props.dangerouslySetInnerHTML)); + } + if ("production" !== process.env.NODE_ENV) { + ("production" !== process.env.NODE_ENV ? warning( + props.innerHTML == null, + 'Directly setting property `innerHTML` is not permitted. ' + + 'For more information, lookup documentation on `dangerouslySetInnerHTML`.' + ) : null); + ("production" !== process.env.NODE_ENV ? warning( + !props.contentEditable || props.children == null, + 'A component is `contentEditable` and contains `children` managed by ' + + 'React. It is now your responsibility to guarantee that none of ' + + 'those nodes are unexpectedly modified or duplicated. This is ' + + 'probably not intentional.' + ) : null); + } + ("production" !== process.env.NODE_ENV ? invariant( + props.style == null || typeof props.style === 'object', + 'The `style` prop expects a mapping from style properties to values, ' + + 'not a string. For example, style={{marginRight: spacing + \'em\'}} when ' + + 'using JSX.' + ) : invariant(props.style == null || typeof props.style === 'object')); + } + + function putListener(id, registrationName, listener, transaction) { + if ("production" !== process.env.NODE_ENV) { + // IE8 has no API for event capturing and the `onScroll` event doesn't + // bubble. + ("production" !== process.env.NODE_ENV ? warning( + registrationName !== 'onScroll' || isEventSupported('scroll', true), + 'This browser doesn\'t support the `onScroll` event' + ) : null); + } + var container = ReactMount.findReactContainerForID(id); + if (container) { + var doc = container.nodeType === ELEMENT_NODE_TYPE ? + container.ownerDocument : + container; + listenTo(registrationName, doc); + } + transaction.getPutListenerQueue().enqueuePutListener( + id, + registrationName, + listener + ); + } + + // For HTML, certain tags should omit their close tag. We keep a whitelist for + // those special cased tags. + + var omittedCloseTags = { + 'area': true, + 'base': true, + 'br': true, + 'col': true, + 'embed': true, + 'hr': true, + 'img': true, + 'input': true, + 'keygen': true, + 'link': true, + 'meta': true, + 'param': true, + 'source': true, + 'track': true, + 'wbr': true + // NOTE: menuitem's close tag should be omitted, but that causes problems. + }; + + // We accept any tag to be rendered but since this gets injected into abitrary + // HTML, we want to make sure that it's a safe tag. + // http://www.w3.org/TR/REC-xml/#NT-Name + + var VALID_TAG_REGEX = /^[a-zA-Z][a-zA-Z:_\.\-\d]*$/; // Simplified subset + var validatedTagCache = {}; + var hasOwnProperty = {}.hasOwnProperty; + + function validateDangerousTag(tag) { + if (!hasOwnProperty.call(validatedTagCache, tag)) { + ("production" !== process.env.NODE_ENV ? invariant(VALID_TAG_REGEX.test(tag), 'Invalid tag: %s', tag) : invariant(VALID_TAG_REGEX.test(tag))); + validatedTagCache[tag] = true; + } + } + + /** + * Creates a new React class that is idempotent and capable of containing other + * React components. It accepts event listeners and DOM properties that are + * valid according to `DOMProperty`. + * + * - Event listeners: `onClick`, `onMouseDown`, etc. + * - DOM properties: `className`, `name`, `title`, etc. + * + * The `style` property functions differently from the DOM API. It accepts an + * object mapping of style properties to values. + * + * @constructor ReactDOMComponent + * @extends ReactMultiChild + */ + function ReactDOMComponent(tag) { + validateDangerousTag(tag); + this._tag = tag; + this._renderedChildren = null; + this._previousStyleCopy = null; + this._rootNodeID = null; + } + + ReactDOMComponent.displayName = 'ReactDOMComponent'; + + ReactDOMComponent.Mixin = { + + construct: function(element) { + this._currentElement = element; + }, + + /** + * Generates root tag markup then recurses. This method has side effects and + * is not idempotent. + * + * @internal + * @param {string} rootID The root DOM ID for this node. + * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction + * @return {string} The computed markup. + */ + mountComponent: function(rootID, transaction, context) { + this._rootNodeID = rootID; + assertValidProps(this._currentElement.props); + var closeTag = omittedCloseTags[this._tag] ? '' : ''; + return ( + this._createOpenTagMarkupAndPutListeners(transaction) + + this._createContentMarkup(transaction, context) + + closeTag + ); + }, + + /** + * Creates markup for the open tag and all attributes. + * + * This method has side effects because events get registered. + * + * Iterating over object properties is faster than iterating over arrays. + * @see http://jsperf.com/obj-vs-arr-iteration + * + * @private + * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction + * @return {string} Markup of opening tag. + */ + _createOpenTagMarkupAndPutListeners: function(transaction) { + var props = this._currentElement.props; + var ret = '<' + this._tag; + + for (var propKey in props) { + if (!props.hasOwnProperty(propKey)) { + continue; + } + var propValue = props[propKey]; + if (propValue == null) { + continue; + } + if (registrationNameModules.hasOwnProperty(propKey)) { + putListener(this._rootNodeID, propKey, propValue, transaction); + } else { + if (propKey === STYLE) { + if (propValue) { + propValue = this._previousStyleCopy = assign({}, props.style); + } + propValue = CSSPropertyOperations.createMarkupForStyles(propValue); + } + var markup = + DOMPropertyOperations.createMarkupForProperty(propKey, propValue); + if (markup) { + ret += ' ' + markup; + } + } + } + + // For static pages, no need to put React ID and checksum. Saves lots of + // bytes. + if (transaction.renderToStaticMarkup) { + return ret + '>'; + } + + var markupForID = DOMPropertyOperations.createMarkupForID(this._rootNodeID); + return ret + ' ' + markupForID + '>'; + }, + + /** + * Creates markup for the content between the tags. + * + * @private + * @param {ReactReconcileTransaction|ReactServerRenderingTransaction} transaction + * @param {object} context + * @return {string} Content markup. + */ + _createContentMarkup: function(transaction, context) { + var prefix = ''; + if (this._tag === 'listing' || + this._tag === 'pre' || + this._tag === 'textarea') { + // Add an initial newline because browsers ignore the first newline in + // a

,
, or