diff --git a/app.js b/app.js new file mode 100644 index 0000000..f5d4a3b --- /dev/null +++ b/app.js @@ -0,0 +1,124 @@ +/*jslint node:true */ +/*jslint nomen:true */ +'use strict'; +// form npm +var express = require('express'); +var path = require('path'); +var favicon = require('serve-favicon'); +var logger = require('morgan'); +var cookieParser = require('cookie-parser'); +var bodyParser = require('body-parser'); +var passport = require('passport'); +var session = require('express-session'); +var i18n = require("i18n"); +var flash = require("connect-flash"); + +// from freesun +// process service +var ps = require('./freesun/services/processservice'); +// system service +var ss = require('./freesun/services/systemservice'); +// tail service +var ts = require('./freesun/services/tailfileservice'); +// tail service +var us = require('./freesun/services/updateservice'); +// config +var config = require('./freesun/env/config'); +// routes +var home = require('./routes/index'); +var login = require('./routes/login'); +var proj = require('./routes/project'); +var proc = require('./routes/process'); +var webr = require('./routes/webserver'); +var upld = require('./routes/upload'); +var upgrade = require('./routes/upgrade'); + +var app = express(); + +i18n.configure({ + locales: ['zh_CN', 'en'], + directory: __dirname + '/locales' +}); + +// view engine setup +app.set('views', path.join(__dirname, 'views')); +app.set('view engine', 'jade'); +app.engine('html', require('jade').__express); + +app.use(favicon(path.join(__dirname, 'static', 'favicon.ico'))); +app.use(logger('dev')); +app.use(bodyParser.json()); +app.use(bodyParser.urlencoded({extended: false})); +app.use(cookieParser()); +app.use(express.static(path.join(__dirname, 'static'))); +app.use(session({ + secret: 'axNurse', + resave: true, + saveUninitialized: true +})); +app.use(i18n.init); + + +if (config.auth.enable) { + app.use(passport.initialize()); + app.use(passport.session()); + app.use(flash()); + + var initPassport = require('./freesun/passport/init'); + initPassport(passport); +} +// start service +ps.start(); +ss.start(); +ts.start(); +us.start(); +//put it +app.set('fs.update.service', us); + +setInterval(function () { + if (global.gc) { + global.gc(); + } +}, 5000); + +// routes +app.use('/', home); +app.use('/login', login); +app.use('/project', proj); +app.use('/process', proc); +app.use('/webserver', webr); +app.use('/upload', upld); +app.use('/upgrade', upgrade); + +// catch 404 and forward to error handler +app.use(function (req, res, next) { + var err = new Error('Not Found'); + err.status = 404; + next(err); +}); + +// error handlers + +// development error handler +// will print stacktrace +if (app.get('env') === 'development') { + app.use(function (err, req, res, next) { + res.status(err.status || 500); + res.render('error', { + message: err.message, + error: err + }); + }); +} + +// production error handler +// no stacktraces leaked to user +app.use(function (err, req, res, next) { + res.status(err.status || 500); + res.render('error', { + message: err.message, + error: {} + }); +}); + +module.exports = app; diff --git a/bin/json.js b/bin/json.js new file mode 100644 index 0000000..4dc1861 --- /dev/null +++ b/bin/json.js @@ -0,0 +1,6 @@ +var Flow = require('..\\freesun\\temp\\install').Flow; +var Flows = require('..\\freesun\\temp\\update').Flow; +console.log(Flows); + +var xx = new Flows(); +console.log(Flows); \ No newline at end of file diff --git a/bin/test.js b/bin/test.js new file mode 100644 index 0000000..fd3d52d --- /dev/null +++ b/bin/test.js @@ -0,0 +1,11 @@ +/** + * Created by rain on 2015/8/27. + */ + +var us = require('../freesun/services/updateservice'); +var fs = require('graceful-fs'); +fs.lstat('D:\\svn\\FS-axNurse-svn\\trunk\\code\\runtime\\app/Server/NGETService', function (err, stats) { + console.log(err); +}); + +us.run(0, 'D:\\svn\\FS-axNurse-svn\\trunk\\code\\uploads\\upload_b5bc7a664fb4818990709d8cc007dd96.zip'); \ No newline at end of file diff --git a/bin/www b/bin/www new file mode 100644 index 0000000..cf81bdb --- /dev/null +++ b/bin/www @@ -0,0 +1,92 @@ +#!/usr/bin/env node + +/** + * Module dependencies. + */ +/*jslint node:true */ +'use strict'; + +var app = require('../app'); +var debug = require('debug')('axnurse:server'); +var http = require('http'); + +/** + * Get port from environment and store in Express. + */ + +var port = normalizePort(process.env.PORT || '3000'); +app.set('port', port); + +/** + * Create HTTP server. + */ + +var server = http.createServer(app); + +/** + * Listen on provided port, on all network interfaces. + */ + +server.listen(port); +server.on('error', onError); +server.on('listening', onListening); + +/** + * Normalize a port into a number, string, or false. + */ + +function normalizePort(val) { + var port = parseInt(val, 10); + + if (isNaN(port)) { + // named pipe + return val; + } + + if (port >= 0) { + // port number + return port; + } + + return false; +} + +/** + * Event listener for HTTP server "error" event. + */ + +function onError(error) { + if (error.syscall !== 'listen') { + throw error; + } + + var bind = typeof port === 'string' + ? 'Pipe ' + port + : 'Port ' + port; + + // handle specific listen errors with friendly messages + switch (error.code) { + case 'EACCES': + console.error(bind + ' requires elevated privileges'); + process.exit(1); + break; + case 'EADDRINUSE': + console.error(bind + ' is already in use'); + process.exit(1); + break; + default: + throw error; + } +} + +/** + * Event listener for HTTP server "listening" event. + */ + +function onListening() { + var addr = server.address(); + var bind = typeof addr === 'string' + ? 'pipe ' + addr + : 'port ' + addr.port; + debug('Listening on ' + bind); +} diff --git a/build-package.txt b/build-package.txt new file mode 100644 index 0000000..cd5b2a8 --- /dev/null +++ b/build-package.txt @@ -0,0 +1,10 @@ +style-loader +css-loader +jsx-loader +react +react-router +react-dropzone +superagent +sweetalert +q +ws \ No newline at end of file diff --git a/freesun/env/config.js b/freesun/env/config.js new file mode 100644 index 0000000..b36b302 --- /dev/null +++ b/freesun/env/config.js @@ -0,0 +1,26 @@ +/** + * Created by rain on 2015/8/5. + */ +/*jslint node:true */ +'use strict'; + +var config = { + auth: { + enable: true + }, + ws: { + process: 8100, + processInterval: 1000, + system: 8300, + systemInterval: 1000, + tail: 8200, + update: 8400, + backupClearInterval: 1000 * 60 * 60 * 24 + }, + debug: true, + project: { + watch: false + } +}; + +module.exports = config; diff --git a/freesun/env/logger.js b/freesun/env/logger.js new file mode 100644 index 0000000..fddae35 --- /dev/null +++ b/freesun/env/logger.js @@ -0,0 +1,22 @@ +/** + * Created by rain on 2015/8/15. + */ +/*jslint node:true */ +/*jslint nomen:true */ +'use strict'; +var winston = require('winston'); +var path = require('path'); + +var logger = new (winston.Logger)({ + transports: [ + new (winston.transports.Console)({ + colorize: 'all' + }), + new (winston.transports.File)({ + filename: path.join(__dirname, '../axNurse.log') + }) + ], + exitOnError: false +}); + +module.exports = logger; \ No newline at end of file diff --git a/freesun/models/process.js b/freesun/models/process.js new file mode 100644 index 0000000..c806f1b --- /dev/null +++ b/freesun/models/process.js @@ -0,0 +1,203 @@ +/** + * Created by rain on 2015/8/7. + */ +/*jslint node:true */ +/*jslint nomen:true */ +'use strict'; +var fs = require('fs'); +var os = require('os'); +var Q = require('q'); +var exec = require('child_process').exec; +var moment = require('moment'); +var ustring = require('underscore.string'); + +var wmic = require('../tools/wmic'); +var psget = wmic.path.get; +var psdetailget = wmic.path.get; + +var logger = require('../env/logger'); + +function Process(process) { + this.id = process.id; + this.name = process.name; + this.image = process.image; + this.path = process.path; + this.watch = process.watch; + this.logfile = process.logfile; + this.project = process.project; + //this.absPath = project.workspace.processDir + path + image + this.absPath = process.absPath; + //this.absDir = project.workspace.processDir + path + this.absDir = process.absDir; + //this.r = []; +} + +function ProcessInfo(info) { + this.spid = info.spid; + this.pid = info.pid; + this.status = info.status; + this.restart = info.restart; + this.memory = info.memory; + this.mempec = info.mempec; + this.uptime = info.uptime; + this.cpupec = info.cpupec; +} + +Process.prototype.runtimeInfo = function () { + return Process.getRuntimeInfo([this]); +}; + +Process.prototype.toggle = function (cmd, refresh) { + var deferred = Q.defer(), + promise, + info, + that = this; + if (refresh || !this.r) { + promise = this.runtimeInfo(); + } else { + promise = Q(); + } + promise.then(function () { + info = that.r[0]; + if (cmd === 1) { + if (info.status !== 0) { + deferred.resolve(ustring.sprintf('Process %s is running.', that.name)); + } else if (!fs.existsSync(that.absPath)) { + console.log(that.absPath); + deferred.reject(ustring.sprintf('Process %s not exist.', that.name)); + } else { + exec("start " + that.image, {cwd: that.absDir}, function (err) { + if (err !== null) { + logger.error(err); + deferred.reject(ustring.sprintf('Fail to start process %s.', that.name)); + } + }); + deferred.resolve(ustring.sprintf('Success to start process %s.', that.name)); + } + } else if (cmd === 0) { + if (info.status === 0) { + deferred.resolve(ustring.sprintf('Process %s is not running.', that.name)); + } else { + exec("taskkill /PID " + info.pid + " /T /F", function (err) { + if (err !== null) { + deferred.reject(err); + } else { + deferred.resolve(ustring.sprintf('Success to stop process %s.', that.name)); + } + }); + } + } else { + deferred.reject('Invalid operation.'); + } + }, function (err) { + deferred.reject(err); + }); + + return deferred.promise; +}; + +Process.getRuntimeInfo = function (allProcesses) { + var count, + infos = [], + now, + i, + proc, + pid, + mem, + rawDate, + startDate, + procDetail, + processes, + procDetails, + processWhere, + detailWhere, + deferred = Q.defer(); + try { + count = allProcesses.length; + processWhere = 'where "( '; + for (i = 0; i < count; i = i + 1) { + var currentProcess = allProcesses[i]; + currentProcess.r = [{status: 0}]; + processWhere += ' (name' + '=' + " '" + currentProcess.image + "'" + " AND " + 'ExecutablePath' + '=' + " '" + currentProcess.absPath.replace(/\\/g, '\\\\') + "') "; + processWhere += i < count - 1 ? ' OR ' : ''; + } + processWhere += ' )" '; + psget('Win32_Process', processWhere, function (err, psinfo) { + if (err) { + //这种情况是: 无可用的实例 认为进程未运行... + deferred.resolve(); + //deferred.resolve(err); + return; + } + processes = psinfo; + processes = processes.filter(function (v, i, arr) { + return v.Name !== undefined; + }); + count = processes.length; + if (count > 0) { + detailWhere = 'where "( '; + for (i = 0; i < count; i = i + 1) { + detailWhere += ' (IDProcess' + '=' + " '" + processes[i].ProcessId + "') "; + detailWhere += i < count - 1 ? ' OR ' : ''; + } + detailWhere += ' )" '; + psdetailget('Win32_PerfFormattedData_PerfProc_Process', detailWhere, function (err, psdetailInfo) { + if (err) { + deferred.reject(err); + return; + } + procDetails = psdetailInfo; + now = Date.now(); + for (i = 0; i < count; i = i + 1) { + infos = []; + proc = processes[i]; + //proc.ExecutablePath = (new Iconv('GB2312', 'UTF-8')).convert(proc.ExecutablePath).toString(); + pid = proc.ProcessId; + mem = proc.WorkingSetSize; + rawDate = proc.CreationDate; //20150810140302.571036+480 + startDate = moment(rawDate.substring(0, rawDate.indexOf('.')), "YYYYMMDDHHmmss").toDate(); + procDetail = procDetails.filter(function (v, i, arr) { + return v.IDProcess === pid; + })[0]; + if (procDetail) { + infos.push(new ProcessInfo( + { + pid: pid, + status: 1, + //restart: safeutf8(proc, 'ProcessId'), + memory: Number(mem / 1024).toFixed(2), + mempec: Number(100 * (mem / os.totalmem())).toFixed(2), + uptime: now - startDate, + cpupec: procDetail.PercentProcessorTime + } + )); + var matchRows = allProcesses.filter(function (v, i, arr) { + return v.image === proc.Name && v.absPath.toUpperCase() === proc.ExecutablePath.toUpperCase(); + }); + if (matchRows) { + matchRows.forEach(function (v) { + v.r = infos; + }); + } else { + logger.error("Fail to get process error, reason: %s", proc.ExecutablePath); + } + } + } + deferred.resolve(); + }); + } else { + deferred.resolve(); + } + }); + } catch (e) { + logger.error("Get process error, reason: %s", e.stack); + deferred.reject(e); + } + return deferred.promise; +}; + +Process.prototype.isRunning = function () { + return this.r && this.r[0] && this.r[0].status === 1; +}; + +module.exports = Process; \ No newline at end of file diff --git a/freesun/models/project.js b/freesun/models/project.js new file mode 100644 index 0000000..d9901d4 --- /dev/null +++ b/freesun/models/project.js @@ -0,0 +1,331 @@ +/** + * Created by rain on 2015/8/25. + */ +/*jslint node:true */ +/*jslint nomen:true */ +/*jslint stupid:true */ +'use strict'; +var path = require('path'); +var Q = require('q'); +var fs = require('fs-extra'); +var ustring = require('underscore.string'); +var uuid = require('node-uuid'); + +var Process = require('./process'); +var WebServer = require('./webserver'); +var logger = require('../env/logger'); +var config = require('../env/config'); + +function Project(project) { + this.name = project.name; + this.updatable = project.updatable; + this.process = []; + this.webserver = []; + //this.id = 0; +} + +Project.projectDir = path.join(__dirname, '..\\projects'); +Project.deletedDir = path.join(__dirname, '..\\projects\\deleted'); + +Project.prototype.addProcess = function (process) { + this.process.push(process); +}; + +Project.prototype.addWebServer = function (web) { + this.webserver.push(web); +}; + +Project.prototype.findProcess = function (id) { + return this.process[id]; +}; + +Project.prototype.findWeb = function (id) { + return this.webserver[id]; +}; + +Project.allProjects = undefined; +Project.enableWatching = config.project.watch; +Project.lastState = config.project.watch; + +Project.findById = function (pjid, config) { + var all = Project.all(config), + proj = null; + try { + proj = all[pjid]; + } catch (e) { + logger.error('Fail to find project by id[%d], reason: %s.', pjid, e.stack); + } + return proj; +}; + +Project.deleteById = function (pjid, config) { + var all = Project.all(config), + result = false, + now = new Date(), + fileRename; + try { + delete all[pjid]; + fileRename = ustring.sprintf('%s.%s-%s-%s %s-%s-%s.js', pjid, now.getFullYear(), now.getMonth() + 1, + now.getDate(), now.getHours(), now.getMinutes(), now.getSeconds()); + fs.renameSync(path.join(Project.projectDir, pjid + '.js'), path.join(Project.deletedDir, fileRename)); + result = true; + } catch (e) { + logger.error('Fail to delete project by id[%d], reason: %s.', pjid, e.stack); + } + return result; +}; + +Project.findProcessById = function (pjid, pid, config) { + var all = Project.all(config), + //projs = all.filter(function (pj) { + // return pj.id === pjid; + //}), + //proj, + //procs, + proc = null; + //if (projs.length > 0) { + // proj = projs[0]; + // procs = proj.process.filter(function (pr) { + // return pr.id === pid; + // }); + // if (projs.length > 0) { + // proc = procs[0]; + // } + //} + try { + proc = all[pjid].process[pid]; + } catch (e) { + logger.error('Fail to find process by id[%d-%d], reason: %s.', pjid, pid, e.stack); + } + return proc; +}; + +Project.findWebServerById = function (pjid, pid, config) { + var all = Project.all(config), + site = null; + try { + site = all[pjid].webserver[pid]; + } catch (e) { + logger.error('Fail to find web server by id[%d-%d], reason: %s.', pjid, pid, e.stack); + } + return site; +}; + +Project.loadConfig = function () { + var loaded = [], + projectFiles = fs.readdirSync(path.join(__dirname, '..\\projects')); + if (Array.isArray(projectFiles)) { + projectFiles.forEach(function (v, i) { + if (path.extname(v) === '.js') { + try { + var proj = require(path.join(__dirname, '..\\projects', v)).project; + proj.id = path.basename(v, '.js'); + loaded.push(proj); + } catch (e) { + logger.error('Fail to load project form %s. reason: %s', v, e.stack); + } + } + }); + } + return loaded; +}; + +Project.makeProject = function (option, id) { + var pj = new Project(option); + pj.id = id; + Object.defineProperty(pj, "workspace", { + value: option.workspace, + writable: true, + enumerable: false, + configurable: true + }); + Object.defineProperty(pj, "sqlCmd", { + value: option.sqlCmd, + writable: true, + enumerable: false, + configurable: true + }); + if (Array.isArray(option.process)) { + option.process.forEach(function (pv, j) { + var proc = new Process(pv); + proc.id = j; + Object.defineProperty(proc, "project", { + value: pj, + writable: true, + enumerable: false, + configurable: true + }); + Object.defineProperty(proc, "absDir", { + value: path.join(option.workspace.processDir, proc.path), + writable: true, + enumerable: false, + configurable: true + }); + Object.defineProperty(proc, "absPath", { + value: path.join(proc.absDir, proc.image), + writable: true, + enumerable: false, + configurable: true + }); + Object.defineProperty(proc, "config", { + value: pv.config, + writable: true, + enumerable: false, + configurable: true + }); + Object.defineProperty(proc, "copy", { + value: pv.copy, + writable: true, + enumerable: false, + configurable: true + }); + if (proc.logfile) { + proc.logfile = path.join(proc.absDir, proc.logfile); + } + pj.addProcess(proc); + }); + } + if (Array.isArray(option.webserver)) { + option.webserver.forEach(function (w, j) { + var web = new WebServer(w); + web.id = j; + Object.defineProperty(web, "project", { + value: pj, + writable: true, + enumerable: false, + configurable: true + }); + //web.absPath = path.join(v.workspace.processDir, web.path); + Object.defineProperty(web, "absPath", { + value: path.join(option.workspace.webDir, web.path), + writable: true, + enumerable: false, + configurable: true + }); + Object.defineProperty(web, "absDir", { + value: web.absPath, + writable: true, + enumerable: false, + configurable: true + }); + Object.defineProperty(web, "config", { + value: w.config, + writable: true, + enumerable: false, + configurable: true + }); + Object.defineProperty(web, "copy", { + value: w.copy, + writable: true, + enumerable: false, + configurable: true + }); + pj.addWebServer(web); + }); + } + return pj; +}; + +Project.getId = function (config) { + var arr = Project.all(config), + id = 0; + while (arr[id.toString()]) { + id = id + 1; + } + return id.toString(); +}; + +Project.all = function (config) { + if (Project.allProjects) { + return Project.allProjects; + } + var projects = config || Project.loadConfig(), + all = [], + pj, + id; + if (Array.isArray(projects)) { + projects.forEach(function (v, i) { + if (v.id) { + id = v.id.toString(); + } else { + id = Project.getId().toString(); + } + pj = Project.makeProject(v, id); + all[id] = pj; + }); + Project.allProjects = all; + } + return Project.allProjects; +}; + +Project.allWithRuntimeInfo = function (config) { + var allProject = Project.all(config), + deferred = Q.defer(), + allWebServers = [], + allProcesses = []; + allProject.forEach(function (pj) { + allProcesses = allProcesses.concat(pj.process); + allWebServers = allWebServers.concat(pj.webserver); + }); + Process.getRuntimeInfo(allProcesses) + .then(function () { + return allWebServers.reduce(function (prev, next) { + return next.refresh(); + }, Q()); + }).then(function () { + if (Project.watch()) { + return allProcesses.reduce(function (prev, next) { + if (!next.watch || next.isRunning()) { + return Q(); + } + //ignore, multi project with same path, multi process will be started. + return next.toggle(1, false); + }, allWebServers.reduce(function (prev, next) { + if (!next.watch || next.isRunning()) { + return Q(); + } + return next.toggle(1, false); + }, Q())); + } + return Q(); + }) + .then(function () { + deferred.resolve(allProject); + }, function (err) { + deferred.reject(err); + }); + return deferred.promise; +}; + +Project.addProject = function (proj) { + Project.all()[proj.id] = proj; +}; + +Project.stopWatching = function () { + Project.enableWatching = false; + Project.lastState = false; +}; + +Project.startWatching = function () { + Project.enableWatching = true; + Project.lastState = true; +}; + +Project.watchSwitch = function () { + Project.enableWatching = !Project.enableWatching; + Project.lastState = Project.enableWatching; +}; + +Project.pauseWatching = function () { + Project.enableWatching = false; +}; + +Project.resumeWatching = function () { + Project.enableWatching = Project.lastState; +}; + +Project.watch = function () { + return Project.enableWatching && config.project.watch; +}; + +module.exports = Project; \ No newline at end of file diff --git a/freesun/models/user.js b/freesun/models/user.js new file mode 100644 index 0000000..80adf46 --- /dev/null +++ b/freesun/models/user.js @@ -0,0 +1,43 @@ +/** + * Created by rain on 2015/8/5. + */ +/*jslint node:true */ +/*jslint nomen:true */ +/*jslint stupid:true */ +'use strict'; +var bcrypt = require('bcrypt-nodejs'); +var Users = [{ + id: 0, + username: "admin", + password: bcrypt.hashSync('axNurse') +}]; + +function User(user) { + this.id = user.id; + this.username = user.username; + this.password = user.password; +} + +User.find = function (username, callback) { + var found = Users.filter(function (v) { + return v.username === username; + }); + if (found) { + callback(null, found[0]); + } else { + callback("User does not exist."); + } +}; + +User.findById = function (id, callback) { + var found = Users.filter(function (v) { + return v.id === id; + }); + if (found) { + callback(null, found[0]); + } else { + callback("User does not exist."); + } +}; + +module.exports = User; \ No newline at end of file diff --git a/freesun/models/webserver.js b/freesun/models/webserver.js new file mode 100644 index 0000000..082aee7 --- /dev/null +++ b/freesun/models/webserver.js @@ -0,0 +1,75 @@ +/** + * Created by rain on 2015/8/26. + */ + +/*jslint node:true */ +/*jslint nomen:true */ +'use strict'; +var fs = require('fs'); +var os = require('os'); +var Q = require('q'); +var exec = require('child_process').exec; + +var logger = require('../env/logger'); +var iis = require('../tools/iis'); + +function WebServer(web) { + this.id = web.id; + this.name = web.name; + this.protocol = web.protocol; + this.port = web.port; + this.host = web.host; + this.path = web.path; + this.watch = web.watch; + this.absPath = web.absPath; + this.absDir = web.absDir; + this.pool = web.pool; + this.refresh(); +} + +WebServer.prototype.refresh = function () { + var self = this, + derfered = Q.defer(); + ((Q.nbind(iis.getInfo, iis))('site', self.name)) + .then(function (info) { + self.status = info === null ? null : info.state; + derfered.resolve(); + }, function (err) { + logger.error(err); + self.status = null; + derfered.resolve(); + }); + return derfered.promise; +}; + +WebServer.prototype.isRunning = function () { + return this.status === 'Started'; +}; + +WebServer.prototype.toggle = function (cmd, refresh) { + var self = this, + derfered = Q.defer(), + start, + func; + if (refresh) { + start = this.refresh; + } else { + start = Q(); + } + if (cmd === 1) { + func = iis.startSite; + } else { + func = iis.stopSite; + } + start.then(function () { + ((Q.nbind(func, iis))(self)) + .then(function () { + derfered.resolve(); + }, function (err) { + derfered.reject(err); + }); + }); + return derfered.promise; +}; + +module.exports = WebServer; \ No newline at end of file diff --git a/freesun/passport/init.js b/freesun/passport/init.js new file mode 100644 index 0000000..57f4c7b --- /dev/null +++ b/freesun/passport/init.js @@ -0,0 +1,23 @@ +/** + * Created by rain on 2015/8/6. + */ +/*jslint node:true */ +/*jslint nomen:true */ +'use strict'; +var login = require('./login'); +var User = require('../models/user'); + +module.exports = function (passport) { + + passport.serializeUser(function (user, done) { + done(null, user.id); + }); + + passport.deserializeUser(function (id, done) { + User.findById(id, function (err, user) { + done(err, user); + }); + }); + + login(passport); +}; \ No newline at end of file diff --git a/freesun/passport/login.js b/freesun/passport/login.js new file mode 100644 index 0000000..15f78ac --- /dev/null +++ b/freesun/passport/login.js @@ -0,0 +1,33 @@ +/** + * Created by rain on 2015/8/6. + */ +/*jslint node:true */ +/*jslint nomen:true */ +/*jslint stupid:true */ +'use strict'; +var LocalStrategy = require('passport-local').Strategy; +var User = require('../models/user'); +var bcrypt = require('bcrypt-nodejs'); + +module.exports = function (passport) { + var isValidPassword = function (user, password) { + return bcrypt.compareSync(password, user.password); + }; + + passport.use('login', new LocalStrategy({ + passReqToCallback: true + }, function (req, username, password, done) { + User.find(username, function (err, user) { + if (err) { + return done(err); + } + if (!user) { + return done(null, false, req.flash('message', req.__('无效的用户名或密码.'))); + } + if (!isValidPassword(user, password)) { + return done(null, false, req.flash('message', req.__('无效的用户名或密码.'))); + } + return done(null, user); + }); + })); +}; \ No newline at end of file diff --git a/freesun/services/processservice.js b/freesun/services/processservice.js new file mode 100644 index 0000000..679796a --- /dev/null +++ b/freesun/services/processservice.js @@ -0,0 +1,55 @@ +/** + * Created by rain on 2015/8/7. + */ +/*jslint node:true */ +'use strict'; +var WebSocketServer = require('ws').Server; + +var Project = require('../models/project'); +var logger = require('../env/logger'); +var wsconfig = require('../env/config').ws; + +function Ps(wss) { + this.wss = wss; + this.start = function () { + this.wss.broadcast = function (data) { + wss.clients.forEach(function each(client) { + try { + client.send(data); + } catch (e) { + logger.error('Fail to send message to client[%s], reason: %s.', client, e.stack); + } + }); + }; + var that = this, + service = function (interval) { + interval = interval || 5000; + setTimeout(function () { + //if (that.wss.clients.length > 0) { + Project.allWithRuntimeInfo().then(function (all) { + wss.broadcast(JSON.stringify(all.filter(function (p, i, arr) { + return p != null; + }))); + service(interval); + }, function (err) { + logger.error(err); + service(interval); + }); + //} else { + // service(interval); + //} + }, interval); + }; + service(wsconfig.processInterval); + }; + + this.stop = function () { + try { + this.wss.close(); + } catch (e) { + logger.error('Fail to stop Ps server, reason: %s.', e.stack); + } + }; +} + +module.exports = new Ps(new WebSocketServer({port: wsconfig.process})); \ No newline at end of file diff --git a/freesun/services/systemservice.js b/freesun/services/systemservice.js new file mode 100644 index 0000000..5ed0f39 --- /dev/null +++ b/freesun/services/systemservice.js @@ -0,0 +1,80 @@ +/** + * Created by rain on 2015/8/10. + */ +/*jslint node:true */ +'use strict'; +var WebSocketServer = require('ws').Server; +var os = require('os'); + +var logger = require('../env/logger'); +var wsconfig = require('../env/config').ws; + +function OsSys(wss) { + this.wss = wss; + this.start = function () { + this.wss.broadcast = function (data) { + wss.clients.forEach(function each(client) { + try { + client.send(data); + } catch (e) { + logger.error('Fail to send message to client[%s], reason: %s.', client, e.stack); + } + }); + }; + var that = this, + service = function (interval) { + interval = interval || 5000; + setTimeout(function () { + if (that.wss.clients.length > 0) { + var cpus = os.cpus(), results = {}, + memresult, cpuresults, + i, cpu, total, type, len; + results.cpus = []; + results.mems = {}; + results.uptime = Number(os.uptime() / 60 / 60).toFixed(2); + memresult = results.mems; + memresult.totalmem = os.totalmem(); + memresult.freemem = os.freemem(); + memresult.memused = os.totalmem() - os.freemem(); + memresult.memusage = Math.round(100 * (os.totalmem() - os.freemem()) / os.totalmem()); + cpuresults = results.cpus; + + for (i = 0, len = cpus.length; i < len; i = i + 1) { + //logger.info('CPU %s', i); + cpu = cpus[i]; + total = 0; + cpuresults[i] = {}; + cpuresults[i].no = i; + for (type in cpu.times) { + if (cpu.times.hasOwnProperty(type)) { + total += cpu.times[type]; + } + } + + for (type in cpu.times) { + if (cpu.times.hasOwnProperty(type)) { + cpuresults[i][type] = Math.round(100 * cpu.times[type] / total); + } + } + } + wss.broadcast(JSON.stringify(results), function () { //ignore errors + }); + service(interval); + } else { + service(interval); + } + }, interval); + }; + service(wsconfig.systemInterval); + }; + + this.stop = function () { + try { + this.wss.close(); + } catch (e) { + logger.error('Fail to close OsSys server, reason: %s.', e.stack); + } + }; +} + +module.exports = new OsSys(new WebSocketServer({port: wsconfig.system})); \ No newline at end of file diff --git a/freesun/services/tailfileservice.js b/freesun/services/tailfileservice.js new file mode 100644 index 0000000..55d2249 --- /dev/null +++ b/freesun/services/tailfileservice.js @@ -0,0 +1,136 @@ +/** + * Created by rain on 2015/8/14. + */ +/*jslint node:true */ +'use strict'; +var WebSocketServer = require('ws').Server; +var WebSocket = require('ws'); +var Q = require('q'); +var fs = require('fs'); + +var Process = require('../models/process'); +var logger = require('../env/logger'); +var Tail = require('../tools/tail').Tail; +var wsconfig = require('../env/config').ws; + +function TailRecord(tail) { + this.tail = tail; + this.count = 0; +} + +function Ts(wss) { + this.wss = wss; + this.tailedfiles = {}; +} + +Ts.prototype.stop = function () { + var tailedfile, tailRecord; + try { + for (tailedfile in this.tailedfiles) { + if (this.tailedfiles.hasOwnProperty(tailedfile)) { + tailRecord = this.tailedfiles[tailedfile]; + if (tailRecord && tailRecord.tail) { + tailRecord.tail.unwatch(); + } + } + } + this.wss.close(); + } catch (e) { + logger.error('Fail to stop tail server, reason: %s.', e.stack); + } +}; + +Ts.prototype.onErr = function (error) { + logger.error('Tail error %s', error); +}; + +Ts.prototype.onSuccess = function (msg) { + logger.info(msg); +}; + +Ts.prototype.onReq = function (req) { + var deferred = Q.defer(); + try { + req = JSON.parse(req); + if (req.filetotail) { + deferred.resolve(req.filetotail); + } else { + deferred.reject({e: 'Invalid request.'}); + } + } catch (e) { + deferred.reject(e.message); + } + return deferred.promise; +}; + +Ts.prototype.checkFile = function (fileToTail) { + var deferred = Q.defer(); + fs.stat(fileToTail, function (err, stats) { + if (err) { + deferred.reject(err); + } else { + stats.fileToTail = fileToTail; + deferred.resolve(stats); + } + }); + return deferred.promise; +}; + +Ts.prototype.start = function () { + var ts = this; + this.wss.on('connection', function connection(ws) { + ws.on('message', function incoming(req) { + ts.onReq(req) + .then(ts.checkFile) + .then(function (fileStats) { + var emsg = '', tailRecord, tail, + deferred = Q.defer(); + + if (fileStats.isFile()) { + if (!ts.tailedfiles.hasOwnProperty(fileStats.fileToTail)) { + ts.tailedfiles[fileStats.fileToTail] = new TailRecord(new Tail(fileStats.fileToTail, '\r\n', 'ascii'), 0); + } + tailRecord = ts.tailedfiles[fileStats.fileToTail]; + tail = tailRecord.tail; + if (!ws.tailedfile) { + tail.on('line', function tailSend(data) { + try { + ws.send(data); + } catch (e) { + tail.removeListener('line', tailSend); + } + }); + //trick + ws.tailedfile = fileStats.fileToTail; + tailRecord.count = tailRecord.count + 1; + tail.watch(); + deferred.resolve('Success to tail file: ' + fileStats.fileToTail); + } else { + emsg = 'Duplicated file tail request.'; + deferred.reject(emsg); + } + } else { + emsg = fileStats.fileToTail + ' does not exist'; + deferred.reject(emsg); + } + return deferred.promise; + }) + .then(ts.onSuccess) + .catch(ts.onErr) + .done(); + }); + ws.on('close', function close() { + if (this.tailedfile) { + var trToClean = ts.tailedfiles[this.tailedfile]; + if (trToClean) { + trToClean.count = trToClean.count - 1; + if (trToClean.count <= 0) { + trToClean.tail.unwatch(); + } + } + } + }); + }); +}; + +module.exports = new Ts(new WebSocketServer({port: wsconfig.tail})); \ No newline at end of file diff --git a/freesun/services/updateservice.js b/freesun/services/updateservice.js new file mode 100644 index 0000000..c49e8ea --- /dev/null +++ b/freesun/services/updateservice.js @@ -0,0 +1,425 @@ +/** + * Created by rain on 2015/8/25. + */ +/*jslint node:true */ +/*jslint nomen:true */ +'use strict'; +var WebSocketServer = require('ws').Server; +var path = require('path'); +var fs = require('fs-extra'); +var Q = require('q'); +var exec = require('child_process').exec; +var ustring = require('underscore.string'); +var events = require("events"); +var util = require("util"); +var uuid = require('node-uuid'); +var merge = require('lodash').merge; + +var unzip = require('../tools/unzip/unzip'); +var logger = require('../env/logger'); +var config = require('../env/config'); +var Project = require('../models/project'); + +var FlowStep = require('../upgrade/flowStep').FlowStep; +var StepLog = require('../upgrade/flowStep').StepLog; +var StepStatus = require('../upgrade/flowStep').StepStatus; + +var wsconfig = config.ws; + +function Us(wss) { + this.wss = wss; + this.isRunning = false; + this.flow = null; + this.steps = {}; + fs.mkdirsSync(Project.deletedDir); + fs.mkdirsSync(Us.tempDir); + fs.mkdirsSync(Us.decompress); + fs.mkdirsSync(Us.backupRoot); + fs.mkdirsSync(Us.uploads); +} + +util.inherits(Us, events.EventEmitter); + + +Us.ROOT = path.join(__dirname, '../../'); + +Us.decompress = path.join(__dirname, '../../workspace', 'decompress'); +Us.backupRoot = path.join(__dirname, '../../workspace', 'backup'); +Us.uploads = path.join(__dirname, '../../uploads'); +Us.deployScript = 'deploy.js'; +Us.tempDir = path.join(__dirname, '..\\temp'); +Us.deployFlowSrc = path.join(Us.decompress, Us.deployScript); +Us.deployFlowTarget = path.join(Us.tempDir, Us.deployScript); +Us.sqlDir = path.join(Us.decompress, 'sql'); +Us.sqlOutput = path.join(Us.decompress, 'sql', 'output.txt'); + + +Us.prototype.newStep = function (flowStep) { + var step = this.steps[flowStep.name]; + if (step) { + step.status = flowStep.status; + step.logs = step.logs.concat(flowStep.logs); + this.emit('process', flowStep, flowStep.logs); + } else { + this.steps[flowStep.name] = flowStep; + this.emit('process', flowStep, [new StepLog(flowStep.name, 0, flowStep.logLevel)]); + if (flowStep.logs.length > 0) { + this.emit('process', flowStep, flowStep.logs); + } + } +}; + +Us.prototype.updateStep = function (flowStep, stepLog) { + var step = this.steps[flowStep.name]; + if (step) { + step.status = flowStep.status; + step.logs.push(stepLog); + this.emit('process', flowStep, [stepLog]); + } else { + flowStep.logs.push(stepLog); + this.steps[flowStep.name] = flowStep; + this.emit('process', flowStep, [new StepLog(flowStep.name, 0, 'info')]); + this.emit('process', flowStep, flowStep.logs); + } +}; + +Us.prototype.dumpSteps = function () { + return JSON.stringify(this.steps); +}; + +Us.prototype.clearSteps = function () { + this.steps = {}; +}; + +Us.prototype.findStep = function (name) { + return this.steps[name]; +}; + +Us.prototype.start = function () { + Project.resumeWatching(); + events.EventEmitter.apply(this); + var that = this, + service = function (interval) { + interval = interval || 1000 * 60 * 60 * 24; + setTimeout(function () { + //Todo clear backup file + //Us.clear(Us.backupRoot); + //Us.clear(Us.uploads); + //service(interval) + }, interval); + }; + service(wsconfig.backupClearInterval); + this.wss.broadcast = function (data) { + that.wss.clients.forEach(function each(client) { + try { + client.send(data); + } catch (e) { + logger.error('Fail to send message to client[%s], reason: %s.', client, e.stack); + } + }); + }; + this.wss.on('connection', function connection(ws) { + var step; + if (that.status()) { + //push current status flow.dumpMsg + for (step in that.steps) { + ws.send(JSON.stringify(step.logs)); + } + //ws.send(JSON.stringify(that.flow.dumpMsg())); + } else { + //nothing; + } + }); + this.on('process', function (currentStep, stepLog) { + that.wss.broadcast(JSON.stringify(stepLog)); + stepLog.forEach(function (log) { + logger.log(log.logLevel, log.msg); + }); + }); +}; + +Us.prototype.status = function () { + return this.isRunning; +}; + +Us.prototype.finish = function () { + this.isRunning = false; + Project.resumeWatching(); + this.wss.broadcast('~!@#$over'); +}; + +Us.prototype.failed = function () { + this.isRunning = false; + Project.resumeWatching(); + this.wss.broadcast('~!@#$error'); +}; + +Us.prototype.check = function () { + if (this.isRunning) { + throw new Error('An operation progress is running.'); + } +}; + +Us.prototype.install = function (pkg) { + var projWrokspace = {workspace: {}}, + that = this; + this.check(); + try { + this.isRunning = true; + projWrokspace.workspace.package = pkg; + projWrokspace.workspace.decompress = Us.decompress; + projWrokspace.workspace.backupRoot = Us.backupRoot; + this.begin(projWrokspace) + .then(function () { + return that.loadInstallScript(projWrokspace); + }).then(function (flow) { + return that.flow.install(flow) + .then(function (flow) { + return that.newProject(flow); + }) + .then(function (flow) { + that.finish(); + }) + .catch(function (flow) { + that.failed(); + return that.flow.uninstall(flow); + }); + }).catch(function (err) { + that.failed(); + //logger.error(err); + }); + } catch (e) { + that.failed(); + throw new Error(ustring.sprintf('This project does not exist or can not be updated. e: %s', e.stack)); + } +}; + +Us.prototype.newProject = function (flow) { + var flowStep, + deferred = Q.defer(); + flowStep = new FlowStep('Record installed project.'); + this.newStep(flowStep); + this.updateStep(flowStep, new StepLog('Begin...', 1, 'info')); + Project.addProject(flow.project); + //不能随意手工添加 ID.js + fs.copySync(Us.deployFlowSrc, path.join(Project.projectDir, flow.project.id + '.js')); + flowStep.status = StepStatus.Success; + this.updateStep(flowStep, new StepLog('End...', 1, 'info')); + deferred.resolve(flow); + return deferred.promise; +}; + +Us.prototype.loadInstallScript = function (projWrokspace) { + var tempProj, + InstallFlow, + that = this, + flowStep, + proj, + deferred = Q.defer(); + flowStep = new FlowStep('Load install script.'); + that.newStep(flowStep); + that.updateStep(flowStep, new StepLog('Begin...', 1, 'info')); + try { + fs.copySync(Us.deployFlowSrc, Us.deployFlowTarget); + delete require.cache[require.resolve(Us.deployFlowTarget)]; + InstallFlow = require(Us.deployFlowTarget).Flow; + //不能随意增加 ID.js + tempProj = Project.makeProject(require(Us.deployFlowTarget).project, Project.getId()); + proj = merge(tempProj, projWrokspace); // merge, dynamic first. + if (proj.sqlCmd) { + proj.sqlCmd.inputFiles = Us.sqlDir; + proj.sqlCmd.outputFile = Us.sqlOutput; + } + that.flow = new InstallFlow(proj, that); + flowStep.status = StepStatus.Success; + that.updateStep(flowStep, new StepLog( + ustring.sprintf('Project info: %s, id:%s', proj.name, proj.id), 1, 'info')); + that.updateStep(flowStep, new StepLog('End...', 1, 'info')); + deferred.resolve(that.flow); + } catch (e) { + flowStep.status = StepStatus.Failed; + that.updateStep(flowStep, new StepLog('Fail. reason: ' + e.stack, 1, 'error')); + deferred.reject(e); + } + return deferred.promise; +}; + +Us.prototype.update = function (pjid, pkg) { + var oldProj = Project.findById(pjid), + that = this, + projWorkspace = {workspace: {}}; + this.check(); + try { + this.isRunning = true; + projWorkspace.workspace.package = pkg; + projWorkspace.workspace.decompress = Us.decompress; + projWorkspace.workspace.backupRoot = Us.backupRoot; + this.begin(projWorkspace) + .then(function () { + oldProj = merge(oldProj, projWorkspace); + return that.loadUpdateScript(oldProj, projWorkspace); + }).then(function (flow) { + return that.flow.newFlow.update(flow) + .then(function () { + return that.updateProject(flow.newFlow); + }) + .then(function () { + that.finish(); + //return Q(); + }) + .catch(function () { + that.failed(); + return that.flow.newFlow.rollback(that.flow); + }); + //.then(function () { + //}); + }).catch(function (err) { + that.failed(); + return Q(); + //logger.error(err); + }); + } catch (e) { + that.failed(); + throw new Error(ustring.sprintf('This project does not exist or can not be updated. e: %s', e.stack)); + } +}; + +Us.prototype.updateProject = function (flow) { + var flowStep, + deferred = Q.defer(); + flowStep = new FlowStep('Update installed project.'); + this.newStep(flowStep); + this.updateStep(flowStep, new StepLog('Begin...', 1, 'info')); + //Overwrite(delete new) new ProjectInfo. + Project.deleteById(flow.project.id); + Project.addProject(flow.project); + fs.copySync(Us.deployFlowSrc, path.join(Project.projectDir, flow.project.id + '.js')); + flowStep.status = StepStatus.Success; + this.updateStep(flowStep, new StepLog('End...', 1, 'info')); + deferred.resolve(flow); + return deferred.promise; +}; + +Us.prototype.loadUpdateScript = function (oldProj, projWorkspace) { + var deferred = Q.defer(), + tempProj, + NewFlow, + OldFlow, + that = this, + flowStep, + proj; + flowStep = new FlowStep('Load update script.'); + that.newStep(flowStep); + that.updateStep(flowStep, new StepLog('Begin...', 1, 'info')); + try { + fs.copySync(Us.deployFlowSrc, Us.deployFlowTarget); + delete require.cache[require.resolve(Us.deployFlowTarget)]; + delete require.cache[require.resolve(path.join(Project.projectDir, oldProj.id + '.js'))]; + tempProj = Project.makeProject(require(Us.deployFlowTarget).project, oldProj.id); + proj = merge(tempProj, projWorkspace); // merge, new info first. + NewFlow = require(Us.deployFlowTarget).Flow; + OldFlow = require(path.join(Project.projectDir, oldProj.id + '.js')).Flow; + if (proj.sqlCmd) { + proj.sqlCmd.inputFiles = Us.sqlDir; + proj.sqlCmd.outputFile = Us.sqlOutput; + } + that.flow = {newFlow: new NewFlow(proj, that), oldFlow: new OldFlow(oldProj, that)}; + that.updateStep(flowStep, new StepLog( + ustring.sprintf('Project info: %s, id:%s', that.flow.oldFlow.project.name, that.flow.oldFlow.project.id), 1, 'info')); + flowStep.status = StepStatus.Success; + that.updateStep(flowStep, new StepLog('End...', 1, 'info')); + deferred.resolve(that.flow); + } catch (e) { + flowStep.status = StepStatus.Failed; + that.updateStep(flowStep, new StepLog('Fail. reason: ' + e.stack, 1, 'error')); + deferred.reject(e); + } + return deferred.promise; +}; + +Us.prototype.begin = function (projWorkspace) { + var defer = Q.defer(), + that = this, + pkgPath = projWorkspace.workspace.package, + flowStep, + decompressPath = projWorkspace.workspace.decompress; + this.clearSteps(); + flowStep = new FlowStep('Unzip package.'); + this.newStep(flowStep); + this.updateStep(flowStep, new StepLog('Begin...', 1, 'info')); + this.updateStep(flowStep, new StepLog(ustring.sprintf('Package: %s', pkgPath), 1, 'info')); + Project.pauseWatching(); + (function () { + if (projWorkspace.workspace.keepOldBackup) { + var now = new Date(); + projWorkspace.workspace.backup = path.join(projWorkspace.workspace.backupRoot, + ustring.sprintf('%s-%s-%s %s-%s-%s', now.getFullYear(), now.getMonth() + 1, + now.getDate(), now.getHours(), now.getMinutes(), now.getSeconds())); + } else { + projWorkspace.workspace.backup = projWorkspace.workspace.backupRoot; + } + return Q.nfcall(fs.emptyDir, projWorkspace.workspace.backup); + }()).then(function () { + return Q.nfcall(fs.emptyDir, decompressPath); + }) + .then(function () { + var reader = fs.createReadStream(pkgPath); + reader.pipe(unzip.Extract({path: decompressPath})); + reader.on('end', function () { + setTimeout(function () { + flowStep.status = StepStatus.Success; + that.updateStep(flowStep, new StepLog('End...', 1, 'info')); + defer.resolve(); + }, 5000); + }); + reader.on('error', function (err) { + console.log(err); + }); + }) + .catch(function (err) { + flowStep.status = StepStatus.Failed; + that.updateStep(flowStep, new StepLog('Fail. reason:' + err, 1, 'error')); + defer.reject(err); + }); + return defer.promise; +}; + +Us.prototype.stop = function () { + try { + this.wss.close(); + } catch (e) { + logger.error('Fail to close US server, reason: %s.', e.stack); + } +}; + +Us.prototype.selfUpdate = function (pkg) { + var reader = fs.createReadStream(pkg), + flowStep, + that; + this.check(); + that = this; + this.clearSteps(); + flowStep = new FlowStep('Self Update.'); + this.newStep(flowStep); + this.updateStep(flowStep, new StepLog('Begin...', 1, 'info')); + reader.pipe(unzip.Extract({path: Us.ROOT})); + reader.on('end', function () { + setTimeout(function () { + exec("npm install", {cwd: Us.ROOT}, function (errIn, stdOut, stdErr) { + var err = errIn || stdErr.trim(); + if (err) { + that.updateStep(flowStep, new StepLog(ustring.sprintf('Failed: %s', err), 1, 'error')); + } else { + that.updateStep(flowStep, new StepLog(ustring.sprintf('Success: %s', stdOut), 1, 'info')); + } + that.updateStep(flowStep, new StepLog('End...', 1, 'info')); + that.finish(); + setTimeout(function () { + process.exit(0); + }, 5000); + }); + }, 5000); + }); +}; + +module.exports = new Us(new WebSocketServer({port: wsconfig.update})); \ No newline at end of file diff --git a/freesun/tools/command.js b/freesun/tools/command.js new file mode 100644 index 0000000..d6d26e3 --- /dev/null +++ b/freesun/tools/command.js @@ -0,0 +1,101 @@ +/*jslint node:true */ +'use strict'; + +var _ = require('lodash'); + +function toWindowsPath(path) { + return path.replace(/\//g, '\\'); +} + +module.exports = function (options) { + var args = []; + + if (options.server) { + var server; + if (_.isString(options.server)) server = options.server; + else { + server = options.server.name; + if (options.server.protocol) server = options.server.protocol + ':' + server; + if (options.server.instance) server += '\\' + options.server.instance; + if (options.server.port) server += ',' + String(options.server.port); + } + args.push('-S', server); + } + if (options.database) args.push('-d', options.database); + if (options.trustedConnection) args.push('-E'); + if (options.username) args.push('-U', options.username); + if (options.password) args.push('-P', options.password); + if (options.dedicatedAdminConnection) args.push('-A'); + if (options.trustServerCert) args.push('-C'); + if (options.loginTimeout) args.push('-l', String(options.loginTimeout)); + if (options.workstationName) args.push('-H', options.workstationName); + if (options.applicationIntent) args.push('-K', options.applicationIntent); + if (options.multisubnetFailover) args.push('-M'); + if (options.encryptedConnection) args.push('-N'); + if (options.newPassword) args.push('-Z', options.newPassword); + + if (options.inputFiles) options.inputFiles + .forEach(function (path) { + args.push('-i', toWindowsPath(path)); + }); + if (options.outputFile) args.push('-o', toWindowsPath(options.outputFile)); + if (options.codepage) { + var codepage = options.codepage; + var codepages = []; + if (_.isString(codepage)) + codepages.push(codepage); + else { + if (codepage.input) + codepages.push('i:' + codepage.input); + if (codepage.output) + codepages.push('o:' + codepage.output); + } + args.push('-f', codepages.join(',')); + } + if (options.errorRedirection) { + args.push('-r' + (options.errorRedirection.all ? '1' : '')); + } + if (options.localizeResults) args.push('-R'); + if (options.unicodeOutput) args.push('-u'); + + if (options.query) args.push('-Q', options.query); + if (options.variables) _.forOwn(options.variables, + function (value, name) { + args.push('-v', name + '=' + value); + }); + if (options.queryTimeout) args.push('-t', String(options.queryTimeout)); + if (options.printInputScripts) args.push('-e'); + if (options.quoteIdentifier) args.push('-I'); + if (options.ignoreVariables) args.push('-x'); + + if (options.headers) args.push('-h', String(options.headers)); + if (options.removeControlChars) { + var removeOptions = ''; + if (options.removeControlChars.single) removeOptions = '1'; + if (options.removeControlChars.consecutive) removeOptions = '2'; + args.push('-k' + removeOptions); + } + if (options.columnSeperator) args.push('-s', options.columnSeperator); + if (options.columnWidth) args.push('-w', String(options.columnWidth)); + if (options.removeTrailingSpaces) args.push('-W'); + if (options.variableLengthDisplayWidth) args.push('-y', String(options.variableLengthDisplayWidth)); + if (options.fixedLengthDisplayWidth) args.push('-Y', String(options.fixedLengthDisplayWidth)); + + if (options.failOnSqlErrors) args.push('-b'); + if (options.errorLevel) args.push('-m', String(options.errorLevel)); + if (options.errorSeverityLevel) args.push('-V', String(options.errorSeverityLevel)); + + if (options.packetSize) args.push('-a', String(options.packetSize)); + if (options.batchTerminator) args.push('-c', options.batchTerminator); + if (options.perfStats) { + args.push('-p' + (options.perfStats.colonSeperated ? '1' : '')); + } + if (options.enhancedSecurity) { + args.push('-X' + (options.enhancedSecurity.failOnErrors ? '1' : '')); + } + + return { + path: 'sqlcmd', + args: args + }; +}; \ No newline at end of file diff --git a/freesun/tools/iis.js b/freesun/tools/iis.js new file mode 100644 index 0000000..d3f2fad --- /dev/null +++ b/freesun/tools/iis.js @@ -0,0 +1,330 @@ +/** + * Copyright (C) 2012 Integrify, Inc. -- copy from node-iis https://github.com/Integrify/node-iis + * + */ +/*jslint node:true */ +'use strict'; + +var exec = require('child_process').exec; +var path = require('path'); +var xml2js = require('xml2js'); +var _ = require('underscore'); + +var IIS = function () { + return { + execute: function (cmd, cb) { + if (!_.isFunction(cb)) { + cb = _.noop; + } + if (!_.isString(cmd)) { + cb(new TypeError('args must be a string')); + } + + exec(cmd, function (errIn, stdOut, stdErr) { + var err = errIn || stdErr.trim(); + + cb(err ? new Error(err + cmd) : null, stdOut.trim()); + }); + }, + setDefaults: function (options) { + var appdrive = options.drive || 'c'; + this.sitekey = options.sitekey || '$'; + this.appcmd = appdrive + ':\\windows\\system32\\inetsrv\\appcmd.exe'; + + }, + createSite: function (options, cb) { + var self = this; + options = options || + { + name: 'New Site', + protocol: 'http', + host: '*', + port: '80' + }; + + //hold this to be used when creating app folders, etc + self.last_site = options.name; + + self.exists('site', options.name, function (err, tf) { + if (!tf) { + + var site_cmd = ' add site /name:"' + options.name + '"'; + site_cmd += ' /bindings:' + (options.bindings || (options.protocol + '://' + options.host + ':' + options.port)); + + if (options.absPath) { + site_cmd += ' /physicalPath:"' + options.absPath + '"'; + } + + self.execute(self.appcmd + ' ' + site_cmd, cb); + } + else { + cb('Site ' + options.name + ' exists'); + } + }); + + }, + deleteSite: function (options, cb) { + var self = this; + self.exists('site', options.name, function (err, tf) { + if (tf) { + self.execute(self.appcmd + ' delete site /site.name:"' + options.name + '"', cb); + } else { + // Ignore + cb(null, 'Site ' + options.name + ' does not exists'); + } + }); + }, + stopSite: function (options, cb) { + var self = this; + self.exists('site', options.name, function (err, tf) { + if (tf) { + self.execute(self.appcmd + ' stop site /site.name:"' + options.name + '"', function (err) { + if (err) { + cb(err); + } else { + self.stopAppPool(options, cb); + } + }); + } else { + // Ignore + cb(null, 'Site ' + options.name + ' does not exists'); + } + }); + }, + startSite: function (options, cb) { + var self = this; + self.exists('site', options.name, function (err, tf) { + if (tf) { + self.execute(self.appcmd + ' start site /site.name:"' + options.name + '"', function (err) { + if (err) { + cb(err); + } else { + self.startAppPool(options, cb); + } + }); + } else { + cb('Site ' + options.name + ' does not exists'); + } + }); + }, + /** + /** + * Create app pool, also set app pool identity of object {name:,identity:} passed + * @param options + * @param cb + */ + createAppPool: function (options, cb) { + var self = this; + var poolname = typeof(options) == 'string' ? options : options.name; + var identity = typeof(options) == 'string' ? null : options.identity; + self.exists('apppool', poolname, function (err, tf) { + if (!tf) { + self.execute(self.appcmd + ' add apppool /name:"' + poolname + '"', function (err, stdout) { + if (!err && identity) { + self.setAppPoolIdentity(poolname, identity, cb); + } + else { + cb(err, stdout); + } + }); + } + else { + cb(null, 'App pool ' + poolname + ' exists'); + } + }) + }, + recycleAppPool: function (options, cb) { + this.execute(this.appcmd + ' recycle apppool /apppool.name:"' + options.pool + '"', cb); + }, + deleteAppPool: function (options, cb) { + var self = this; + self.exists('apppool', options.pool, function (err, tf) { + if (tf) { + self.execute(self.appcmd + ' delete apppool /apppool.name:"' + options.pool + '"', cb); + } else { + cb(null, 'App Pool ' + options.pool + ' does not exists'); + } + }); + }, + stopAppPool: function (options, cb) { + var self = this; + self.exists('apppool', options.pool, function (err, tf) { + if (tf && tf.state !== 'Stopped') { + self.execute(self.appcmd + ' stop apppool /apppool.name:"' + options.pool + '"', cb); + } else { + cb(null, 'App Pool ' + options.pool + ' does not exists or stopped'); + } + }); + }, + startAppPool: function (options, cb) { + var self = this; + self.exists('apppool', options.pool, function (err, tf) { + if (tf) { + self.execute(self.appcmd + ' start apppool /apppool.name:"' + options.pool + '"', cb); + } else { + cb(null, 'App Pool ' + options.pool + ' does not exists'); + } + }); + }, + mapAppPool: function (options, cb) { + var map_cmd = ' set app /app.name:"' + options.name + '/" /applicationPool:' + options.pool; + this.execute(this.appcmd + ' ' + map_cmd, cb); + }, + setAppPoolIdentity: function (pool_name, identity, cb) { + var set_cmd = " set config /section:applicationPools /[name='" + pool_name + "'].processModel.identityType:" + identity; + this.execute(this.appcmd + ' ' + set_cmd, cb); + }, + createAppFolder: function (options, cb) { + var self = this; + self.exists('app', (options.site || this.last_site) + '/' + options.virtual_path, function (err, tf) { + if (!tf) { + var createapp_cmd = ' add app /site.name:"' + (options.site || self.last_site) + '" /path:/' + options.virtual_path + ' /physicalPath:"' + options.physical_path + '"'; + self.execute(self.appcmd + createapp_cmd, cb); + } + else { + cb(err, "App " + (options.site || self.last_site) + '/' + options.virtual_path + " already exists"); + } + }); + + }, + unlockSection: function (section, cb) { + var unlock_cmd = " unlock config /section:" + section; + this.execute(this.appcmd + unlock_cmd, cb); + }, + setWindowsAuthentication: function (appPath, enable, cb) { + var self = this; + var set_cmd = ' set config "' + appPath + '" /section:windowsAuthentication /enabled:' + enable; + self.unlockSection('windowsAuthentication', function (err, stdout) { + self.execute(self.appcmd + set_cmd, cb); + }); + + }, + setAnonymousAuthentication: function (appPath, enable, cb) { + var self = this; + var set_cmd = ' set config "' + appPath + '" /section:anonymousAuthentication /enabled:' + enable; + self.unlockSection('anonymousAuthentication', function (err, stdout) { + self.execute(self.appcmd + set_cmd, cb); + }); + + }, + list: function (type, cb) { + var parser = new xml2js.Parser(); + var self = this; + self.execute(this.appcmd + ' list ' + type + ' /xml', function (err, outxml) { + parser.parseString(outxml, function (err, result) { + result = result['appcmd']; + // + // may return a single object if only 1 site exists + // + var mapped = []; + if (_.isArray(result[type.toUpperCase()])) { + mapped = _.map(result[type.toUpperCase()], function (v) { + return v[self.sitekey]; + }); + } else if (result[type.toUpperCase()]) { + mapped = [result[type.toUpperCase()][self.sitekey]]; + } else { + mapped = []; + } + + if (cb) { + cb(err, mapped); + } + else { + console.log(mapped); + + } + + }); + + }); + + }, + exists: function (type, name, cb) { + var self = this; + this.list(type, function (err, res) { + + var match = null; + + if (!err) { + match = _.find(res, function (v) { + var m = v[type.toUpperCase() + '.NAME']; + return m && m.toLowerCase() === name.toLowerCase(); + }); + } + + if (cb) { + cb(err, match); + } + else { + console.log(match); + } + + }); + }, + getInfo: function (type, name, cb) { + this.list(type, function (err, res) { + var info = null; + if (!err) { + info = res.filter(function (v) { + var m = v[type.toUpperCase() + '.NAME']; + return m && m.toLowerCase() === name.toLowerCase(); + }); + } + + if (cb) { + cb(err, info.length > 0 ? info[0] : null); + } + else { + console.log(info); + } + }); + }, + setFilePermissions: function (path, account, cb) { + this.execute('icacls "' + path + '*" /grant ' + account + ':(OI)(CI)F', function (err, stdout) { + if (cb) { + cb(err, stdout); + } + else { + console.log(err, stdout); + } + }); + }, + /** + * Set the physical path web site maps to + * @param site_name + */ + setPhysicalPath: function (site_name, path, cb) { + this.execute(this.appcmd + ' set vdir "' + site_name + '/" -physicalPath:"' + path + '"', cb); + }, + /** + * Get the physical path web site maps to + * @param site_name + */ + getPhysicalPath: function (site_name, cb) { + var self = this; + this.list("VDIR", function (err, res) { + + var match = null; + + if (!err) { + match = _.find(res, function (v) { + var m = v['VDIR.NAME']; + return m && m.toLowerCase() === (site_name.toLowerCase() + '/'); + }); + } + + if (cb) { + cb(err, match ? match["physicalPath"] : null); + } + else { + console.log(match ? match["physicalPath"] : null); + } + }); + } + }; +}(); + +IIS.setDefaults({}); + +module.exports = IIS; \ No newline at end of file diff --git a/freesun/tools/sqlcmd.js b/freesun/tools/sqlcmd.js new file mode 100644 index 0000000..f7ac448 --- /dev/null +++ b/freesun/tools/sqlcmd.js @@ -0,0 +1,13 @@ +/* + * -- copy sqlcmd-runner from https://github.com/mikeobrien/node-sqlcmd-runner + */ + +/*jslint node:true */ +'use strict'; + +var run = require('./sqlproc'), + command = require('./command'); + +module.exports = function (options, onData) { + return run(command(options), onData); +}; \ No newline at end of file diff --git a/freesun/tools/sqlproc.js b/freesun/tools/sqlproc.js new file mode 100644 index 0000000..00ae030 --- /dev/null +++ b/freesun/tools/sqlproc.js @@ -0,0 +1,39 @@ +/*jslint node:true */ +'use strict'; +var process = require('child_process'), + path = require('path'), + Q = require('q'), + logger = require('../env/logger'); + +module.exports = function (command, onData) { + var sqlcmd = process.spawn(command.path, command.args), + log = function (message) { + message = message.toString('utf8'); + logger.log(message); + return message; + }, + stdout = '', + stderr = '', + deferred = Q.defer(); + sqlcmd.stdout.on('data', function (message) { + var msg = log(message); + stdout += msg; + if (onData) { + onData(msg); + } + }); + sqlcmd.stderr.on('data', function (message) { + stderr += log(message); + }); + sqlcmd.on('exit', function (code) { + logger.log('Exit code: ' + code); + if (code > 0) { + var message = 'sqlcmd failed' + (stderr ? ': \r\n\r\n' + stderr : '.'); + deferred.reject(new Error(message)); + } else { + deferred.resolve(); + } + }); + + return deferred.promise; +}; \ No newline at end of file diff --git a/freesun/tools/tail.js b/freesun/tools/tail.js new file mode 100644 index 0000000..bfc1566 --- /dev/null +++ b/freesun/tools/tail.js @@ -0,0 +1,165 @@ +/** + * Created by rain on 2015/8/19. -- copy form node-tail https://github.com/lucagrulla/node-tail -- modify use gaze + */ +/*jslint node:true */ +/*jslint nomen:true */ +/*jslint stupid:true */ +'use strict'; +var Tail, environment, events, fs, + __bind = function (fn, me) { + return function () { + return fn.apply(me, arguments); + }; + }, + __hasProp = {}.hasOwnProperty, + __extends = function (child, parent) { + var key; + for (key in parent) { + if (__hasProp.call(parent, key)) { + child[key] = parent[key]; + } + } + function Ctor() { + this.constructor = child; + } + + Ctor.prototype = parent.prototype; + child.prototype = new Ctor(); + child.__super__ = parent.prototype; + return child; + }; +var Gaze = require('gaze').Gaze; +events = require("events"); +fs = require('fs'); +environment = process.env.NODE_ENV || 'development'; + +Tail = (function (_super) { + __extends(Tail, _super); + + Tail.prototype.readBlock = function () { + var block, stream, + _this = this; + + if (this.queue.length >= 1) { + block = this.queue.shift(); + if (block.end > block.start) { + stream = fs.createReadStream(this.filename, { + start: block.start, + end: block.end - 1, + encoding: _this.encoding + }); + stream.on('error', function (error) { + console.log("Tail error:" + error); + return _this.emit('error', error); + }); + stream.on('end', function () { + if (_this.queue.length >= 1) { + return _this.internalDispatcher.emit("next"); + } + }); + return stream.on('data', function (data) { + var chunk, parts, _i, _len, _results; + + _this.buffer += data; + parts = _this.buffer.split(_this.separator); + _this.buffer = parts.pop(); + _results = []; + for (_i = 0, _len = parts.length; _i < _len; _i = _i + 1) { + chunk = parts[_i]; + _results.push(_this.emit("line", chunk)); + } + return _results; + }); + } + } + }; + + function Tail(filename, separator, encoding, fsWatchOptions, frombeginning) { + var stats, + _this = this; + + this.filename = filename; + this.separator = separator !== null ? separator : '\n'; + this.encoding = encoding !== null ? encoding : "utf-8"; + this.fsWatchOptions = fsWatchOptions !== null ? fsWatchOptions : {}; + this.frombeginning = frombeginning !== null ? frombeginning : false; + this.readBlock = __bind(this.readBlock, this); + this.buffer = ''; + this.internalDispatcher = new events.EventEmitter(); + this.queue = []; + this.isWatching = false; + stats = fs.statSync(this.filename); + this.internalDispatcher.on('next', function () { + return _this.readBlock(); + }); + this.pos = this.frombeginning ? 0 : stats.size; + this.watch(); + } + + Tail.prototype.watch = function () { + var _this = this; + + if (this.isWatching) { + return; + } + this.isWatching = true; + this.watcher = new Gaze(this.filename); + + this.watcher.on('all', function (event, filepath) { + if (filepath === _this.filename) { + return _this.watchEvent(event); + } + }); + }; + + Tail.prototype.watchEvent = function (e) { + var stats, + _this = this; + + if (e === 'changed') { + stats = fs.statSync(this.filename); + if (stats.size < this.pos) { + this.pos = stats.size; + } + if (stats.size > this.pos) { + this.queue.push({ + start: this.pos, + end: stats.size + }); + this.pos = stats.size; + if (this.queue.length === 1) { + return this.internalDispatcher.emit("next"); + } + } + } else if (e === 'renamed') { + this.unwatch(); + return setTimeout(function () { + return _this.watch(); + }, 1000); + } + }; + + Tail.prototype.watchFileEvent = function (curr, prev) { + if (curr.size > prev.size) { + this.queue.push({ + start: prev.size, + end: curr.size + }); + if (this.queue.length === 1) { + return this.internalDispatcher.emit("next"); + } + } + }; + + Tail.prototype.unwatch = function () { + if (this.watcher) { + this.watcher.close(); + this.pos = 0; + } + this.isWatching = false; + this.queue = []; + }; + return Tail; +}(events.EventEmitter)); + +exports.Tail = Tail; diff --git a/freesun/tools/unzip/lib/entry.js b/freesun/tools/unzip/lib/entry.js new file mode 100644 index 0000000..43535a8 --- /dev/null +++ b/freesun/tools/unzip/lib/entry.js @@ -0,0 +1,17 @@ +'use strict'; + +module.exports = Entry; + +var PassThrough = require('readable-stream/passthrough'); +var inherits = require('util').inherits; + +inherits(Entry, PassThrough); + +function Entry () { + PassThrough.call(this); + this.props = {}; +} + +Entry.prototype.autodrain = function () { + this.on('readable', this.read.bind(this)); +}; diff --git a/freesun/tools/unzip/lib/extract.js b/freesun/tools/unzip/lib/extract.js new file mode 100644 index 0000000..fd03181 --- /dev/null +++ b/freesun/tools/unzip/lib/extract.js @@ -0,0 +1,56 @@ +'use strict'; + +module.exports = Extract; + +var Parse = require("../unzip").Parse; +var Writer = require("fstream").Writer; +var Writable = require('readable-stream/writable'); +var path = require('path'); +var inherits = require('util').inherits; + +inherits(Extract, Writable); + +function Extract (opts) { + var self = this; + if (!(this instanceof Extract)) { + return new Extract(opts); + } + + Writable.apply(this); + this._opts = opts || { verbose: false }; + + this._parser = Parse(this._opts); + this._parser.on('error', function(err) { + self.emit('error', err); + }); + this.on('finish', function() { + self._parser.end(); + }); + + var writer = Writer({ + type: 'Directory', + path: opts.path + }); + writer.on('error', function(err) { + self.emit('error', err); + }); + writer.on('close', function() { + self.emit('close') + }); + + this.on('pipe', function(source) { + if (opts.verbose && source.path) { + console.log('Archive: ', source.path); + } + }); + + this._parser.pipe(writer); +} + +Extract.prototype._write = function (chunk, encoding, callback) { + if (this._parser.write(chunk)) { + return callback(); + } + + return this._parser.once('drain', callback); +}; diff --git a/freesun/tools/unzip/lib/parse.js b/freesun/tools/unzip/lib/parse.js new file mode 100644 index 0000000..329651a --- /dev/null +++ b/freesun/tools/unzip/lib/parse.js @@ -0,0 +1,315 @@ +'use strict'; + +module.exports = Parse.create = Parse; + +require("setimmediate"); +var Transform = require('readable-stream/transform'); +var inherits = require('util').inherits; +var zlib = require('zlib'); +var iconv = require('iconv-lite'); +var binary = require('binary'); +var PullStream = require('pullstream'); +var MatchStream = require('match-stream'); +var Entry = require('./entry'); + +inherits(Parse, Transform); + +function Parse(opts) { + var self = this; + if (!(this instanceof Parse)) { + return new Parse(opts); + } + + Transform.call(this, {lowWaterMark: 0}); + this._opts = opts || {verbose: false}; + this._hasEntryListener = false; + + this._pullStream = new PullStream(); + this._pullStream.on("error", function (e) { + self.emit('error', e); + }); + this._pullStream.once("end", function () { + self._streamEnd = true; + }); + this._pullStream.once("finish", function () { + self._streamFinish = true; + }); + + this._readRecord(); +} + +Parse.prototype._readRecord = function () { + var self = this; + this._pullStream.pull(4, function (err, data) { + if (err) { + return self.emit('error', err); + } + + if (data.length === 0) { + return; + } + + var signature = data.readUInt32LE(0); + if (signature === 0x04034b50) { + self._readFile(); + } else if (signature === 0x02014b50) { + self._readCentralDirectoryFileHeader(); + } else if (signature === 0x06054b50) { + self._readEndOfCentralDirectoryRecord(); + } else { + err = new Error('invalid signature: 0x' + signature.toString(16)); + self.emit('error', err); + } + }); +}; + +Parse.prototype._readFile = function () { + var self = this; + this._pullStream.pull(26, function (err, data) { + if (err) { + return self.emit('error', err); + } + + var vars = binary.parse(data) + .word16lu('versionsNeededToExtract') + .word16lu('flags') + .word16lu('compressionMethod') + .word16lu('lastModifiedTime') + .word16lu('lastModifiedDate') + .word32lu('crc32') + .word32lu('compressedSize') + .word32lu('uncompressedSize') + .word16lu('fileNameLength') + .word16lu('extraFieldLength') + .vars; + + return self._pullStream.pull(vars.fileNameLength, function (err, fileName) { + if (err) { + return self.emit('error', err); + } + fileName = iconv.decode(fileName, "GB2312"); + var entry = new Entry(); + entry.path = fileName; + entry.props.path = fileName; + entry.type = (vars.compressedSize === 0 && /[\/\\]$/.test(fileName)) ? 'Directory' : 'File'; + + if (self._opts.verbose) { + if (entry.type === 'Directory') { + console.log(' creating:', fileName); + } else if (entry.type === 'File') { + if (vars.compressionMethod === 0) { + console.log(' extracting:', fileName); + } else { + console.log(' inflating:', fileName); + } + } + } + + var hasEntryListener = self._hasEntryListener; + if (hasEntryListener) { + self.emit('entry', entry); + } + + self._pullStream.pull(vars.extraFieldLength, function (err, extraField) { + if (err) { + return self.emit('error', err); + } + if (vars.compressionMethod === 0) { + self._pullStream.pull(vars.compressedSize, function (err, compressedData) { + if (err) { + return self.emit('error', err); + } + + if (hasEntryListener) { + entry.write(compressedData); + entry.end(); + } + + return self._readRecord(); + }); + } else { + var fileSizeKnown = !(vars.flags & 0x08); + + var inflater = zlib.createInflateRaw(); + inflater.on('error', function (err) { + self.emit('error', err); + }); + + if (fileSizeKnown) { + entry.size = vars.uncompressedSize; + if (hasEntryListener) { + entry.on('finish', self._readRecord.bind(self)); + self._pullStream.pipe(vars.compressedSize, inflater).pipe(entry); + } else { + self._pullStream.drain(vars.compressedSize, function (err) { + if (err) { + return self.emit('error', err); + } + self._readRecord(); + }); + } + } else { + var descriptorSig = new Buffer(4); + descriptorSig.writeUInt32LE(0x08074b50, 0); + + var matchStream = new MatchStream({pattern: descriptorSig}, function (buf, matched, extra) { + if (hasEntryListener) { + if (!matched) { + return this.push(buf); + } + this.push(buf); + } + setImmediate(function () { + self._pullStream.unpipe(); + self._pullStream.prepend(extra); + self._processDataDescriptor(entry); + }); + return this.push(null); + }); + + self._pullStream.pipe(matchStream); + if (hasEntryListener) { + matchStream.pipe(inflater).pipe(entry); + } + } + } + }); + }); + }); +}; + +Parse.prototype._processDataDescriptor = function (entry) { + var self = this; + this._pullStream.pull(16, function (err, data) { + if (err) { + return self.emit('error', err); + } + + var vars = binary.parse(data) + .word32lu('dataDescriptorSignature') + .word32lu('crc32') + .word32lu('compressedSize') + .word32lu('uncompressedSize') + .vars; + + entry.size = vars.uncompressedSize; + self._readRecord(); + }); +}; + +Parse.prototype._readCentralDirectoryFileHeader = function () { + var self = this; + this._pullStream.pull(42, function (err, data) { + if (err) { + return self.emit('error', err); + } + + var vars = binary.parse(data) + .word16lu('versionMadeBy') + .word16lu('versionsNeededToExtract') + .word16lu('flags') + .word16lu('compressionMethod') + .word16lu('lastModifiedTime') + .word16lu('lastModifiedDate') + .word32lu('crc32') + .word32lu('compressedSize') + .word32lu('uncompressedSize') + .word16lu('fileNameLength') + .word16lu('extraFieldLength') + .word16lu('fileCommentLength') + .word16lu('diskNumber') + .word16lu('internalFileAttributes') + .word32lu('externalFileAttributes') + .word32lu('offsetToLocalFileHeader') + .vars; + + return self._pullStream.pull(vars.fileNameLength, function (err, fileName) { + if (err) { + return self.emit('error', err); + } + fileName = fileName.toString('utf8'); + + self._pullStream.pull(vars.extraFieldLength, function (err, extraField) { + if (err) { + return self.emit('error', err); + } + self._pullStream.pull(vars.fileCommentLength, function (err, fileComment) { + if (err) { + return self.emit('error', err); + } + return self._readRecord(); + }); + }); + }); + }); +}; + +Parse.prototype._readEndOfCentralDirectoryRecord = function () { + var self = this; + this._pullStream.pull(18, function (err, data) { + if (err) { + return self.emit('error', err); + } + + var vars = binary.parse(data) + .word16lu('diskNumber') + .word16lu('diskStart') + .word16lu('numberOfRecordsOnDisk') + .word16lu('numberOfRecords') + .word32lu('sizeOfCentralDirectory') + .word32lu('offsetToStartOfCentralDirectory') + .word16lu('commentLength') + .vars; + + if (vars.commentLength) { + setImmediate(function () { + self._pullStream.pull(vars.commentLength, function (err, comment) { + if (err) { + return self.emit('error', err); + } + comment = comment.toString('utf8'); + return self._pullStream.end(); + }); + }); + + } else { + self._pullStream.end(); + } + }); +}; + +Parse.prototype._transform = function (chunk, encoding, callback) { + if (this._pullStream.write(chunk)) { + return callback(); + } + + this._pullStream.once('drain', callback); +}; + +Parse.prototype.pipe = function (dest, opts) { + var self = this; + if (typeof dest.add === "function") { + self.on("entry", function (entry) { + dest.add(entry); + }) + } + return Transform.prototype.pipe.apply(this, arguments); +}; + +Parse.prototype._flush = function (callback) { + if (!this._streamEnd || !this._streamFinish) { + return setImmediate(this._flush.bind(this, callback)); + } + + this.emit('close'); + return callback(); +}; + +Parse.prototype.addListener = function (type, listener) { + if ('entry' === type) { + this._hasEntryListener = true; + } + return Transform.prototype.addListener.call(this, type, listener); +}; + +Parse.prototype.on = Parse.prototype.addListener; diff --git a/freesun/tools/unzip/unzip.js b/freesun/tools/unzip/unzip.js new file mode 100644 index 0000000..f58bf06 --- /dev/null +++ b/freesun/tools/unzip/unzip.js @@ -0,0 +1,4 @@ +'use strict'; + +exports.Parse = require('./lib/parse'); +exports.Extract = require('./lib/extract'); \ No newline at end of file diff --git a/freesun/tools/wmic.js b/freesun/tools/wmic.js new file mode 100644 index 0000000..347506d --- /dev/null +++ b/freesun/tools/wmic.js @@ -0,0 +1,72 @@ +/** + * Created by rain on 2015/8/23. -- copy form ms-wmic https://github.com/mjhasbach/node-ms-wmic + */ +/*jslint node:true */ +/*jslint nomen:true */ +/*jslint stupid:true */ +'use strict'; +var csv = require('csv'), + _ = require('lodash'), + exec = require('child_process').exec; +var parseOuput = function (err, stdOut, cb) { + if (err) { + cb(err, [], stdOut); + return; + } + csv.parse(stdOut.replace(/\r\r/g, '\n'), {columns: true, relax: true}, function (err, rows) { + cb(err, rows, stdOut); + }); +}; +var wmic = { + execute: function (args, cb) { + if (!_.isFunction(cb)) { + cb = _.noop; + } + if (!_.isString(args)) { + cb(new TypeError('args must be a string')); + return wmic; + } + + exec('wmic ' + args, function (errIn, stdOut, stdErr) { + var err = errIn || stdErr.trim(); + + cb(err ? new Error(err + args) : null, stdOut.trim()); + }); + + return wmic; + }, + + path: { + get: function (obj, where, cb) { + if (_.isFunction(where)) { + cb = where; + } + if (!_.isFunction(cb)) { + throw new TypeError('cb must be a function'); + } + + wmic.execute('path ' + obj + ' ' + where + 'get * /format:csv', function (err, stdOut) { + parseOuput(err, stdOut, cb); + }); + + return wmic; + } + }, + process: { + list: function (where, cb) { + if (_.isFunction(where)) { + cb = where; + } + if (!_.isFunction(cb)) { + throw new TypeError('cb must be a function'); + } + + wmic.execute('process' + where + 'list /format:csv', function (err, stdOut) { + parseOuput(err, stdOut, cb); + }); + + return wmic; + } + } +}; +module.exports = wmic; \ No newline at end of file diff --git a/freesun/upgrade/copyutil.js b/freesun/upgrade/copyutil.js new file mode 100644 index 0000000..3e413fb --- /dev/null +++ b/freesun/upgrade/copyutil.js @@ -0,0 +1,293 @@ +/** + * Created by rain on 2015/8/27. + */ +/*jslint node:true */ +"use strict"; + +var Q = require('q'); +var fs = require('fs-extra'); +var path = require('path'); +var ustring = require('underscore.string'); + +var FlowStep = require('./flowStep').FlowStep; +var StepLog = require('./flowStep').StepLog; +var StepStatus = require('./flowStep').StepStatus; + +var CopyUtil = {}; + +var backup = function (flow, targetArray, desc) { + var deferred = Q.defer(), + flowStep, + stepLog, + targetDir; + flowStep = new FlowStep(ustring.sprintf('Backup %s.', desc)); + targetDir = flow.project.workspace.backup; + flow.service.newStep(flowStep); + flow.service.updateStep(flowStep, new StepLog('Begin...', 1, 'info')); + if (Array.isArray(targetArray)) { + targetArray.reduce(function (prev, next, i) { + return prev.then(function () { + stepLog = new StepLog(ustring.sprintf('%s backup: %s...', desc, next.name), 2, 'info'); + flow.service.updateStep(flowStep, stepLog); + var dir = path.join(targetDir, next.path); + return Q.nfcall(fs.emptyDir, dir) + .then(function () { + stepLog = new StepLog(ustring.sprintf('%s backup: copy %s to %s...', desc, next.absDir, dir), 2, 'info'); + flow.service.updateStep(flowStep, stepLog); + return Q.nfcall(fs.copy, next.absDir, dir); + }) + .then(function () { + flow.service.updateStep(flowStep, new StepLog(ustring.sprintf('%s backup: %s, done.', desc, next.name), 2, 'info')); + }); + }); + }, Q()).then(function () { + flow.service.updateStep(flowStep, new StepLog('End...', 1, 'info')); + flowStep.status = StepStatus.Success; + deferred.resolve(flow); + }).catch(function (err) { + stepLog = new StepLog(ustring.sprintf('Fail, reason: %s', err), 2, 'error'); + flowStep.status = StepStatus.Failed; + flow.service.updateStep(flowStep, stepLog); + deferred.reject(flow); + }); + } else { + flow.service.updateStep(flowStep, new StepLog('End...', 1, 'info')); + flowStep.status = StepStatus.Success; + deferred.resolve(flow); + } + return deferred.promise; +}; + +var deploy = function (flow, targetArray, targetDir, desc) { + var deferred = Q.defer(), + step = new FlowStep(ustring.sprintf('Deploy %s.', desc)), + sourceDir = flow.project.workspace.decompress; + flow.service.newStep(step); + flow.service.updateStep(step, new StepLog('Begin...', 1, 'info')); + targetArray.reduce(function (prev, next) { + return prev.then(function () { + flow.service.updateStep(step, new StepLog('deploying ' + next.name + '..', 2, 'info')); + var target = targetDir + '/' + next.path; + var source = sourceDir + '/' + next.path; + + return Q.nfcall(fs.emptyDir, target) + .then(function () { + return Q.nfcall(fs.copy, source, target); + }) + .then(function () { + flow.service.updateStep(step, new StepLog(next.name + 'deployed.', 2, 'info')); + return Q(); + }); + }); + }, Q()).then(function () { + step.status = StepStatus.Success; + flow.service.updateStep(step, new StepLog('End.', 1, 'info')); + deferred.resolve(flow); + }).catch(function (err) { + step.status = StepStatus.Failed; + flow.service.updateStep(step, new StepLog('Fail. reason:' + err, 1, 'error')); + deferred.reject(flow); + }); + + return deferred.promise; +}; + +var setup = function (flow, targetArray, targetDir, desc) { + var deferred = Q.defer(), + step = new FlowStep(ustring.sprintf('Setup %s.', desc)); + + flow.service.newStep(step); + flow.service.updateStep(step, new StepLog('Begin...', 1, 'info')); + targetArray.reduce(function (prev, p) { + return prev.then(function () { + var config = p.config; + + if (!config) { + flow.service.updateStep(step, new StepLog(p.name + ' has no config', 2, 'warn')); + return Q(); + } + flow.service.updateStep(step, new StepLog('setup ' + p.name + '..', 2, 'info')); + return config.reduce(function (prev, c) { + var configFile = path.join(targetDir, p.path, c.name); + var items = c.items; + if (!items) { + flow.service.updateStep(step, new StepLog('config:[' + c.name + '] has no item', 2, 'warn')); + return Q(); + } + + return Q.nfcall(fs.readFile, configFile + '.tmpl') + .then(function (data) { + items.forEach(function (it) { + while (data.toString().indexOf(it.key) !== -1) { + data = data.toString().replace(it.key, it.value); + } + }); + + return Q.nfcall(fs.writeFile, configFile, data); + }); + }, Q()).then(function () { + flow.service.updateStep(step, new StepLog('setup ' + p.name + ' completed.', 2, 'info')); + return Q(); + }); + }); + }, Q()).then(function () { + step.status = StepStatus.Success; + flow.service.updateStep(step, new StepLog('End...', 1, 'info')); + deferred.resolve(flow); + }).catch(function (err) { + step.status = StepStatus.Failed; + flow.service.updateStep(step, new StepLog('Fail. reason:' + err, 1, 'error')); + deferred.reject(flow); + }); + + return deferred.promise; +}; + +var migrate = function (flow, targetArray, targetDir, desc) { + var deferred = Q.defer(); + var step = new FlowStep(ustring.sprintf('Migrate %s.', desc)); + flow.service.newStep(step); + flow.service.updateStep(step, new StepLog('Begin...', 1, 'info')); + + var backup = flow.project.workspace.backup; + + var internalCopy = function (p, c) { + var source = path.join(backup, p.path, c.from); + var des = path.join(targetDir, p.path, c.to); + var copy = Q.denodeify(fs.copy); + return copy(source, des) + .then(function () { + flow.service.updateStep(step, new StepLog('copy ' + source + ' to ' + des + ' completed.', 2, 'info')); + return Q(); + }); + }; + + var internalMigrate = function (p) { + var copy = p.copy; + if (!copy) { + flow.service.updateStep(step, new StepLog(p.name + ' has no copy', 2, 'warn')); + return Q(); + } else { + flow.service.updateStep(step, new StepLog('migrate ' + p.name + '..', 2, 'info')); + return copy.reduce(function (prev, next) { + return prev.then(function () { + return internalCopy(p, next); + }); + }, Q()) + .then(function () { + flow.service.updateStep(step, new StepLog(p.name + ' migrate completed.', 2, 'info')); + return Q(); + }); + } + }; + + targetArray.reduce(function (prev, next) { + return prev.then(function () { + return internalMigrate(next); + }); + }, Q()).then(function () { + step.status = StepStatus.Success; + flow.service.updateStep(step, new StepLog('End...', 1, 'info')); + deferred.resolve(flow); + }).catch(function (err) { + step.status = StepStatus.Failed; + flow.service.updateStep(step, new StepLog('Fail. reason:' + err, 1, 'error')); + deferred.reject(flow); + }); + + return deferred.promise; +}; + +var restore = function (flow, targetArray, desc) { + var deferred = Q.defer(), + flowStep, + stepLog, + targetDir; + flowStep = new FlowStep(ustring.sprintf('Restore %s.', desc), 'warn'); + targetDir = flow.project.workspace.backup; + flow.service.newStep(flowStep); + flow.service.updateStep(flowStep, new StepLog('Begin...', 1, 'warn')); + + if (!flow.service.findStep(ustring.sprintf('Backup %s.', desc)) || flow.service.findStep(ustring.sprintf('Backup %s.', desc)).status !== StepStatus.Success) { + flowStep.status = StepStatus.Failed; + flow.service.updateStep(flowStep, new StepLog('skipped. reason: there is no backup found', 1, 'error')); + deferred.resolve(flow); + return; + } + + if (Array.isArray(targetArray)) { + targetArray.reduce(function (prev, next, i) { + return prev.then(function () { + stepLog = new StepLog(ustring.sprintf('%s restore: %s...', desc, next.name), 2, 'warn'); + flow.service.updateStep(flowStep, stepLog); + var dir = path.join(targetDir, next.path); + return Q.nfcall(fs.emptyDir, next.absDir) + .then(function () { + stepLog = new StepLog(ustring.sprintf('%s restore: copy %s to %s...', desc, dir, next.absDir), 2, 'warn'); + flow.service.updateStep(flowStep, stepLog); + return Q.nfcall(fs.copy, dir, next.absDir); + }) + .then(function () { + flow.service.updateStep(flowStep, new StepLog(ustring.sprintf('%s restore: %s, done.', desc, next.name), 2, 'warn')); + }); + }); + }, Q()).then(function () { + flow.service.updateStep(flowStep, new StepLog('End...', 1, 'warn')); + flowStep.status = StepStatus.Success; + deferred.resolve(flow); + }).catch(function (err) { + stepLog = new StepLog(ustring.sprintf('Fail, reason: %s', err), 2, 'error'); + flowStep.status = StepStatus.Failed; + flow.service.updateStep(flowStep, stepLog); + deferred.reject(flow); + }); + } else { + flow.service.updateStep(flowStep, new StepLog('End...', 1, 'warn')); + flowStep.status = StepStatus.Success; + deferred.resolve(flow); + } + return deferred.promise; +}; + + +CopyUtil.backupProcess = function (flow) { + return backup(flow, flow.project.process, 'Process'); +}; + +CopyUtil.backupWebServer = function (flow) { + return backup(flow, flow.project.webserver, 'WebServer'); +}; + +CopyUtil.deployWeb = function (flow) { + return deploy(flow, flow.project.webserver, flow.project.workspace.webDir, 'WebServer'); +}; + +CopyUtil.deployProcess = function (flow) { + return deploy(flow, flow.project.process, flow.project.workspace.processDir, 'Process'); +}; + +CopyUtil.setupWeb = function (flow) { + return setup(flow, flow.project.webserver, flow.project.workspace.webDir, 'WebServer'); +}; + +CopyUtil.setupProcess = function (flow) { + return setup(flow, flow.project.process, flow.project.workspace.processDir, 'Process'); +}; + +CopyUtil.migrateWeb = function (flow) { + return migrate(flow, flow.project.webserver, flow.project.workspace.webDir, 'WebServer'); +}; + +CopyUtil.migrateProcess = function (flow) { + return migrate(flow, flow.project.process, flow.project.workspace.processDir, 'Process'); +}; + +CopyUtil.restoreWeb = function (flow) { + return restore(flow, flow.project.webserver, 'WebServer'); +}; + +CopyUtil.restoreProcess = function (flow) { + return restore(flow, flow.project.process, 'Process'); +}; + +module.exports = CopyUtil; \ No newline at end of file diff --git a/freesun/upgrade/database.js b/freesun/upgrade/database.js new file mode 100644 index 0000000..e76729e --- /dev/null +++ b/freesun/upgrade/database.js @@ -0,0 +1,154 @@ +/** + * Created by rain on 2015/8/20. + */ +/*jslint node:true */ +"use strict"; +var Q = require('q'); +var path = require('path'); +var fs = require('fs'); +var extend = require('underscore').extend; +var utring = require('underscore.string'); +var uuid = require('node-uuid'); + +var sqlcmd = require('../tools/sqlcmd'); +var FlowStep = require('./flowStep').FlowStep; +var StepLog = require('./flowStep').StepLog; +var StepStatus = require('./flowStep').StepStatus; + +function Database() { +} + +var backup = function (flow) { + var sqlCmd = flow.project.sqlCmd, + backupOptions = extend({}, sqlCmd.loginTemplate, sqlCmd.queryTemplate), + deferred = Q.defer(), + targetFile = sqlCmd.backupDBFile, + flowStep, + stepLog; + if (sqlCmd.keepOldBackup) { + targetFile = path.join(path.dirname(targetFile), uuid.v4() + '.bak'); + flow.project.workspace.backupDBFile = targetFile; + } + flowStep = new FlowStep('Backup database.'); + flow.service.newStep(flowStep); + flow.service.updateStep(flowStep, new StepLog('Begin...', 1, 'info')); + backupOptions.query = utring.sprintf("BACKUP DATABASE [%s] TO DISK = '%s' WITH STATS=10", sqlCmd.loginTemplate.database, targetFile); + sqlcmd(backupOptions, function (data) { + stepLog = new StepLog(data, 2, 'info'); + flow.service.updateStep(flowStep, stepLog); + }).then( + function () { + stepLog = new StepLog('End...', 1, 'info'); + flowStep.status = StepStatus.Success; + flow.service.updateStep(flowStep, stepLog); + deferred.resolve(flow); + }, + function (err) { + stepLog = new StepLog('Fail. reason:' + err, 1, 'error'); + flowStep.status = StepStatus.Failed; + flow.service.updateStep(flowStep, stepLog); + deferred.reject(flow); + } + ); + return deferred.promise; +}; +Database.backup = backup; + +var restore = function (flow, check) { + var sqlCmd = flow.project.sqlCmd, + restoreOptions = extend({}, sqlCmd.loginTemplate, sqlCmd.queryTemplate), + deferred = Q.defer(), + flowStep, + stepLog, + dependStep, + targetFile = flow.project.workspace.backupDBFile; + flowStep = new FlowStep('Restore Database.', 'warn'); + flow.service.newStep(flowStep); + flow.service.updateStep(flowStep, new StepLog('Begin...', 1, 'warn')); + dependStep = flow.service.findStep('Execute sql scripts.'); + //change connect database when execute restore operation. + restoreOptions.database = 'master'; + if (check && dependStep && dependStep.status !== StepStatus.NotExecute) { + restoreOptions.query = utring.sprintf("RESTORE DATABASE [%s] FROM DISK = '%s' WITH STATS=10,REPLACE", sqlCmd.loginTemplate.database, targetFile); + sqlcmd(restoreOptions, function (data) { + stepLog = new StepLog(data, 2, 'info'); + flow.service.updateStep(flowStep, stepLog); + }).then( + function () { + stepLog = new StepLog('End...', 1, 'warn'); + flowStep.status = StepStatus.Success; + flow.service.updateStep(flowStep, stepLog); + deferred.resolve(flow); + }, + function (err) { + stepLog = new StepLog('Fail. reason:' + err, 1, 'error'); + flowStep.status = StepStatus.Failed; + flow.service.updateStep(flowStep, stepLog); + deferred.reject(flow); + } + ); + } else { + stepLog = new StepLog('End...', 1, 'warn'); + flowStep.status = StepStatus.Success; + flow.service.updateStep(flowStep, stepLog); + deferred.resolve(flow); + } + return deferred.promise; +}; +Database.restore = restore; + +var executeSqls = function (flow) { + var sqlCmd = flow.project.sqlCmd, + deferred = Q.defer(), + flowStep, + stepLog, + executeOptions = extend({}, sqlCmd.loginTemplate, sqlCmd.ioTemplate), + sqlFiles; + flowStep = new FlowStep('Execute sql scripts.'); + flow.service.newStep(flowStep); + flow.service.updateStep(flowStep, new StepLog('Begin...', 1, 'info')); + try { + sqlFiles = fs.readdirSync(sqlCmd.inputFiles); + } catch (err) { + stepLog = new StepLog('Error. reason:' + err, 1, 'warn'); + stepLog = new StepLog('End...', 1, 'info'); + flowStep.status = StepStatus.Success; + flow.service.updateStep(flowStep, stepLog); + deferred.resolve(flow); + return deferred.promise; + } + executeOptions.inputFiles = !sqlFiles ? [] : sqlFiles.filter(function (file) { + return path.extname(file) === '.sql'; + }).map(function (file) { + return path.join(sqlCmd.inputFiles, file); + }); + if (executeOptions.inputFiles && executeOptions.inputFiles.length > 0) { + executeOptions.outputFile = sqlCmd.outputFile; + sqlcmd(executeOptions, function (data) { + stepLog = new StepLog(data, 2, 'info'); + flow.service.updateStep(flowStep, stepLog); + }).then( + function () { + stepLog = new StepLog('End...', 1, 'info'); + flowStep.status = StepStatus.Success; + flow.service.updateStep(flowStep, stepLog); + deferred.resolve(flow); + }, + function (err) { + stepLog = new StepLog('Fail. reason:' + err, 1, 'error'); + flowStep.status = StepStatus.Failed; + flow.service.updateStep(flowStep, stepLog); + deferred.reject(flow); + } + ); + } else { + stepLog = new StepLog('End...', 1, 'info'); + flowStep.status = StepStatus.Success; + flow.service.updateStep(flowStep, stepLog); + deferred.resolve(flow); + } + return deferred.promise; +}; +Database.executeSqls = executeSqls; + +module.exports = Database; \ No newline at end of file diff --git a/freesun/upgrade/flowStep.js b/freesun/upgrade/flowStep.js new file mode 100644 index 0000000..a179b18 --- /dev/null +++ b/freesun/upgrade/flowStep.js @@ -0,0 +1,39 @@ +/** + * Created by liuxinyi on 2015/8/26. + */ +/*jslint node:true */ +"use strict"; +var ustring = require('underscore.string'); +function FlowStep(name, logLevel) { + this.name = name; + this.status = 0; + if (logLevel) { + this.logLevel = logLevel; + } else { + this.logLevel = 'info'; + } + this.logs = []; +} + +function StepLog(msg, level, logLevel) { + this.msg = msg; + this.level = level; + this.logLevel = logLevel; + this.time = (function () { + var now = new Date(); + return ustring.sprintf('%s-%s-%s %s-%s-%s', now.getFullYear(), now.getMonth() + 1, + now.getDate(), now.getHours(), now.getMinutes(), now.getSeconds()); + }()); +} + +var StepStatus = { + Failed: -1, + NotExecute: 0, + Success: 1 +}; + +module.exports = { + FlowStep: FlowStep, + StepLog: StepLog, + StepStatus: StepStatus +}; \ No newline at end of file diff --git a/freesun/upgrade/process.js b/freesun/upgrade/process.js new file mode 100644 index 0000000..3afb825 --- /dev/null +++ b/freesun/upgrade/process.js @@ -0,0 +1,73 @@ +/** + * Created by liuxinyi on 2015/8/25. + */ +/*jslint node:true */ +"use strict"; +var fs = require('fs-extra'); +var exec = require('child_process').exec; +var Q = require('q'); +var ustring = require('underscore.string'); +var path = require('path'); + +var Process = require('../models/process'); +var FlowStep = require('./flowStep').FlowStep; +var StepLog = require('./flowStep').StepLog; +var StepStatus = require('./flowStep').StepStatus; + +var ProcessUpdate = {}; + +ProcessUpdate.stop = function (flow) { + var deferred = Q.defer(), + flowStep, + stepLog, + proj = flow.project; + flowStep = new FlowStep('Stop process.'); + flow.service.newStep(flowStep); + flow.service.updateStep(flowStep, new StepLog('Begin...', 1, 'info')); + proj.process.reduce(function (prev, next) { + return prev.then(function () { + stepLog = new StepLog(ustring.sprintf('Stop process: %s', next.name), 2, 'info'); + flow.service.updateStep(flowStep, stepLog); + return next.toggle(0, true); + }); + }, Process.getRuntimeInfo(proj.process)).then(function () { + flow.service.updateStep(flowStep, new StepLog('End...', 1, 'info')); + flowStep.status = StepStatus.Success; + deferred.resolve(flow); + }).catch(function (err) { + stepLog = new StepLog(ustring.sprintf('Fail, reason: %s', err), 1, 'error'); + flowStep.status = StepStatus.Failed; + flow.service.updateStep(flowStep, stepLog); + deferred.reject(flow); + }); + return deferred.promise; +}; + +ProcessUpdate.start = function (flow) { + var deferred = Q.defer(), + flowStep, + stepLog, + proj = flow.project; + flowStep = new FlowStep('Start process.'); + flow.service.newStep(flowStep); + flow.service.updateStep(flowStep, new StepLog('Begin...', 1, 'info')); + proj.process.reduce(function (prev, next) { + return prev.then(function () { + stepLog = new StepLog(ustring.sprintf('Start process: %s', next.name), 2, 'info'); + flow.service.updateStep(flowStep, stepLog); + return next.toggle(1); + }); + }, Process.getRuntimeInfo(proj.process)).then(function () { + flow.service.updateStep(flowStep, new StepLog('End...', 1, 'info')); + flowStep.status = StepStatus.Success; + deferred.resolve(flow); + }).catch(function (err) { + stepLog = new StepLog(ustring.sprintf('fail, reason: %s', err), 1, 'error'); + flowStep.status = StepStatus.Failed; + flow.service.updateStep(flowStep, stepLog); + deferred.reject(flow); + }); + return deferred.promise; +}; + +module.exports = ProcessUpdate; \ No newline at end of file diff --git a/freesun/upgrade/webserver.js b/freesun/upgrade/webserver.js new file mode 100644 index 0000000..6276ee8 --- /dev/null +++ b/freesun/upgrade/webserver.js @@ -0,0 +1,92 @@ +/** + * Created by rain on 2015/8/26. + */ +/*jslint node:true */ +"use strict"; + +var Q = require('q'); +var path = require('path'); +var ustring = require('underscore.string'); +var uuid = require('node-uuid'); + +var iis = require('../tools/iis'); +var FlowStep = require('./flowStep').FlowStep; +var StepLog = require('./flowStep').StepLog; +var StepStatus = require('./flowStep').StepStatus; + + +function WebUpdate() { +} + +var templateFunc = function (iisOp, flow, desc) { + var deferred = Q.defer(), + flowStep, + stepLog, + proj = flow.project; + if (typeof iisOp !== 'function') { + deferred.reject(ustring.sprintf('Operator %s is not a function', iisOp.toString())); + } + flowStep = new FlowStep(ustring.sprintf('%s.', desc)); + flow.service.newStep(flowStep); + flow.service.updateStep(flowStep, new StepLog('Begin...', 1, 'info')); + proj.webserver.reduce(function (prev, next, i) { + return prev.then(function () { + stepLog = new StepLog(ustring.sprintf('%s: %s', desc, JSON.stringify(next)), 2, 'info'); + flow.service.updateStep(flowStep, stepLog); + var func = Q.nbind(iisOp, iis); + return func(next); + }); + }, Q()).then(function () { + flow.service.updateStep(flowStep, new StepLog('End...', 1, 'info')); + flowStep.status = StepStatus.Success; + deferred.resolve(flow); + }).catch(function (err) { + stepLog = new StepLog(ustring.sprintf('Fail, reason: %s', err), 1, 'error'); + flowStep.status = StepStatus.Failed; + flow.service.updateStep(flowStep, stepLog); + deferred.reject(flow); + }); + return deferred.promise; +}; + +var stop = function (flow) { + return templateFunc(iis.stopSite, flow, 'Stop web server'); +}; +WebUpdate.stop = stop; + +var deletee = function (flow) { + return templateFunc(iis.deleteSite, flow, 'Delete web server'); +}; +WebUpdate.deletee = deletee; + +var create = function (flow) { + return templateFunc(iis.createSite, flow, 'Create web server'); +}; +WebUpdate.create = create; + +var start = function (flow) { + return templateFunc(iis.startSite, flow, 'Start web server'); +}; +WebUpdate.start = start; + +var deleteePool = function (flow) { + return templateFunc(iis.deleteAppPool, flow, 'Delete app pool'); +}; +WebUpdate.deleteePool = deleteePool; + +var stopAppPool = function (flow) { + return templateFunc(iis.stopAppPool, flow, 'Stop app pool'); +}; +WebUpdate.stopAppPool = stopAppPool; + +var createPool = function (flow) { + return templateFunc(iis.createAppPool, flow, 'Create app pool'); +}; +WebUpdate.createPool = createPool; + +var mapAppPool = function (flow) { + return templateFunc(iis.mapAppPool, flow, 'Map app pool'); +}; +WebUpdate.mapAppPool = mapAppPool; + +module.exports = WebUpdate; \ No newline at end of file diff --git a/karma.conf.js b/karma.conf.js new file mode 100644 index 0000000..9240567 --- /dev/null +++ b/karma.conf.js @@ -0,0 +1,65 @@ +// Karma configuration +// Generated on Mon Aug 10 2015 12:46:33 GMT+0800 (中国标准时间) + +module.exports = function(config) { + config.set({ + + // base path that will be used to resolve all patterns (eg. files, exclude) + basePath: '', + + + // frameworks to use + // available frameworks: https://npmjs.org/browse/keyword/karma-adapter + frameworks: ['jasmine'], + + + // list of files / patterns to load in the browser + files: [ + {pattern: 'spec/**/*Spec.js', included: true} + ], + + + // list of files to exclude + exclude: [ + ], + + + // preprocess matching files before serving them to the browser + // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor + preprocessors: { + }, + + + // test results reporter to use + // possible values: 'dots', 'progress' + // available reporters: https://npmjs.org/browse/keyword/karma-reporter + reporters: ['progress'], + + + // web server port + port: 9876, + + + // enable / disable colors in the output (reporters and logs) + colors: true, + + + // level of logging + // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG + logLevel: config.LOG_INFO, + + + // enable / disable watching file and executing tests whenever any file changes + autoWatch: true, + + + // start these browsers + // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher + browsers: ['Chrome'], + + + // Continuous Integration mode + // if true, Karma captures browsers, runs the tests and exits + singleRun: true + }) +} diff --git a/locales/en.json b/locales/en.json new file mode 100644 index 0000000..fe839b5 --- /dev/null +++ b/locales/en.json @@ -0,0 +1,3 @@ +{ + "无效的用户名或密码.": "无效的用户名或密码." +} \ No newline at end of file diff --git a/locales/zh_CN.json b/locales/zh_CN.json new file mode 100644 index 0000000..9e26dfe --- /dev/null +++ b/locales/zh_CN.json @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..da0e407 --- /dev/null +++ b/package.json @@ -0,0 +1,88 @@ +{ + "name": "win32-deploy-tool", + "version": "1.0.0", + "description": "Deploy tool for win32 environment, manage project as processes and web serveres. Can monitor the processes and web serveres status(running cpu mem...).", + "main": "bin/www", + "bin": { + "win32-deploy-tool": "json.js" + }, + "dependencies": { + "bcrypt-nodejs": "^0.0.3", + "binary": "^0.3.0", + "body-parser": "^1.14.1", + "connect-flash": "^0.1.1", + "cookie-parser": "^1.4.0", + "css-loader": "^0.15.6", + "csv": "^0.4.6", + "debug": "^2.2.0", + "express-session": "^1.12.0", + "express": "^4.13.3", + "formidable": "^1.0.17", + "fstream": "^0.1.31", + "gaze": "^0.5.2", + "fs-extra": "^0.26.0", + "iconv-lite": "^0.4.13", + "i18n": "^0.5.0", + "inherits": "^2.0.1", + "jade": "^1.11.0", + "jasmine-core": "^2.3.4", + "jsx-loader": "^0.13.2", + "karma-chrome-launcher": "^0.2.1", + "karma-coverage": "^0.5.3", + "karma-jasmine": "^0.3.6", + "karma-webpack": "^1.7.0", + "lodash": "^3.10.1", + "match-stream": "^0.0.2", + "moment": "^2.10.6", + "morgan": "^1.6.1", + "ms": "^0.7.1", + "node-uuid": "^1.4.3", + "passport": "^0.3.0", + "pullstream": "^0.4.1", + "passport-local": "^1.0.0", + "q": "^1.4.1", + "react": "^0.13.3", + "react-dropzone": "^1.3.0", + "react-router": "^0.13.4", + "readable-stream": "^1.0.33", + "serve-favicon": "^2.3.0", + "setimmediate": "^1.0.4", + "style-loader": "^0.12.4", + "statuses": "^1.2.1", + "superagent": "^1.4.0", + "sweetalert": "^1.1.3", + "underscore": "^1.8.3", + "webpack": "^1.12.2", + "unpipe": "^1.0.0", + "winston": "^1.1.1", + "underscore.string": "^3.2.2", + "ws": "^0.8.0", + "xml2js": "^0.4.13" + }, + "devDependencies": {}, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "https://github.com/novrain/win32-deploy-tool.git" + }, + "keywords": [ + "node", + "npm", + "deploy", + "install", + "update", + "multi", + "process", + "web", + "manager", + "win32" + ], + "author": "tyr novrain", + "license": "MIT", + "bugs": { + "url": "https://github.com/novrain/win32-deploy-tool/issues" + }, + "homepage": "https://github.com/novrain/win32-deploy-tool" +} diff --git a/routes/auth.js b/routes/auth.js new file mode 100644 index 0000000..d0e64d8 --- /dev/null +++ b/routes/auth.js @@ -0,0 +1,23 @@ +/** + * Created by rain on 2015/8/6. + */ +/*jslint node:true */ +/*jslint nomen:true */ +'use strict'; +var Auth = {}; +var Q = require('q'); + +Auth.isAuthenticated = function (req, res) { + var deferred = Q.defer(); + + if (req.isAuthenticated()) { + deferred.resolve(); + } else { + res.statusCode = 401; + res.end('Unauthenticated'); + } + + return deferred.promise; +}; + +module.exports = Auth; \ No newline at end of file diff --git a/routes/index.js b/routes/index.js new file mode 100644 index 0000000..96ea451 --- /dev/null +++ b/routes/index.js @@ -0,0 +1,12 @@ +/*jslint node:true */ +/*jslint nomen:true */ +'use strict'; +var express = require('express'); +var router = express.Router(); + +/* GET home page. */ +router.get('/', function (req, res, next) { + res.render('index'); +}); + +module.exports = router; diff --git a/routes/login.js b/routes/login.js new file mode 100644 index 0000000..32f7d47 --- /dev/null +++ b/routes/login.js @@ -0,0 +1,23 @@ +/** + * Created by rain on 2015/8/5. + */ +/*jslint node:true */ +/*jslint nomen:true */ +'use strict'; +var passport = require('passport'); +var express = require('express'); +var router = express.Router(); + +/** + * base route /login + */ +router.get('/', function (req, res, next) { + res.render('login'); +}); + +router.post('/', passport.authenticate('login', { + successRedirect: '/', + failureRedirect: '/login' +})); + +module.exports = router; \ No newline at end of file diff --git a/routes/process.js b/routes/process.js new file mode 100644 index 0000000..e1c9101 --- /dev/null +++ b/routes/process.js @@ -0,0 +1,31 @@ +/** + * Created by rain on 2015/8/7. + */ +/*jslint node:true */ +/*jslint nomen:true */ +'use strict'; +var express = require('express'); +var router = express.Router(); +var Project = require('../freesun/models/project'); +var Auth = require('./auth'); + +router.post('/toggle', function (req, res) { + Auth.isAuthenticated(req, res) + .then(function () { + var pjid = req.body.pjid; + var pid = req.body.id; + var cmd = Number(req.body.cmd); + + var pr = Project.findProcessById(pjid, pid); + if (pr == null) { + res.end('process not found'); + } + pr.toggle(cmd, true).then(function (r) { + res.end(JSON.stringify({res: true, msg: r})); + }, function (r) { + res.end(JSON.stringify({res: false, msg: r})); + }); + }); +}); + +module.exports = router; \ No newline at end of file diff --git a/routes/project.js b/routes/project.js new file mode 100644 index 0000000..eeb8234 --- /dev/null +++ b/routes/project.js @@ -0,0 +1,40 @@ +/** + * Created by rain on 2015/9/7. + */ +/*jslint node:true */ +/*jslint nomen:true */ +'use strict'; +var express = require('express'); +var router = express.Router(); +var Project = require('../freesun/models/project'); +var config = require('../freesun/env/config'); +var Auth = require('./auth'); + +router.get('/list', function (req, res, next) { + res.send(Project.all()); +}); + +router.delete('/delete/:id', function (req, res, next) { + Auth.isAuthenticated(req, res) + .then(function () { + res.end(JSON.stringify({result: Project.deleteById(req.params.id)})); + }); +}); + +router.post('/watch/switch', function (req, res, next) { + Auth.isAuthenticated(req, res) + .then(function () { + if (config.project.watch) { + Project.watchSwitch(); + res.end(JSON.stringify({result: true})); + } else { + res.end(JSON.stringify({result: false})); + } + }); +}); + +router.get('/watch/state', function (req, res, next) { + res.end(JSON.stringify({result: Project.watch()})); +}); + +module.exports = router; \ No newline at end of file diff --git a/routes/upgrade.js b/routes/upgrade.js new file mode 100644 index 0000000..1b9fb60 --- /dev/null +++ b/routes/upgrade.js @@ -0,0 +1,15 @@ +/** + * Created by liuxinyi on 2015/8/25. + */ +/*jslint node:true */ +/*jslint nomen:true */ +'use strict'; +var express = require('express'); +var router = express.Router(); + +router.get('/status', function (req, res) { + var us = req.app.get('fs.update.service'); + res.end(JSON.stringify({isUpdating: us.status()})); +}); + +module.exports = router; \ No newline at end of file diff --git a/routes/upload.js b/routes/upload.js new file mode 100644 index 0000000..ff80060 --- /dev/null +++ b/routes/upload.js @@ -0,0 +1,50 @@ +/** + * Created by liuxinyi on 2015/8/24. + */ +/*jslint node:true */ +/*jslint nomen:true */ +'use strict'; +var express = require('express'); +var fs = require('fs'); +var formidable = require('formidable'); +var router = express.Router(); +var Auth = require('./auth'); + +router.post('/package', function (req, res) { + Auth.isAuthenticated(req, res) + .then(function () { + var form = new formidable.IncomingForm; + form.uploadDir = './uploads'; + form.keepExtensions = true; + form.parse(req, function (err, fields, files) { + if (err != null) { + res.end(JSON.stringify({res: false, msg: err})); + return; + } + + var pkg = files[0]; + if (pkg.type !== 'application/x-zip-compressed') { + res.end(JSON.stringify({res: false, msg: '只支持zip格式文件'})); + } else { + var fileName = pkg.path + '.zip'; + try { + fs.renameSync(pkg.path, fileName); + var us = req.app.get('fs.update.service'); + var pjid = req.query.pjid; + if (pjid === '-1') {// install + us.install(fs.realpathSync(fileName)); + } else if (pjid === '-2') { + us.selfUpdate(fs.realpathSync(fileName)); + } else { + us.update(pjid, fs.realpathSync(fileName)); + } + res.end(JSON.stringify({res: true, msg: fileName})); + } catch (e) { + res.end(JSON.stringify({res: false, msg: e.message})); + } + } + }); + }); +}); + +module.exports = router; \ No newline at end of file diff --git a/routes/webserver.js b/routes/webserver.js new file mode 100644 index 0000000..f252a3c --- /dev/null +++ b/routes/webserver.js @@ -0,0 +1,35 @@ +/** + * Created by liuxinyi on 2015/9/1. + */ +/*jslint node:true */ +/*jslint nomen:true */ +'use strict'; +var express = require('express'); +var router = express.Router(); +var Q = require('q'); +var iis = require('../freesun/tools/iis'); +var Project = require('../freesun/models/project'); +var Auth = require('./auth'); + +router.post('/toggle', function (req, res) { + Auth.isAuthenticated(req, res) + .then(function () { + var pjid = req.body.pjid; + var id = req.body.id; + var cmd = Number(req.body.cmd); + + var site = Project.findWebServerById(pjid, id); + if (site == null) { + res.end(JSON.stringify({res: true, msg: 'web server not found'})); + return; + } + site.toggle(cmd, false) + .then(function (r) { + res.end(JSON.stringify({res: true, msg: site.name + (cmd === 1 ? ' started.' : ' stopped')})); + }, function (err) { + res.end(JSON.stringify({res: false, msg: err})); + }); + }); +}); + +module.exports = router; \ No newline at end of file diff --git a/static/README.md b/static/README.md new file mode 100644 index 0000000..b3594dc --- /dev/null +++ b/static/README.md @@ -0,0 +1,10 @@ +## +1. ʹCommonJS淶Webpack +2. װ `npm install -g webpack`, ʹ`webpack`ɵ`javascripts/build`Ŀ¼ + + +## +1. ʹJasmineԪ +2. Դλ`javascripts/__test__` +3. װ`npm install -g karma-cli`,ʹ`karma start`еԪ +4. 븲ڸĿ¼`fe-coverage` \ No newline at end of file diff --git a/static/favicon.ico b/static/favicon.ico new file mode 100644 index 0000000..4a51f2e Binary files /dev/null and b/static/favicon.ico differ diff --git a/static/images/loading.gif b/static/images/loading.gif new file mode 100644 index 0000000..529198a Binary files /dev/null and b/static/images/loading.gif differ diff --git a/static/images/logo-mini.png b/static/images/logo-mini.png new file mode 100644 index 0000000..4a50a47 Binary files /dev/null and b/static/images/logo-mini.png differ diff --git a/static/images/logo.png b/static/images/logo.png new file mode 100644 index 0000000..3d8a8ec Binary files /dev/null and b/static/images/logo.png differ diff --git a/static/images/tips.png b/static/images/tips.png new file mode 100644 index 0000000..4f348f1 Binary files /dev/null and b/static/images/tips.png differ diff --git a/static/javascripts/__tests__/Project.test.js b/static/javascripts/__tests__/Project.test.js new file mode 100644 index 0000000..a6883fb --- /dev/null +++ b/static/javascripts/__tests__/Project.test.js @@ -0,0 +1,29 @@ +/** + * Created by liuxinyi on 2015/8/10. + */ +var React = require('react/addons'); +var Project = require('../src/components/Project.js'); +var TestUtils = React.addons.TestUtils; + +describe('component:Project', function() { + it('display name through props', function(){ + var dom = TestUtils.renderIntoDocument( + + ); + + var tip = TestUtils.findRenderedDOMComponentWithClass(dom, 'page-header'); + + expect(tip.getDOMNode().getElementsByTagName('span')[0].innerText).toEqual('test'); + }); + + it('display tips when inited', function() { + var dom = TestUtils.renderIntoDocument( + + ); + + var title = TestUtils.findRenderedDOMComponentWithClass(dom, 'text-yellow'); + + expect(title.getDOMNode().textContent).toEqual('进程信息读取中..'); + + }); +}); \ No newline at end of file diff --git a/static/javascripts/build/index.js b/static/javascripts/build/index.js new file mode 100644 index 0000000..a70ff55 --- /dev/null +++ b/static/javascripts/build/index.js @@ -0,0 +1,29243 @@ +/******/ (function(modules) { // webpackBootstrap +/******/ // 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 +/******/ }; + +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); + +/******/ // 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 = ""; + +/******/ // Load entry module and return exports +/******/ return __webpack_require__(0); +/******/ }) +/************************************************************************/ +/******/ ([ +/* 0 */ +/***/ function(module, exports, __webpack_require__) { + + /** + * Created by liuxinyi on 2015/8/5. + */ + var React = __webpack_require__(1); + var Router = __webpack_require__(157); + var Projects = __webpack_require__(196); + var ProjectUpgrade = __webpack_require__(216); + var NotFound = __webpack_require__(219); + var LogView = __webpack_require__(220); + + var Route = Router.Route; + var NotFoundRoute = Router.NotFoundRoute; + + var routes = ( + React.createElement(Route, null, + React.createElement(Route, {path: "/", handler: Projects}), + React.createElement(Route, {path: "upgrade/:pjid", handler: ProjectUpgrade}), + React.createElement(Route, {path: "log/:file", handler: LogView}), + + React.createElement(NotFoundRoute, {handler: NotFound}) + ) + ); + + Router.run(routes, function(Root) { + React.render(React.createElement(Root, null), document.getElementById('main')); + }); + +/***/ }, +/* 1 */ +/***/ function(module, exports, __webpack_require__) { + + module.exports = __webpack_require__(2); + + +/***/ }, +/* 2 */ +/***/ 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__(4); + var ReactChildren = __webpack_require__(8); + var ReactComponent = __webpack_require__(22); + var ReactClass = __webpack_require__(37); + var ReactContext = __webpack_require__(12); + var ReactCurrentOwner = __webpack_require__(17); + var ReactElement = __webpack_require__(11); + var ReactElementValidator = __webpack_require__(32); + var ReactDOM = __webpack_require__(40); + var ReactDOMTextComponent = __webpack_require__(42); + var ReactDefaultInjection = __webpack_require__(91); + var ReactInstanceHandles = __webpack_require__(19); + var ReactMount = __webpack_require__(67); + var ReactPerf = __webpack_require__(28); + var ReactPropTypes = __webpack_require__(122); + var ReactReconciler = __webpack_require__(29); + var ReactServerRendering = __webpack_require__(154); + + var assign = __webpack_require__(13); + var findDOMNode = __webpack_require__(111); + var onlyChild = __webpack_require__(156); + + 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__(51); + 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__(3))) + +/***/ }, +/* 3 */ +/***/ 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; }; + + +/***/ }, +/* 4 */ +/***/ 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__(5); + + var invariant = __webpack_require__(7); + + /** + * 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__(3))) + +/***/ }, +/* 5 */ +/***/ 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__(6); + + 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; + + +/***/ }, +/* 6 */ +/***/ 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__(7); + + /** + * 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__(3))) + +/***/ }, +/* 7 */ +/***/ 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__(3))) + +/***/ }, +/* 8 */ +/***/ 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__(9); + var ReactFragment = __webpack_require__(10); + + var traverseAllChildren = __webpack_require__(18); + var warning = __webpack_require__(15); + + 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__(3))) + +/***/ }, +/* 9 */ +/***/ 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__(7); + + /** + * 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__(3))) + +/***/ }, +/* 10 */ +/***/ 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__(11); + + var warning = __webpack_require__(15); + + /** + * 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__(3))) + +/***/ }, +/* 11 */ +/***/ 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__(12); + var ReactCurrentOwner = __webpack_require__(17); + + var assign = __webpack_require__(13); + var warning = __webpack_require__(15); + + 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__(3))) + +/***/ }, +/* 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 ReactContext + */ + + 'use strict'; + + var assign = __webpack_require__(13); + var emptyObject = __webpack_require__(14); + var warning = __webpack_require__(15); + + 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__(3))) + +/***/ }, +/* 13 */ +/***/ 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; + + +/***/ }, +/* 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 emptyObject + */ + + "use strict"; + + var emptyObject = {}; + + if ("production" !== process.env.NODE_ENV) { + Object.freeze(emptyObject); + } + + module.exports = emptyObject; + + /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(3))) + +/***/ }, +/* 15 */ +/***/ 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__(16); + + /** + * 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__(3))) + +/***/ }, +/* 16 */ +/***/ 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; + + +/***/ }, +/* 17 */ +/***/ 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; + + +/***/ }, +/* 18 */ +/***/ 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__(11); + var ReactFragment = __webpack_require__(10); + var ReactInstanceHandles = __webpack_require__(19); + + var getIteratorFn = __webpack_require__(21); + var invariant = __webpack_require__(7); + var warning = __webpack_require__(15); + + 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__(3))) + +/***/ }, +/* 19 */ +/***/ 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__(20); + + var invariant = __webpack_require__(7); + + 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__(3))) + +/***/ }, +/* 20 */ +/***/ 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; + + +/***/ }, +/* 21 */ +/***/ 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; + + +/***/ }, +/* 22 */ +/***/ 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__(23); + + var invariant = __webpack_require__(7); + var warning = __webpack_require__(15); + + /** + * 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__(3))) + +/***/ }, +/* 23 */ +/***/ 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__(24); + var ReactCurrentOwner = __webpack_require__(17); + var ReactElement = __webpack_require__(11); + var ReactInstanceMap = __webpack_require__(25); + var ReactUpdates = __webpack_require__(26); + + var assign = __webpack_require__(13); + var invariant = __webpack_require__(7); + var warning = __webpack_require__(15); + + 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__(3))) + +/***/ }, +/* 24 */ +/***/ 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; + + +/***/ }, +/* 25 */ +/***/ 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; + + +/***/ }, +/* 26 */ +/***/ 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__(27); + var PooledClass = __webpack_require__(9); + var ReactCurrentOwner = __webpack_require__(17); + var ReactPerf = __webpack_require__(28); + var ReactReconciler = __webpack_require__(29); + var Transaction = __webpack_require__(36); + + var assign = __webpack_require__(13); + var invariant = __webpack_require__(7); + var warning = __webpack_require__(15); + + 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__(3))) + +/***/ }, +/* 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 CallbackQueue + */ + + 'use strict'; + + var PooledClass = __webpack_require__(9); + + var assign = __webpack_require__(13); + var invariant = __webpack_require__(7); + + /** + * 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__(3))) + +/***/ }, +/* 28 */ +/***/ 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__(3))) + +/***/ }, +/* 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 ReactReconciler + */ + + 'use strict'; + + var ReactRef = __webpack_require__(30); + var ReactElementValidator = __webpack_require__(32); + + /** + * 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__(3))) + +/***/ }, +/* 30 */ +/***/ 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__(31); + + 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; + + +/***/ }, +/* 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 ReactOwner + */ + + 'use strict'; + + var invariant = __webpack_require__(7); + + /** + * 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__(3))) + +/***/ }, +/* 32 */ +/***/ 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__(11); + var ReactFragment = __webpack_require__(10); + var ReactPropTypeLocations = __webpack_require__(33); + var ReactPropTypeLocationNames = __webpack_require__(34); + var ReactCurrentOwner = __webpack_require__(17); + var ReactNativeComponent = __webpack_require__(35); + + var getIteratorFn = __webpack_require__(21); + var invariant = __webpack_require__(7); + var warning = __webpack_require__(15); + + 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__(3))) + +/***/ }, +/* 33 */ +/***/ 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__(6); + + var ReactPropTypeLocations = keyMirror({ + prop: null, + context: null, + childContext: null + }); + + module.exports = ReactPropTypeLocations; + + +/***/ }, +/* 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 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__(3))) + +/***/ }, +/* 35 */ +/***/ 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__(13); + var invariant = __webpack_require__(7); + + 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__(3))) + +/***/ }, +/* 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 Transaction + */ + + 'use strict'; + + var invariant = __webpack_require__(7); + + /** + * `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__(3))) + +/***/ }, +/* 37 */ +/***/ 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__(22); + var ReactCurrentOwner = __webpack_require__(17); + var ReactElement = __webpack_require__(11); + var ReactErrorUtils = __webpack_require__(38); + var ReactInstanceMap = __webpack_require__(25); + var ReactLifeCycle = __webpack_require__(24); + var ReactPropTypeLocations = __webpack_require__(33); + var ReactPropTypeLocationNames = __webpack_require__(34); + var ReactUpdateQueue = __webpack_require__(23); + + var assign = __webpack_require__(13); + var invariant = __webpack_require__(7); + var keyMirror = __webpack_require__(6); + var keyOf = __webpack_require__(39); + var warning = __webpack_require__(15); + + 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__(3))) + +/***/ }, +/* 38 */ +/***/ 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; + + +/***/ }, +/* 39 */ +/***/ 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; + + +/***/ }, +/* 40 */ +/***/ 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__(11); + var ReactElementValidator = __webpack_require__(32); + + var mapObject = __webpack_require__(41); + + /** + * 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__(3))) + +/***/ }, +/* 41 */ +/***/ 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; + + +/***/ }, +/* 42 */ +/***/ 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__(43); + var ReactComponentBrowserEnvironment = + __webpack_require__(47); + var ReactDOMComponent = __webpack_require__(87); + + var assign = __webpack_require__(13); + var escapeTextContentForBrowser = __webpack_require__(46); + + /** + * 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; + + +/***/ }, +/* 43 */ +/***/ 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__(44); + + var quoteAttributeValueForBrowser = __webpack_require__(45); + var warning = __webpack_require__(15); + + 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__(3))) + +/***/ }, +/* 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 DOMProperty + * @typechecks static-only + */ + + /*jslint bitwise: true */ + + 'use strict'; + + var invariant = __webpack_require__(7); + + 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__(3))) + +/***/ }, +/* 45 */ +/***/ 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__(46); + + /** + * 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; + + +/***/ }, +/* 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 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; + + +/***/ }, +/* 47 */ +/***/ 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__(48); + var ReactMount = __webpack_require__(67); + + /** + * 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; + + +/***/ }, +/* 48 */ +/***/ 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__(49); + var DOMChildrenOperations = __webpack_require__(58); + var DOMPropertyOperations = __webpack_require__(43); + var ReactMount = __webpack_require__(67); + var ReactPerf = __webpack_require__(28); + + var invariant = __webpack_require__(7); + var setInnerHTML = __webpack_require__(66); + + /** + * 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__(3))) + +/***/ }, +/* 49 */ +/***/ 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__(50); + var ExecutionEnvironment = __webpack_require__(51); + + var camelizeStyleName = __webpack_require__(52); + var dangerousStyleValue = __webpack_require__(54); + var hyphenateStyleName = __webpack_require__(55); + var memoizeStringOnly = __webpack_require__(57); + var warning = __webpack_require__(15); + + 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__(3))) + +/***/ }, +/* 50 */ +/***/ 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; + + +/***/ }, +/* 51 */ +/***/ 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; + + +/***/ }, +/* 52 */ +/***/ 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__(53); + + 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; + + +/***/ }, +/* 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 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; + + +/***/ }, +/* 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 dangerousStyleValue + * @typechecks static-only + */ + + 'use strict'; + + var CSSProperty = __webpack_require__(50); + + 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; + + +/***/ }, +/* 55 */ +/***/ 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__(56); + + 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; + + +/***/ }, +/* 56 */ +/***/ 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; + + +/***/ }, +/* 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 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; + + +/***/ }, +/* 58 */ +/***/ 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__(59); + var ReactMultiChildUpdateTypes = __webpack_require__(64); + + var setTextContent = __webpack_require__(65); + var invariant = __webpack_require__(7); + + /** + * 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__(3))) + +/***/ }, +/* 59 */ +/***/ 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__(51); + + var createNodesFromMarkup = __webpack_require__(60); + var emptyFunction = __webpack_require__(16); + var getMarkupWrap = __webpack_require__(63); + var invariant = __webpack_require__(7); + + 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__(3))) + +/***/ }, +/* 64 */ +/***/ 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__(6); + + /** + * 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; + + +/***/ }, +/* 65 */ +/***/ 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__(51); + var escapeTextContentForBrowser = __webpack_require__(46); + var setInnerHTML = __webpack_require__(66); + + /** + * 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; + + +/***/ }, +/* 66 */ +/***/ 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__(51); + + 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; + + +/***/ }, +/* 67 */ +/***/ 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__(44); + var ReactBrowserEventEmitter = __webpack_require__(68); + var ReactCurrentOwner = __webpack_require__(17); + var ReactElement = __webpack_require__(11); + var ReactElementValidator = __webpack_require__(32); + var ReactEmptyComponent = __webpack_require__(76); + var ReactInstanceHandles = __webpack_require__(19); + var ReactInstanceMap = __webpack_require__(25); + var ReactMarkupChecksum = __webpack_require__(77); + var ReactPerf = __webpack_require__(28); + var ReactReconciler = __webpack_require__(29); + var ReactUpdateQueue = __webpack_require__(23); + var ReactUpdates = __webpack_require__(26); + + var emptyObject = __webpack_require__(14); + var containsNode = __webpack_require__(79); + var getReactRootElementInContainer = __webpack_require__(82); + var instantiateReactComponent = __webpack_require__(83); + var invariant = __webpack_require__(7); + var setInnerHTML = __webpack_require__(66); + var shouldUpdateReactComponent = __webpack_require__(86); + var warning = __webpack_require__(15); + + 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__(3))) + +/***/ }, +/* 68 */ +/***/ 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__(5); + var EventPluginHub = __webpack_require__(69); + var EventPluginRegistry = __webpack_require__(70); + var ReactEventEmitterMixin = __webpack_require__(73); + var ViewportMetrics = __webpack_require__(74); + + var assign = __webpack_require__(13); + var isEventSupported = __webpack_require__(75); + + /** + * 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; + + +/***/ }, +/* 69 */ +/***/ 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__(70); + var EventPluginUtils = __webpack_require__(4); + + var accumulateInto = __webpack_require__(71); + var forEachAccumulated = __webpack_require__(72); + var invariant = __webpack_require__(7); + + /** + * 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__(3))) + +/***/ }, +/* 70 */ +/***/ 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__(7); + + /** + * 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__(3))) + +/***/ }, +/* 71 */ +/***/ 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__(7); + + /** + * + * 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__(3))) + +/***/ }, +/* 72 */ +/***/ 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; + + +/***/ }, +/* 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 ReactEventEmitterMixin + */ + + 'use strict'; + + var EventPluginHub = __webpack_require__(69); + + 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; + + +/***/ }, +/* 74 */ +/***/ 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; + + +/***/ }, +/* 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 isEventSupported + */ + + 'use strict'; + + var ExecutionEnvironment = __webpack_require__(51); + + 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; + + +/***/ }, +/* 76 */ +/***/ 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__(11); + var ReactInstanceMap = __webpack_require__(25); + + var invariant = __webpack_require__(7); + + 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__(3))) + +/***/ }, +/* 77 */ +/***/ 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__(78); + + 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; + + +/***/ }, +/* 78 */ +/***/ 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; + + +/***/ }, +/* 79 */ +/***/ 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__(80); + + /*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; + + +/***/ }, +/* 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 isTextNode + * @typechecks + */ + + var isNode = __webpack_require__(81); + + /** + * @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; + + +/***/ }, +/* 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 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; + + +/***/ }, +/* 82 */ +/***/ 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; + + +/***/ }, +/* 83 */ +/***/ 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__(84); + var ReactEmptyComponent = __webpack_require__(76); + var ReactNativeComponent = __webpack_require__(35); + + var assign = __webpack_require__(13); + var invariant = __webpack_require__(7); + var warning = __webpack_require__(15); + + // 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__(3))) + +/***/ }, +/* 84 */ +/***/ 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__(85); + var ReactContext = __webpack_require__(12); + var ReactCurrentOwner = __webpack_require__(17); + var ReactElement = __webpack_require__(11); + var ReactElementValidator = __webpack_require__(32); + var ReactInstanceMap = __webpack_require__(25); + var ReactLifeCycle = __webpack_require__(24); + var ReactNativeComponent = __webpack_require__(35); + var ReactPerf = __webpack_require__(28); + var ReactPropTypeLocations = __webpack_require__(33); + var ReactPropTypeLocationNames = __webpack_require__(34); + var ReactReconciler = __webpack_require__(29); + var ReactUpdates = __webpack_require__(26); + + var assign = __webpack_require__(13); + var emptyObject = __webpack_require__(14); + var invariant = __webpack_require__(7); + var shouldUpdateReactComponent = __webpack_require__(86); + var warning = __webpack_require__(15); + + 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__(3))) + +/***/ }, +/* 85 */ +/***/ 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__(7); + + 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__(3))) + +/***/ }, +/* 86 */ +/***/ 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__(15); + + /** + * 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__(3))) + +/***/ }, +/* 87 */ +/***/ 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__(49); + var DOMProperty = __webpack_require__(44); + var DOMPropertyOperations = __webpack_require__(43); + var ReactBrowserEventEmitter = __webpack_require__(68); + var ReactComponentBrowserEnvironment = + __webpack_require__(47); + var ReactMount = __webpack_require__(67); + var ReactMultiChild = __webpack_require__(88); + var ReactPerf = __webpack_require__(28); + + var assign = __webpack_require__(13); + var escapeTextContentForBrowser = __webpack_require__(46); + var invariant = __webpack_require__(7); + var isEventSupported = __webpack_require__(75); + var keyOf = __webpack_require__(39); + var warning = __webpack_require__(15); + + 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 
+                
+            
+        )
+    }
+});
\ No newline at end of file
diff --git a/static/javascripts/src/components/NotFound.js b/static/javascripts/src/components/NotFound.js
new file mode 100644
index 0000000..1d566f3
--- /dev/null
+++ b/static/javascripts/src/components/NotFound.js
@@ -0,0 +1,18 @@
+/**
+ * Created by liuxinyi on 2015/8/10.
+ */
+var React = require('react');
+var Link = require('react-router').Link;
+
+module.exports = React.createClass({
+    render: function(){
+        return (
+            

+ + 页面灰走了~~ +
+ 返回首页 +

+ ) + } +}); \ No newline at end of file diff --git a/static/javascripts/src/components/PerfChart.js b/static/javascripts/src/components/PerfChart.js new file mode 100644 index 0000000..c686c30 --- /dev/null +++ b/static/javascripts/src/components/PerfChart.js @@ -0,0 +1,37 @@ +/** + * Created by liuxinyi on 2015/8/20. + */ +var React = require('react'); +var sl = require('./SparkLines/index'); +var Sparklines = sl.Sparklines; +var SparklinesLine = sl.SparklinesLine; +var SparkLinesBars = sl.SparklinesBars; +var SparklinesSpots = sl.SparklinesSpots; +var SparklinesReferenceLine = sl.SparklinesReferenceLine; + +module.exports = React.createClass({ + getInitialState: function(){ + return {data: []}; + }, + componentWillReceiveProps : function(nextProp){ + this.setState({data: this.state.data.concat(nextProp.data)}); + }, + render: function () { + var content = ''; + if(this.props.type === 'line'){ + content = (); + }else if(this.props.type === 'bar'){ + content = (); + }else{ + content = (); + } + + return ( + + {content} + + + + ) + } +}); \ No newline at end of file diff --git a/static/javascripts/src/components/Process.js b/static/javascripts/src/components/Process.js new file mode 100644 index 0000000..1e39667 --- /dev/null +++ b/static/javascripts/src/components/Process.js @@ -0,0 +1,119 @@ +/** + * Created by liuxinyi on 2015/8/6. + */ +var React = require('react'); +var Navigation = require('react-router').Navigation; +var Link = require('react-router').Link; +require('sweetalert/dist/sweetalert.css'); +var swal = require('sweetalert'); +var ApiCaller = require('../utils/ApiCaller'); +var TimeUtil = require('../utils/TimeUtil'); +var UnitUtil = require('../utils/UnitUtil'); +var PerfChart = require('./PerfChart'); + +var dataStyle = { + fontSize: 24 +}; + +module.exports = React.createClass({ + mixins: [Navigation], + handleStartStop: function () { + var text = this.props.info.r[0].status === 1 ? "停止" : "启动"; + var self = this; + swal({ + title: "是否" + text + this.props.info.name + "?", + text: "", + type: "warning", + showCancelButton: true, + cancelButtonText: 'no', + confirmButtonColor: "#ffc66d", + confirmButtonText: "go!", + showLoaderOnConfirm: true, + closeOnConfirm: false + }, function () { + ApiCaller.post(ApiCaller.API.PROCESS_TOGGLE, { + pjid: self.props.projectId, + id: self.props.info.id, + cmd: self.props.info.r[0].status === 1 ? 0 : 1 + }) + .then(function (d) { + var icon = d.res === true ? "success" : "error"; + swal(d.msg, '', icon); + }); + }); + }, + handlePatch: function () { + //swal('请先登录','','info'); + this.transitionTo('/process/' + this.props.info.id); + }, + render: function () { + var btnToggle; + var titleClass; + var status; + var details; + var time = TimeUtil.MillisecondToDate(this.props.info.r[0].uptime); + + if (this.props.info.r[0].status === 1) { + btnToggle = ; + titleClass = 'text-success'; + status = ( +

运行时长:{time}

+ ); + details = ( +
+
CPU:{this.props.info.r[0].cpupec}%
+
+
MEM:{UnitUtil.Convert1024(this.props.info.r[0].memory)}({this.props.info.r[0].mempec}%) +
+
+
); + } else { + btnToggle = ; + titleClass = 'text-danger'; + status = ( +

未启动

+ ); + details = ''; + } + + var logVeiw = ''; + if (this.props.info.logfile && this.props.info.logfile !== '') { + var url = '/log/' + this.props.info.logfile; + logVeiw = 日志 + } + + var icon = ''; + if(this.props.info.watch === true){ + icon = ; + } else { + icon = ; + } + + return ( +
+
+
+

{this.props.info.name}{icon}

+ +
+
+
{this.props.info.path}
+ +
{status}
+
+
+ {details} +
+
+ +

+ {btnToggle} + {logVeiw} +

+
+
+
+ ) + } +}); \ No newline at end of file diff --git a/static/javascripts/src/components/Project.js b/static/javascripts/src/components/Project.js new file mode 100644 index 0000000..a4c90c7 --- /dev/null +++ b/static/javascripts/src/components/Project.js @@ -0,0 +1,92 @@ +/** + * Created by liuxinyi on 2015/8/6. + */ +var React = require('react'); +var Navigation = require('react-router').Navigation; +var swal = require('sweetalert'); +var Process = require('./Process'); +var WebServer = require('./WebServer'); +var ApiCaller = require('../utils/ApiCaller'); + +module.exports = React.createClass({ + mixins: [Navigation], + handleUpgrade: function () { + this.transitionTo('/upgrade/' + this.props.id); + }, + handleRemove: function () { + var self = this; + swal({ + title: "是否移除项目:" + this.props.name + "?", + text: "", + type: "warning", + showCancelButton: true, + cancelButtonText: 'no', + confirmButtonColor: "#ffc66d", + confirmButtonText: "go!", + showLoaderOnConfirm: true, + closeOnConfirm: false + }, function () { + ApiCaller.delete(ApiCaller.API.PROJECT_REMOVE + '/' + self.props.id) + .then(function (d) { + var icon = d.result === true ? "success" : "error"; + var txt = d.result === true ? "移除成功" : "移除失败"; + swal(txt, '', icon); + }); + }); + }, + render: function () { + var self = this; + var processList; + var webserverList; + var kw = this.props.filter; + if (kw === '-e') { + processList = this.props.process.map(function (i) { + if (i.r[0].status !== 1) { + return + } + }); + + webserverList = this.props.webserver.map(function (i) { + if (i.status !== 'Started') { + return + } + }); + } else { + processList = this.props.process.map(function (i) { + if (kw === '' || i.name.toLowerCase().indexOf(kw.toLowerCase()) !== -1) { + return + } + }); + + webserverList = this.props.webserver.map(function (i) { + if (kw === '' || i.name.toLowerCase().indexOf(kw.toLowerCase()) !== -1) { + return + } + }); + } + + var btnUpgrade = ''; + if (this.props.updateable) { + btnUpgrade = (); + } + + return ( +
+
+

{this.props.name}

+ +

+ {btnUpgrade} + +

+
+
+ {webserverList} +
+
+ {processList} +
+
+ ) + } +}); \ No newline at end of file diff --git a/static/javascripts/src/components/ProjectUpgrade.js b/static/javascripts/src/components/ProjectUpgrade.js new file mode 100644 index 0000000..ec558cf --- /dev/null +++ b/static/javascripts/src/components/ProjectUpgrade.js @@ -0,0 +1,169 @@ +/** + * Created by liuxinyi on 2015/8/18. + */ +var React = require('react'); +var Link = require('react-router').Link; +var State = require('react-router').State; +var WebSocket = require('ws'); +var swal = require('sweetalert'); +var ApiCaller = require('../utils/ApiCaller'); +var FileUpload = require('./Upgrade/FileUpload'); + +var UpgradeState = { + "Unknown": -1, + "Preparing": 0, + "Upgrading": 1, + "Upgraded": 2, + "Failed": 3 +}; + +function getLogStyle(level, logLevel) { + var style = {paddingLeft: 0, color: '#BBBBBB'}; + + while (level > 0) { + style.paddingLeft = style.paddingLeft + 20; + level = level - 1; + } + + switch (logLevel) { + case 'error': + style.color = '#A93F41'; + break; + case 'warn': + style.color = '#ffc66d'; + break; + } + + return style; +} + +var ws; + +module.exports = React.createClass({ + mixins: [State], + getInitialState: function () { + return {status: UpgradeState.Unknown, log: [], operation: ''}; + }, + getStatus: function () { + var self = this; + ApiCaller.get(ApiCaller.API.UPGRADE_STATE) + .then(function (data) { + if (!data.isUpdating) { + self.setState({status: UpgradeState.Preparing}); + } else { + var l = self.state.log; + l.push({ + msg: '已有' + self.state.operation + '过程在进行中..', + time: new Date(), + level: 0, + logLevel: 'warn' + }); + self.setState({log: l}); + self.setState({status: UpgradeState.Upgrading}); + } + }); + }, + onlog: function (value) { + if (value.data === '~!@#$over') { + this.setState({status: UpgradeState.Upgraded}); + } else if (value.data === '~!@#$error') { + this.setState({status: UpgradeState.Failed}); + } else { + var d = this.state.log; + var arr = JSON.parse(value.data); + var r = d.concat(arr); + this.setState({log: r}); + } + }, + onUploaded: function (res) { + if (res) { + this.setState({status: UpgradeState.Upgrading}); + } else { + swal(this.state.operation + '预处理失败', res.msg, 'error'); + this.getStatus(); + } + }, + componentWillMount: function () { + if (this.props.params.pjid === '-1') { + this.setState({operation: '安装', status: UpgradeState.Preparing}); + } else { + this.setState({operation: '升级'}); + } + }, + componentDidMount: function () { + this.getStatus(); + ws = new WebSocket(ApiCaller.API.UPGRADE_LOG); + ws.onmessage = this.onlog.bind(this); + }, + componentDidUpdate: function () { + document.body.scrollTop = document.body.scrollHeight; + }, + render: function () { + var content; + var footBack; + var result = "结束"; + var className = "text-yellow"; + switch (this.state.status) { + case UpgradeState.Failed: + result = "失败"; + className = "text-error"; + break; + } + switch (this.state.status) { + case UpgradeState.Unknown: + content = ( +

+ + 正在努力查询状态.. +

+ ); + break; + case UpgradeState.Preparing: + content = ( +
+

上传{this.state.operation}包

+ +
+ ); + break; + case UpgradeState.Upgrading: + case UpgradeState.Upgraded: + case UpgradeState.Failed: + var logs = this.state.log.map(function (l) { + return (

{l.msg} - {l.time}

) + }); + var rslt = (

+ ing.. +

); + if (this.state.status === UpgradeState.Upgraded || this.state.status === UpgradeState.Failed) { + rslt = (

{this.state.operation},{result}.

); + footBack = ( +
+ 返回 +
+ ); + } + content = ( +
+

{this.state.operation},开始!

+ {logs} + {rslt} +
+ ); + break; + } + + return ( +
+
+ 返回 +
+
+ {content} +
+ {footBack} +
+ ) + } +}); \ No newline at end of file diff --git a/static/javascripts/src/components/Projects.js b/static/javascripts/src/components/Projects.js new file mode 100644 index 0000000..4641b8b --- /dev/null +++ b/static/javascripts/src/components/Projects.js @@ -0,0 +1,116 @@ +/** + * Created by liuxinyi on 2015/8/6. + */ +var React = require('react'); +var Navigation = require('react-router').Navigation; +var Project = require('./Project'); +var ApiCaller = require('../utils/ApiCaller'); +var WebSocket = require('ws'); +require('sweetalert/dist/sweetalert.css'); +var swal = require('sweetalert'); + +module.exports = React.createClass({ + mixins: [Navigation], + getInitialState: function() { + return {keyword: '', data: null, msg: "项目信息读取中...", watching: undefined}; + }, + handleSysUpdate: function() { + this.transitionTo('/upgrade/-2'); + }, + handleInstall: function () { + this.transitionTo('/upgrade/-1'); + }, + handleSwitchWatch: function () { + var self = this; + swal({ + title: "是否【" + (!this.state.watching ? "开启" : "关闭") + "】状态监控?", + text: "", + type: "warning", + showCancelButton: true, + cancelButtonText: 'no', + confirmButtonColor: "#ffc66d", + confirmButtonText: "go!", + showLoaderOnConfirm: true, + closeOnConfirm: false + }, function () { + ApiCaller.post(ApiCaller.API.PROJECT_WATCH_SWITCH, {}) + .then(function (d) { + var icon = d.result ? "success" : "error", + msg = d.result ? '状态监控' + (!self.state.watching ? "已开启" : "已关闭") : '状态监控无法启动或关闭, 全局监控未启用或存在异常'; + self.state.watching = d.result ? !self.state.watching : self.state.watching; + swal(msg, '', icon); + self.getProjectWatchState(); + }); + }); + }, + handleSearch: function(){ + this.setState({keyword: event.target.value.trim()}); + }, + handleSearchSubmit: function(){ + this.setState({keyword: event.target[0].value.trim()}); + return false; + }, + getProjectWatchState : function () { + var self = this; + ApiCaller.get(ApiCaller.API.PROJECT_WATCH_STATE) + .then(function (d) { + self.setState({watching: d.result}); + }); + }, + componentDidMount: function () { + this.getProjectWatchState(); + var ws = new WebSocket(ApiCaller.API.PROCESSES_STATUS); + ws.onmessage = function (e) { + var data = JSON.parse(e.data); + this.setState({data: data}); + }.bind(this); + ws.onclose = function () { + this.setState({data: null, msg: "连接已飞,F5试试.."}); + }.bind(this); + }, + render: function () { + var self = this; + var content = ''; + if (this.state.data == null) { + content = (

{this.state.msg}

); + } else if (this.state.data.length === 0) { + content = (

暂无项目,请安装新项目

); + } else{ + content = this.state.data.map(function(p){ + return () + }); + } + + var watching = ''; + if(this.state.watching === undefined) { + watching = (加载中..); + } else if(this.state.watching === true){ + watching = (); + } else { + watching = (); + } + + return ( +
+ ) + } +}); \ No newline at end of file diff --git a/static/javascripts/src/components/SparkLines/index.js b/static/javascripts/src/components/SparkLines/index.js new file mode 100644 index 0000000..51679c0 --- /dev/null +++ b/static/javascripts/src/components/SparkLines/index.js @@ -0,0 +1,714 @@ +module.exports = +/******/ (function(modules) { // webpackBootstrap +/******/ // 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 +/******/ }; + +/******/ // Execute the module function +/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); + +/******/ // 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 = "/"; + +/******/ // Load entry module and return exports +/******/ return __webpack_require__(0); +/******/ }) +/************************************************************************/ +/******/ ([ +/* 0 */ +/***/ function(module, exports, __webpack_require__) { + + module.exports = __webpack_require__(1); + + +/***/ }, +/* 1 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + module.exports = __webpack_require__(2); + +/***/ }, +/* 2 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + Object.defineProperty(exports, '__esModule', { + value: true + }); + + var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); + + var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } }; + + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + + function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } + + function _inherits(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 _react = __webpack_require__(3); + + var _react2 = _interopRequireDefault(_react); + + var _SparklinesLine = __webpack_require__(4); + + var _SparklinesLine2 = _interopRequireDefault(_SparklinesLine); + + var _SparklinesBars = __webpack_require__(5); + + var _SparklinesBars2 = _interopRequireDefault(_SparklinesBars); + + var _SparklinesSpots = __webpack_require__(6); + + var _SparklinesSpots2 = _interopRequireDefault(_SparklinesSpots); + + var _SparklinesReferenceLine = __webpack_require__(7); + + var _SparklinesReferenceLine2 = _interopRequireDefault(_SparklinesReferenceLine); + + var _SparklinesNormalBand = __webpack_require__(9); + + var _SparklinesNormalBand2 = _interopRequireDefault(_SparklinesNormalBand); + + var _DataProcessor = __webpack_require__(8); + + var _DataProcessor2 = _interopRequireDefault(_DataProcessor); + + var Sparklines = (function (_React$Component) { + _inherits(Sparklines, _React$Component); + + _createClass(Sparklines, null, [{ + key: 'propTypes', + value: { + data: _react2['default'].PropTypes.array, + limit: _react2['default'].PropTypes.number, + width: _react2['default'].PropTypes.number, + height: _react2['default'].PropTypes.number, + margin: _react2['default'].PropTypes.number, + style: _react2['default'].PropTypes.object + }, + enumerable: true + }, { + key: 'defaultProps', + value: { + data: [], + width: 120, + height: 30, + margin: 2 + }, + enumerable: true + }]); + + function Sparklines(props) { + _classCallCheck(this, Sparklines); + + _get(Object.getPrototypeOf(Sparklines.prototype), 'constructor', this).call(this, props); + } + + _createClass(Sparklines, [{ + key: 'shouldComponentUpdate', + value: function shouldComponentUpdate(nextProps, nextState) { + var _this = this; + + return nextProps.data.some(function (d, i) { + return d !== _this.props.data[i]; + }); + } + }, { + key: 'render', + value: function render() { + var _props = this.props; + var data = _props.data; + var limit = _props.limit; + var width = _props.width; + var height = _props.height; + var margin = _props.margin; + var style = _props.style; + + if (data.length === 0) return false; + + var points = _DataProcessor2['default'].dataToPoints(data, limit, width, height, margin); + + return _react2['default'].createElement( + 'svg', + { width: width, height: height, style: style }, + _react2['default'].Children.map(this.props.children, function (child) { + return _react2['default'].cloneElement(child, { points: points, width: width, height: height, margin: margin }); + }) + ); + } + }]); + + return Sparklines; + })(_react2['default'].Component); + + exports.Sparklines = Sparklines; + exports.SparklinesLine = _SparklinesLine2['default']; + exports.SparklinesBars = _SparklinesBars2['default']; + exports.SparklinesSpots = _SparklinesSpots2['default']; + exports.SparklinesReferenceLine = _SparklinesReferenceLine2['default']; + exports.SparklinesNormalBand = _SparklinesNormalBand2['default']; + exports.DataProcessor = _DataProcessor2['default']; + +/***/ }, +/* 3 */ +/***/ function(module, exports) { + + module.exports = require("react"); + +/***/ }, +/* 4 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + Object.defineProperty(exports, '__esModule', { + value: true + }); + + var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); + + var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } }; + + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + + function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } + + function _inherits(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 _react = __webpack_require__(3); + + var _react2 = _interopRequireDefault(_react); + + var SparklinesLine = (function (_React$Component) { + _inherits(SparklinesLine, _React$Component); + + function SparklinesLine() { + _classCallCheck(this, SparklinesLine); + + _get(Object.getPrototypeOf(SparklinesLine.prototype), 'constructor', this).apply(this, arguments); + } + + _createClass(SparklinesLine, [{ + key: 'render', + value: function render() { + var _props = this.props; + var points = _props.points; + var width = _props.width; + var height = _props.height; + var margin = _props.margin; + var color = _props.color; + var style = _props.style; + + var linePoints = points.map(function (p) { + return [p.x, p.y]; + }).reduce(function (a, b) { + return a.concat(b); + }); + //var closePolyPoints = [points[points.length - 1].x, height - margin, margin, height - margin, margin, points[0].y]; + var closePolyPoints = [margin, margin, width - margin, margin, width - margin, height - margin, margin, height - margin, margin, margin]; + var fillPoints = closePolyPoints; + + var lineStyle = { + stroke: color || style.stroke || 'slategray', + strokeWidth: style.strokeWidth || '1', + strokeLinejoin: style.strokeLinejoin || 'round', + strokeLinecap: style.strokeLinecap || 'round', + fill: 'none' + }; + var fillStyle = { + stroke: style.stroke || 'none', + strokeWidth: '0', + fillOpacity: style.fillOpacity || '.1', + fill: color || style.fill || 'slategray' + }; + + return _react2['default'].createElement( + 'g', + null, + _react2['default'].createElement('polyline', { points: fillPoints.join(' '), style: fillStyle }), + _react2['default'].createElement('polyline', { points: linePoints.join(' '), style: lineStyle }) + ); + } + }], [{ + key: 'propTypes', + value: { + color: _react2['default'].PropTypes.string, + style: _react2['default'].PropTypes.object + }, + enumerable: true + }, { + key: 'defaultProps', + value: { + style: {} + }, + enumerable: true + }]); + + return SparklinesLine; + })(_react2['default'].Component); + + exports['default'] = SparklinesLine; + module.exports = exports['default']; + +/***/ }, +/* 5 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + Object.defineProperty(exports, '__esModule', { + value: true + }); + + var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); + + var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } }; + + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + + function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } + + function _inherits(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 _react = __webpack_require__(3); + + var _react2 = _interopRequireDefault(_react); + + var SparklinesBars = (function (_React$Component) { + _inherits(SparklinesBars, _React$Component); + + function SparklinesBars() { + _classCallCheck(this, SparklinesBars); + + _get(Object.getPrototypeOf(SparklinesBars.prototype), 'constructor', this).apply(this, arguments); + } + + _createClass(SparklinesBars, [{ + key: 'render', + value: function render() { + var _props = this.props; + var points = _props.points; + var width = _props.width; + var height = _props.height; + var margin = _props.margin; + var style = _props.style; + + var barWidth = points.length >= 2 ? points[1].x - points[0].x : 0; + + return _react2['default'].createElement( + 'g', + null, + points.map(function (p, i) { + return _react2['default'].createElement('rect', { + key: i, + x: p.x, y: p.y, + width: barWidth, height: height - p.y, + style: style }); + }) + ); + } + }], [{ + key: 'propTypes', + value: { + style: _react2['default'].PropTypes.object + }, + enumerable: true + }, { + key: 'defaultProps', + value: { + style: { fill: 'slategray' } + }, + enumerable: true + }]); + + return SparklinesBars; + })(_react2['default'].Component); + + exports['default'] = SparklinesBars; + module.exports = exports['default']; + +/***/ }, +/* 6 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + Object.defineProperty(exports, '__esModule', { + value: true + }); + + var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); + + var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } }; + + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + + function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } + + function _inherits(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 _react = __webpack_require__(3); + + var _react2 = _interopRequireDefault(_react); + + var SparklinesSpots = (function (_React$Component) { + _inherits(SparklinesSpots, _React$Component); + + function SparklinesSpots() { + _classCallCheck(this, SparklinesSpots); + + _get(Object.getPrototypeOf(SparklinesSpots.prototype), 'constructor', this).apply(this, arguments); + } + + _createClass(SparklinesSpots, [{ + key: 'lastDirection', + value: function lastDirection(points) { + + Math.sign = Math.sign || function (x) { + return x > 0 ? 1 : -1; + }; + + return points.length < 2 ? 0 : Math.sign(points[points.length - 2].y - points[points.length - 1].y); + } + }, { + key: 'render', + value: function render() { + var _props = this.props; + var points = _props.points; + var width = _props.width; + var height = _props.height; + var size = _props.size; + var style = _props.style; + var spotColors = _props.spotColors; + + var startSpot = _react2['default'].createElement('circle', { + cx: points[0].x, + cy: points[0].y, + r: size, + style: style }); + + var endSpot = _react2['default'].createElement('circle', { + cx: points[points.length - 1].x, + cy: points[points.length - 1].y, + r: size, + style: style || { fill: spotColors[this.lastDirection(points)] } }); + + return _react2['default'].createElement( + 'g', + null, + style && startSpot, + endSpot + ); + } + }], [{ + key: 'propTypes', + value: { + size: _react2['default'].PropTypes.number, + style: _react2['default'].PropTypes.object, + spotColors: _react2['default'].PropTypes.object + }, + enumerable: true + }, { + key: 'defaultProps', + value: { + size: 2, + spotColors: { + '-1': 'red', + '0': 'black', + '1': 'green' + } + }, + enumerable: true + }]); + + return SparklinesSpots; + })(_react2['default'].Component); + + exports['default'] = SparklinesSpots; + module.exports = exports['default']; + +/***/ }, +/* 7 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + Object.defineProperty(exports, '__esModule', { + value: true + }); + + var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); + + var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } }; + + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + + function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } + + function _inherits(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 _react = __webpack_require__(3); + + var _react2 = _interopRequireDefault(_react); + + var _DataProcessor = __webpack_require__(8); + + var _DataProcessor2 = _interopRequireDefault(_DataProcessor); + + var SparklinesReferenceLine = (function (_React$Component) { + _inherits(SparklinesReferenceLine, _React$Component); + + function SparklinesReferenceLine() { + _classCallCheck(this, SparklinesReferenceLine); + + _get(Object.getPrototypeOf(SparklinesReferenceLine.prototype), 'constructor', this).apply(this, arguments); + } + + _createClass(SparklinesReferenceLine, [{ + key: 'render', + value: function render() { + var _props = this.props; + var points = _props.points; + var margin = _props.margin; + var type = _props.type; + var style = _props.style; + + var ypoints = points.map(function (p) { + return p.y; + }); + var y = _DataProcessor2['default'].calculateFromData(ypoints, type); + + return _react2['default'].createElement('line', { + x1: points[0].x, y1: y + margin, + x2: points[points.length - 1].x, y2: y + margin, + style: style }); + } + }], [{ + key: 'propTypes', + value: { + type: _react2['default'].PropTypes.oneOf(['max', 'min', 'mean', 'avg', 'median']), + style: _react2['default'].PropTypes.object + }, + enumerable: true + }, { + key: 'defaultProps', + value: { + type: 'mean', + style: { stroke: 'red', strokeOpacity: .75, strokeDasharray: '2, 2' } + }, + enumerable: true + }]); + + return SparklinesReferenceLine; + })(_react2['default'].Component); + + exports['default'] = SparklinesReferenceLine; + module.exports = exports['default']; + +/***/ }, +/* 8 */ +/***/ function(module, exports) { + + "use strict"; + + Object.defineProperty(exports, "__esModule", { + value: true + }); + + var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); + + function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } + + var DataProcessor = (function () { + function DataProcessor() { + _classCallCheck(this, DataProcessor); + } + + _createClass(DataProcessor, null, [{ + key: "dataToPoints", + value: function dataToPoints(data, limit, width, height, margin) { + + if (limit && limit < data.length) { + data = data.slice(data.length - limit); + } + + var max = this.max(data); + var min = this.min(data); + + var vfactor = (height - margin * 2) / (max - min || 1); + var hfactor = (width - margin * 2) / ((limit || data.length) - 1); + + return data.map(function (d, i) { + return { + x: i * hfactor + margin, + y: (max - data[i]) * vfactor + margin + }; + }); + } + }, { + key: "max", + value: function max(data) { + return 100;// Math.max.apply(Math, data); + } + }, { + key: "min", + value: function min(data) { + return 0;// Math.min.apply(Math, data); + } + }, { + key: "mean", + value: function mean(data) { + return (this.max(data) - this.min(data)) / 2; + } + }, { + key: "avg", + value: function avg(data) { + return data.reduce(function (a, b) { + return a + b; + }) / (data.length + 1); + } + }, { + key: "median", + value: function median(data) { + return data.sort()[Math.floor(data.length / 2)]; + } + }, { + key: "variance", + value: function variance(data) { + var mean = this.mean(data); + var sq = data.map(function (n) { + return Math.pow(n - mean, 2); + }); + return this.mean(sq); + } + }, { + key: "stdev", + value: function stdev(data) { + var mean = this.mean(data); + var sqDiff = data.map(function (n) { + return Math.pow(n - mean, 2); + }); + var avgSqDiff = this.avg(sqDiff); + return Math.sqrt(avgSqDiff); + } + }, { + key: "calculateFromData", + value: function calculateFromData(data, calculationType) { + return this[calculationType].call(this, data); + } + }]); + + return DataProcessor; + })(); + + exports["default"] = DataProcessor; + module.exports = exports["default"]; + +/***/ }, +/* 9 */ +/***/ function(module, exports, __webpack_require__) { + + 'use strict'; + + Object.defineProperty(exports, '__esModule', { + value: true + }); + + var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })(); + + var _get = function get(_x, _x2, _x3) { var _again = true; _function: while (_again) { var object = _x, property = _x2, receiver = _x3; desc = parent = getter = undefined; _again = false; if (object === null) object = Function.prototype; var desc = Object.getOwnPropertyDescriptor(object, property); if (desc === undefined) { var parent = Object.getPrototypeOf(object); if (parent === null) { return undefined; } else { _x = parent; _x2 = property; _x3 = receiver; _again = true; continue _function; } } else if ('value' in desc) { return desc.value; } else { var getter = desc.get; if (getter === undefined) { return undefined; } return getter.call(receiver); } } }; + + function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; } + + function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } } + + function _inherits(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 _react = __webpack_require__(3); + + var _react2 = _interopRequireDefault(_react); + + var _DataProcessor = __webpack_require__(8); + + var _DataProcessor2 = _interopRequireDefault(_DataProcessor); + + var SparklinesNormalBand = (function (_React$Component) { + _inherits(SparklinesNormalBand, _React$Component); + + function SparklinesNormalBand() { + _classCallCheck(this, SparklinesNormalBand); + + _get(Object.getPrototypeOf(SparklinesNormalBand.prototype), 'constructor', this).apply(this, arguments); + } + + _createClass(SparklinesNormalBand, [{ + key: 'render', + value: function render() { + var _props = this.props; + var points = _props.points; + var margin = _props.margin; + var style = _props.style; + + var ypoints = points.map(function (p) { + return p.y; + }); + var mean = _DataProcessor2['default'].calculateFromData(ypoints, 'mean'); + var stdev = _DataProcessor2['default'].calculateFromData(ypoints, 'stdev'); + + return _react2['default'].createElement('rect', { x: points[0].x, y: mean - stdev + margin, + width: points[points.length - 1].x - points[0].x, height: stdev * 2, + style: style }); + } + }], [{ + key: 'propTypes', + value: { + style: _react2['default'].PropTypes.object + }, + enumerable: true + }, { + key: 'defaultProps', + value: { + style: { fill: 'red', fillOpacity: .1 } + }, + enumerable: true + }]); + + return SparklinesNormalBand; + })(_react2['default'].Component); + + exports['default'] = SparklinesNormalBand; + module.exports = exports['default']; + +/***/ } +/******/ ]); \ No newline at end of file diff --git a/static/javascripts/src/components/Upgrade/FileUpload.js b/static/javascripts/src/components/Upgrade/FileUpload.js new file mode 100644 index 0000000..5c2dc76 --- /dev/null +++ b/static/javascripts/src/components/Upgrade/FileUpload.js @@ -0,0 +1,54 @@ +/** + * Created by liuxinyi on 2015/8/24. + */ +var React = require('react'); +var Dropzone = require('react-dropzone'); +var swal = require('sweetalert'); +var ApiCaller = require('../../utils/ApiCaller'); + +var UploadStatus = { + PreUpload : 0, + Uploading : 1 +}; + +module.exports = React.createClass({ + getInitialState: function () { + return {status : UploadStatus.PreUpload}; + }, + onDrop: function(files) { + var self = this; + self.setState({status: UploadStatus.Uploading}); + ApiCaller + .upload(ApiCaller.API.UPLOAD_PACKAGE + '?pjid=' + this.props.pjid, files) + .then(function(data){ + self.setState({status: UploadStatus.PreUpload}); + self.props.onUploaded(data.res); + }); + }, + render : function () { + var content = ''; + switch (this.state.status){ + case UploadStatus.PreUpload: + content = ( + +
拖拽或点击选择要上传的升级包.(只支持zip格式)
+
+ ); + break; + case UploadStatus.Uploading: + content = ( +
+
+
+
+ ); + break; + } + + return ( +
+ {content} +
+ ); + } +}); \ No newline at end of file diff --git a/static/javascripts/src/components/WebServer.js b/static/javascripts/src/components/WebServer.js new file mode 100644 index 0000000..7e22710 --- /dev/null +++ b/static/javascripts/src/components/WebServer.js @@ -0,0 +1,101 @@ +/** + * Created by liuxinyi on 2015/9/1. + */ +var React = require('react'); +var Navigation = require('react-router').Navigation; +var Link = require('react-router').Link; +require('sweetalert/dist/sweetalert.css'); +var swal = require('sweetalert'); +var ApiCaller = require('../utils/ApiCaller'); +var TimeUtil = require('../utils/TimeUtil'); +var PerfChart = require('./PerfChart'); + +var dataStyle = { + fontSize: 24 +}; + +module.exports = React.createClass({ + mixins: [Navigation], + handleStartStop: function () { + var text = this.props.info.status === "Started" ? "停止" : "启动"; + var self = this; + swal({ + title: "是否" + text + this.props.info.name + "?", + text: "", + type: "warning", + showCancelButton: true, + cancelButtonText: 'no', + confirmButtonColor: "#ffc66d", + confirmButtonText: "go!", + showLoaderOnConfirm: true, + closeOnConfirm: false + }, function () { + ApiCaller.post(ApiCaller.API.WEBSERVER_TOGGLE, { + pjid: self.props.projectId, + id: self.props.info.id, + cmd: self.props.info.status === "Started" ? 0 : 1 + }) + .then(function (d) { + var icon = d.res === true ? "success" : "error"; + swal(d.msg, '', icon); + }); + }); + }, + handlePatch: function () { + //swal('请先登录','','info'); + this.transitionTo('/process/' + this.props.info.id); + }, + render: function () { + var btnToggle; + var titleClass; + var status; + if (this.props.info.status === "Started") { + btnToggle = ; + titleClass = 'text-success'; + status = ( +

运行中

+ ); + } else { + btnToggle = ; + titleClass = 'text-danger'; + status = ( +

未启动

+ ); + } + + var logVeiw = ''; + if (this.props.info.logfile && this.props.info.logfile !== '') { + var url = '/log/' + this.props.info.logfile; + logVeiw = 日志 + } + + var icon = ''; + if(this.props.info.watch === true){ + icon = ; + } else { + icon = ; + } + + return ( +
+
+
+

{this.props.info.name}{icon}

+ +
+
{this.props.info.protocol}://{this.props.info.host}:{this.props.info.port}
+
{this.props.info.path}
+
+ +
{status}
+ +

+ {btnToggle} + {logVeiw} +

+
+
+
+ ) + } +}); \ No newline at end of file diff --git a/static/javascripts/src/main.js b/static/javascripts/src/main.js new file mode 100644 index 0000000..fc922e0 --- /dev/null +++ b/static/javascripts/src/main.js @@ -0,0 +1,26 @@ +/** + * Created by liuxinyi on 2015/8/5. + */ +var React = require('react'); +var Router = require('react-router'); +var Projects = require('./components/Projects'); +var ProjectUpgrade = require('./components/ProjectUpgrade'); +var NotFound = require('./components/NotFound'); +var LogView = require('./components/LogView'); + +var Route = Router.Route; +var NotFoundRoute = Router.NotFoundRoute; + +var routes = ( + + + + + + + +); + +Router.run(routes, function(Root) { + React.render(, document.getElementById('main')); +}); \ No newline at end of file diff --git a/static/javascripts/src/utils/ApiCaller.js b/static/javascripts/src/utils/ApiCaller.js new file mode 100644 index 0000000..bdb1775 --- /dev/null +++ b/static/javascripts/src/utils/ApiCaller.js @@ -0,0 +1,101 @@ +/** + * Created by liuxinyi on 2015/8/14. + */ +var Q = require('q'); +var request = require('superagent'); +var swal = require('sweetalert'); + +var ApiCaller = {}; + +var host = window.document.location.hostname; + +ApiCaller.API = { + "PROCESSES_STATUS": "ws://" + host + ":8100", + "PROCESS_LOG": "ws://" + host + ":8200", + "PROCESS_TOGGLE": "process/toggle", + "WEBSERVER_TOGGLE": "webserver/toggle", + "UPLOAD_PACKAGE": "upload/package", + "UPGRADE_STATE" : "upgrade/status", + "UPGRADE_LOG" : "ws://" + host + ":8400", + "PROJECT_REMOVE" : "project/delete", + "PROJECT_WATCH_STATE" : "project/watch/state", + "PROJECT_WATCH_SWITCH" : "project/watch/switch" +}; + +ApiCaller.get = function (url) { + var deferred = Q.defer(); + + request.get(url).end(function(err, res) { + if(err != null) { + swal('网络好像不太给力', '', 'info'); + }else if (res.status === 401) { + window.location.assign('/login'); + }else { + deferred.resolve(JSON.parse(res.text)); + } + }); + + return deferred.promise; +}; + +ApiCaller.post = function (url, data) { + var deferred = Q.defer(); + + request.post(url).send(data).end(function(err, res) { + if(err != null) { + if (res.status === 401) { + window.location.assign('/login'); + }else{ + swal('网络好像不太给力', '', 'info'); + } + }else { + deferred.resolve(JSON.parse(res.text)); + } + }); + + return deferred.promise; +}; + +ApiCaller.delete = function (url) { + var deferred = Q.defer(); + + request.del(url).end(function(err, res) { + if(err != null) { + if (res.status === 401) { + window.location.assign('/login'); + }else{ + swal('网络好像不太给力', '', 'info'); + } + }else { + deferred.resolve(JSON.parse(res.text)); + } + }); + + return deferred.promise; +}; + +ApiCaller.upload = function(url, files){ + var deferred = Q.defer(); + + var req = request.post(url); + var index = 0; + files.forEach(function (file) { + req.attach(index, file); + index = index + 1; + }); + req.end(function(err, res){ + if(err != null){ + if (err.status === 401) { + window.location.assign('/login'); + } else { + swal('网络好像不太给力', '', 'info'); + } + }else{ + deferred.resolve(JSON.parse(res.text)); + } + }); + + return deferred.promise; +}; + +module.exports = ApiCaller; \ No newline at end of file diff --git a/static/javascripts/src/utils/TimeUtil.js b/static/javascripts/src/utils/TimeUtil.js new file mode 100644 index 0000000..f928381 --- /dev/null +++ b/static/javascripts/src/utils/TimeUtil.js @@ -0,0 +1,26 @@ +/** + * Created by liuxinyi on 2015/8/19. + */ +var util = { + MillisecondToDate: function (msd) { + var time = parseFloat(msd) / 1000; + if (null != time && "" != time) { + if (time > 60 && time < 60 * 60) { + time = parseInt(time / 60.0) + "分钟" + parseInt((parseFloat(time / 60.0) - + parseInt(time / 60.0)) * 60) + "秒"; + } + else if (time >= 60 * 60) { + time = parseInt(time / 3600.0) + "小时" + parseInt((parseFloat(time / 3600.0) - + parseInt(time / 3600.0)) * 60) + "分钟" + + parseInt((parseFloat((parseFloat(time / 3600.0) - parseInt(time / 3600.0)) * 60) - + parseInt((parseFloat(time / 3600.0) - parseInt(time / 3600.0)) * 60)) * 60) + "秒"; + } + else { + time = parseInt(time) + "秒"; + } + } + return time; + } +}; + +module.exports = util; \ No newline at end of file diff --git a/static/javascripts/src/utils/UnitUtil.js b/static/javascripts/src/utils/UnitUtil.js new file mode 100644 index 0000000..fb1a7e0 --- /dev/null +++ b/static/javascripts/src/utils/UnitUtil.js @@ -0,0 +1,25 @@ +/** + * Created by liuxinyi on 2015/9/1. + */ +var util = { + Convert1024: function (d) { + if (null != d && "" != d) { + var data = parseInt(d); + if (data > 1024 && data < 1024 * 1024) { + data = (data / 1024.0).toFixed(2) + "MB"; + } + else if (data >= 1024 * 1024) { + data = (data / 1024.0 / 1024.0).toFixed(2) + "GB"; + } + else { + data = data + "KB"; + } + + return data; + }else{ + return d; + } + } +}; + +module.exports = util; \ No newline at end of file diff --git a/static/stylesheets/style.css b/static/stylesheets/style.css new file mode 100644 index 0000000..752a2c5 --- /dev/null +++ b/static/stylesheets/style.css @@ -0,0 +1,36 @@ +body { + background: #3C3F41; + color: #BBBBBB; + font: 700 13px "Hiragino Sans GB", "Microsoft Yahei" +} + +.ghost-btn, .ghost-btn:focus { + border: 0 solid #ffc66d; + color: #ffc66d; + background: transparent; +} + +.ghost-btn:hover { + color: black; + background: #ffc66d; +} + +.text-yellow { + color: #ffc66d; +} + +.text-error { + color: #ff0000; +} + +.text-success{ + color: #43b19a +} + +.btn-success{ + background-color: #43b19a +} + +body .stop-srolling{ + overflow: scroll; +} \ No newline at end of file diff --git a/views/error.jade b/views/error.jade new file mode 100644 index 0000000..51ec12c --- /dev/null +++ b/views/error.jade @@ -0,0 +1,6 @@ +extends layout + +block content + h1= message + h2= error.status + pre #{error.stack} diff --git a/views/index.html b/views/index.html new file mode 100644 index 0000000..8cd5cc9 --- /dev/null +++ b/views/index.html @@ -0,0 +1,16 @@ + + + + + 安心云 小护士 + + + + +
+
+
+
+ + + \ No newline at end of file diff --git a/views/index.jade b/views/index.jade new file mode 100644 index 0000000..3c95496 --- /dev/null +++ b/views/index.jade @@ -0,0 +1 @@ +include index.html \ No newline at end of file diff --git a/views/layout.jade b/views/layout.jade new file mode 100644 index 0000000..15af079 --- /dev/null +++ b/views/layout.jade @@ -0,0 +1,7 @@ +doctype html +html + head + title= title + link(rel='stylesheet', href='/stylesheets/style.css') + body + block content diff --git a/views/login.html b/views/login.html new file mode 100644 index 0000000..ded318f --- /dev/null +++ b/views/login.html @@ -0,0 +1,29 @@ + + + + + 安心云 小护士 + + + + +

+ +

+
+
+
+ + +
+
+ + +
+
+ +
+ +
+ + \ No newline at end of file diff --git a/views/login.jade b/views/login.jade new file mode 100644 index 0000000..e48f633 --- /dev/null +++ b/views/login.jade @@ -0,0 +1,4 @@ +// + Created by rain on 2015/8/6. + +include login.html \ No newline at end of file diff --git a/webpack.config.js b/webpack.config.js new file mode 100644 index 0000000..4b594ef --- /dev/null +++ b/webpack.config.js @@ -0,0 +1,15 @@ +/** + * Created by liuxinyi on 2015/8/6. + */ +module.exports = { + entry: './static/javascripts/src/main.js', + output: { + filename: './static/javascripts/build/index.js' + }, + module: { + loaders: [ + { test: /\.js$/, loader: "jsx-loader" }, + { test: /\.css$/, loader: "style-loader!css-loader" } + ] + } +}; \ No newline at end of file