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.
+ *
+ *
+ *
+ * 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