diff --git a/.gitignore b/.gitignore index 97a90fea..ffc9e3f9 100644 --- a/.gitignore +++ b/.gitignore @@ -14,4 +14,5 @@ configtest.toml bolter.exe mythbuntu-16.04.3-desktop-i386.iso.torrent ubuntu-17.04-desktop-amd64.iso (1).torrent -ubuntu.torrent \ No newline at end of file +ubuntu.torrent +*.torrent diff --git a/engine/engine.go b/engine/engine.go index e69de29b..93d6aa63 100644 --- a/engine/engine.go +++ b/engine/engine.go @@ -0,0 +1,46 @@ +package engine //main file for all the calculations and data gathering needed for creating the running torrent array + +import ( + "fmt" +) + +func calculateTorrentSpeed(t *torrent.Torrent, c *clientDB) { + now := time.Now() + bytes := t.BytesCompleted() + fmt.Println("UpdatedAt: ", c.UpdatedAt) + if c.UpdatedAt.IsZero() { + c.UpdatedAt = now + fmt.Println("Setting Time", c.UpdatedAt) + + } else { + dt := float32(now.Sub(c.UpdatedAt)) + fmt.Println("Delta Time: ", dt) + db := float32(bytes - c.BytesCompleted) + fmt.Println("Delta Bytes:", db) + rate := db * (float32(time.Second) / dt) + + fmt.Println("form: ", float32(time.Second)) + if rate >= 0 { + c.DownloadSpeed = rate + } + } + +} + + + +func calculateTorrentStatus(t *torrent.Torrent, c *clientDB) { + if t.Seeding() { + c.Status = "Seeding" + } else if t.Stats().ActivePeers > 0 && t.BytesMissing() > 0 { + c.Status = "Downloading" + } else if t.Stats().ActivePeers == 0 && t.BytesMissing() == 0 { + c.Status = "Completed" + } else if t.Stats().ActivePeers == 0 && t.BytesMissing() > 0 { + c.Status = "Awaiting Peers" + } else { + c.Status = "Unknown" + } +} + + diff --git a/main.go b/main.go index d602383a..3833fb51 100644 --- a/main.go +++ b/main.go @@ -20,6 +20,7 @@ import ( "github.com/anacrolix/torrent/metainfo" "github.com/boltdb/bolt" + //tengine "github.com/deranjer/gtEngine/engine" ) var ( @@ -41,17 +42,18 @@ type torrentList struct { //helps create the JSON structure that react expects t } type clientDB struct { - TorrentName string `json:"TorrentName"` - DownloadedSize int64 `json:"DownloadedSize"` - Size int64 `json:"Size"` - DownloadSpeed float32 `json:"DownloadSpeed"` - UploadSpeed float32 `json:"UploadSpeed"` + TorrentName string `json:"TorrentName"` + DownloadedSize string `json:"DownloadedSize"` + Size string `json:"Size"` + DownloadSpeed string `json:"DownloadSpeed"` + downloadSpeedInt int64 + UploadSpeed string `json:"UploadSpeed"` + //UploadSpeedInt int64 DataBytesWritten int64 DataBytesRead int64 - ActivePeers int `json:"ActivePeers"` - TotalPeers int `json:"TotalPeers"` - TorrentHashString string `json:"TorrentHashString"` - PercentDone float32 `json:"PercentDone"` + ActivePeers string `json:"ActivePeers"` + TorrentHashString string `json:"TorrentHashString"` + PercentDone string `json:"PercentDone"` TorrentHash metainfo.Hash StoragePath string `json:"StorageLocation"` DateAdded string @@ -59,33 +61,92 @@ type clientDB struct { Status string `json:"Status"` BytesCompleted int64 UpdatedAt time.Time + ETA string `json:"ETA"` } -func calculateTorrentSpeed(t *torrent.Torrent, c *clientDB) { +func secondsToMinutes(inSeconds int64) string { + minutes := inSeconds / 60 + seconds := inSeconds % 60 + minutesString := fmt.Sprintf("%d", minutes) + secondsString := fmt.Sprintf("%d", seconds) + str := minutesString + " Min/ " + secondsString + " Sec" + return str +} + +func convertSizetoGB(t float32, d float32) (tDelta string, dDelta string) { //converting sizes to MB or GB as needed and adding string + if t > 1024 && d > 1024 { + t := fmt.Sprintf("%.2f", t/1024) + t = t + " GB" + d := fmt.Sprintf("%.2f", d/1024) + d = d + " GB" + return t, d + } else if d > 1024 || t > 1024 { + if d > 1024 { + d := fmt.Sprintf("%.2f", d/1024) + d = d + " GB" + t := fmt.Sprintf("%.2f", t) + t = t + " MB" + return t, d + } + d := fmt.Sprintf("%.2f", d) + d = d + " MB" + t := fmt.Sprintf("%.2f", t/1024) + t = t + " GB" + return t, d + } else { + d := fmt.Sprintf("%.2f", d) + t := fmt.Sprintf("%.2f", t) + t = t + " MB" + d = d + " MB" + return t, d + } +} + +func calculateTorrentSpeed(t *torrent.Torrent, c *clientDB, oc clientDB) { now := time.Now() bytes := t.BytesCompleted() - fmt.Println("UpdatedAt: ", c.UpdatedAt) - if c.UpdatedAt.IsZero() { - c.UpdatedAt = now - fmt.Println("Setting Time", c.UpdatedAt) - - } else { - dt := float32(now.Sub(c.UpdatedAt)) - fmt.Println("Delta Time: ", dt) - db := float32(bytes - c.BytesCompleted) - fmt.Println("Delta Bytes:", db) - rate := db * (float32(time.Second) / dt) - - fmt.Println("form: ", float32(time.Second)) - if rate >= 0 { - c.DownloadSpeed = rate - } + bytesUpload := t.Stats().DataBytesWritten + dt := float32(now.Sub(oc.UpdatedAt)) // get the delta time length between now and last updated + db := float32(bytes - oc.BytesCompleted) //getting the delta bytes + rate := db * (float32(time.Second) / dt) // converting into seconds + dbU := float32(bytesUpload - oc.DataBytesWritten) + fmt.Println("BytesWritten", bytesUpload) + fmt.Println("WireBytes", t.Stats().DataBytesWritten) + fmt.Println("ChunksWritten", t.Stats().ChunksWritten) + rateUpload := dbU * (float32(time.Second) / dt) + if rate >= 0 { + rate = rate / 1024 / 1024 //creating integer to calculate ETA + c.DownloadSpeed = fmt.Sprintf("%.2f", rate) + c.DownloadSpeed = c.DownloadSpeed + " MB/s" + c.downloadSpeedInt = int64(rate) } + if rateUpload >= 0 { + rateUpload = rateUpload / 1024 / 1024 + c.UploadSpeed = fmt.Sprintf("%.2f", rateUpload) + c.UploadSpeed = c.UploadSpeed + " MB/s" + //c.UploadSpeedInt = int64(rateUpload) + } + //c.DownloadSpeed = fmt.Sprintf("%.2f", rate) //setting zero for download speed + //c.DownloadSpeed = c.DownloadSpeed + " MB/s" + c.UpdatedAt = now +} +func calculateTorrentETA(t *torrent.Torrent, c *clientDB) { + missingBytes := t.Length() - t.BytesCompleted() + missingMB := missingBytes / 1024 / 1024 + if missingMB == 0 { + c.ETA = "Done" + } else if c.downloadSpeedInt == 0 { + c.ETA = "N/A" + } else { + ETASeconds := missingMB / c.downloadSpeedInt + str := secondsToMinutes(ETASeconds) //converting seconds to minutes + seconds + c.ETA = str + } } func calculateTorrentStatus(t *torrent.Torrent, c *clientDB) { - if t.Seeding() { + if t.Seeding() && t.Stats().ActivePeers > 0 && t.BytesMissing() == 0 { c.Status = "Seeding" } else if t.Stats().ActivePeers > 0 && t.BytesMissing() > 0 { c.Status = "Downloading" @@ -103,23 +164,28 @@ func serveHome(w http.ResponseWriter, r *http.Request) { s1.ExecuteTemplate(w, "base", map[string]string{"APP_ID": APP_ID}) } -func startTorrent(clientTorrent *torrent.Torrent, torrentLocalStorage *TorrentLocal, torrentDbStorage *bolt.DB, dataDir string, torrentFile string, torrentFileName string) { - +func timeOutInfo(clientTorrent *torrent.Torrent, seconds time.Duration) (deleted bool) { //forcing a timeout of the timeout := make(chan bool, 1) //creating a timeout channel for our gotinfo go func() { - time.Sleep(45 * time.Second) + time.Sleep(seconds * time.Second) timeout <- true }() select { case <-clientTorrent.GotInfo(): //attempting to retrieve info for torrent fmt.Println("Recieved torrent info..") clientTorrent.DownloadAll() + return false case <-timeout: // getting info for torrent has timed out so purging the torrent fmt.Println("Dropping Torrent") clientTorrent.Drop() - return + return true } +} + +func startTorrent(clientTorrent *torrent.Torrent, torrentLocalStorage *TorrentLocal, torrentDbStorage *bolt.DB, dataDir string, torrentFile string, torrentFileName string) { + + timeOutInfo(clientTorrent, 45) //seeing if adding the torrrent times out (giving 45 seconds) var TempHash metainfo.Hash TempHash = clientTorrent.InfoHash() fmt.Println(clientTorrent.Info().Source) @@ -139,15 +205,15 @@ func startTorrent(clientTorrent *torrent.Torrent, torrentLocalStorage *TorrentLo clientTorrent.DownloadAll() //starting the download } -func createRunningTorrentArray(tclient *torrent.Client, TorrentLocalArray []*TorrentLocal, config fullClientSettings, db *bolt.DB) (RunningTorrentArray []clientDB) { +func createRunningTorrentArray(tclient *torrent.Client, TorrentLocalArray []*TorrentLocal, PreviousTorrentArray []clientDB, config fullClientSettings, db *bolt.DB) (RunningTorrentArray []clientDB) { for _, element := range TorrentLocalArray { //re-adding all the torrents we had stored from last shutdown var singleTorrent *torrent.Torrent if element.TorrentType == "file" { //if it is a file pull it from the uploaded torrent folder - fmt.Println("Filename", element.TorrentFileName) + //fmt.Println("Filename", element.TorrentFileName) if _, err := os.Stat(element.TorrentFileName); err == nil { //if we CAN find the torrent, add it - fmt.Println("Adding file name...", element.TorrentFileName) + //fmt.Println("Adding file name...", element.TorrentFileName) singleTorrent, _ = tclient.AddTorrentFromFile(element.TorrentFileName) } else { //if we cant find the torrent delete it fmt.Println("File Error", err) @@ -160,49 +226,51 @@ func createRunningTorrentArray(tclient *torrent.Client, TorrentLocalArray []*Tor singleTorrent, _ = tclient.AddMagnet(elementMagnet) } - timeout := make(chan bool, 1) //creating a timeout channel for our gotinfo - go func() { - time.Sleep(45 * time.Second) - timeout <- true - }() - select { - case <-singleTorrent.GotInfo(): //attempting to retrieve info for torrent - singleTorrent.DownloadAll() - case <-timeout: // getting info for torrent has timed out so purging the torrent - fmt.Println("Dropping Torrent") - singleTorrent.Drop() + timeOut := timeOutInfo(singleTorrent, 45) + if timeOut == true { // if we did timeout then drop the torrent from the boltdb database delTorrentLocalStorage(db, element) //purging torrent from the local database - continue } - fmt.Println("Recieved info for: ", element.TorrentName) fullClientDB := new(clientDB) fullStruct := singleTorrent.Stats() - bytesTotal := singleTorrent.Length() - //bytesCompleted := singleTorrent.BytesCompleted() + //ranging over the previous torrent array to calculate the speed for each torrent + if len(PreviousTorrentArray) > 0 { //if we actually have a previous array + for _, previousElement := range PreviousTorrentArray { + TempHash := singleTorrent.InfoHash() + if previousElement.TorrentHashString == TempHash.AsString() { //matching previous to new + calculateTorrentSpeed(singleTorrent, fullClientDB, previousElement) + } + } + } + activePeersString := fmt.Sprintf("%v", fullStruct.ActivePeers) //converting to strings + totalPeersString := fmt.Sprintf("%v", fullStruct.TotalPeers) + bytesCompletedMB := float32(singleTorrent.BytesCompleted() / 1024 / 1024) + totalSizeMB := float32(singleTorrent.Length() / 1024 / 1024) + //downloadSizeString := fmt.Sprintf("%d", bytesCompletedMB) - calculateTorrentSpeed(singleTorrent, fullClientDB) //Setting the downloadSpeed for the torrent - //fullClientDB.UpdatedAt = time.Now() // setting the current time to measure download speed. + tSize, dSize := convertSizetoGB(totalSizeMB, bytesCompletedMB) //convert size to GB if needed var TempHash metainfo.Hash TempHash = singleTorrent.InfoHash() - fullClientDB.DownloadedSize = singleTorrent.BytesCompleted() / 1024 / 1024 - fullClientDB.Size = bytesTotal / 1024 / 1024 + + fullClientDB.DownloadedSize = dSize + fullClientDB.Size = tSize + PercentDone := fmt.Sprintf("%.2f", bytesCompletedMB/totalSizeMB) fullClientDB.TorrentHash = TempHash - fullClientDB.PercentDone = (float32(fullClientDB.DownloadedSize) / float32(fullClientDB.Size)) + fullClientDB.PercentDone = PercentDone fullClientDB.DataBytesRead = fullStruct.ConnStats.DataBytesRead fullClientDB.DataBytesWritten = fullStruct.ConnStats.DataBytesWritten - fullClientDB.ActivePeers = fullStruct.ActivePeers - fullClientDB.TotalPeers = fullStruct.TotalPeers + fullClientDB.ActivePeers = activePeersString + " / (" + totalPeersString + ")" fullClientDB.TorrentHashString = TempHash.AsString() fullClientDB.StoragePath = element.StoragePath fullClientDB.TorrentName = element.TorrentName fullClientDB.DateAdded = element.DateAdded - fmt.Println("Download Speed: ", fullClientDB.DownloadSpeed) - fmt.Println("Percent Done: ", fullClientDB.PercentDone) - fmt.Println("UpdatedAt: ", fullClientDB.UpdatedAt) - - calculateTorrentStatus(singleTorrent, fullClientDB) //calculate the status of the torrent + fullClientDB.BytesCompleted = singleTorrent.BytesCompleted() + calculateTorrentETA(singleTorrent, fullClientDB) //calculating the ETA for the torrent + //fmt.Println("Download Speed: ", fullClientDB.DownloadSpeed) + //fmt.Println("Percent Done: ", fullClientDB.PercentDone) + //tclient.WriteStatus(os.Stdout) + calculateTorrentStatus(singleTorrent, fullClientDB) //calculate the status of the torrent, ie downloading seeding etc RunningTorrentArray = append(RunningTorrentArray, *fullClientDB) @@ -211,8 +279,6 @@ func createRunningTorrentArray(tclient *torrent.Client, TorrentLocalArray []*Tor } func updateClient(torrentstats []clientDB, conn *websocket.Conn) { //get the torrent client and the websocket connection to write msg - //first get the list of torrents in the client - conn.WriteJSON(torrentstats) //converting to JSON and writing to the client } @@ -237,11 +303,12 @@ func main() { var TorrentLocalArray = []*TorrentLocal{} //this is an array of ALL of the local storage torrents, they will be added back in via hash var RunningTorrentArray = []clientDB{} //this stores ALL of the torrents that are running, used for client update pushes combines Local Storage and Running tclient info + var PreviousTorrentArray = []clientDB{} TorrentLocalArray = readInTorrents(db) //pulling in all the already added torrents if TorrentLocalArray != nil { //the first creation of the running torrent array - RunningTorrentArray = createRunningTorrentArray(tclient, TorrentLocalArray, Config, db) //Updates the RunningTorrentArray with the current client data as well + RunningTorrentArray = createRunningTorrentArray(tclient, TorrentLocalArray, PreviousTorrentArray, Config, db) //Updates the RunningTorrentArray with the current client data as well } else { fmt.Println("Database is empty!") @@ -275,8 +342,8 @@ func main() { }) http.HandleFunc("/api", func(w http.ResponseWriter, r *http.Request) { //exposing the data to the TorrentLocalArray = readInTorrents(db) - RunningTorrentArray = createRunningTorrentArray(tclient, TorrentLocalArray, Config, db) //Updates the RunningTorrentArray with the current client data as well - var torrentlistArray = new(torrentList) + RunningTorrentArray = createRunningTorrentArray(tclient, TorrentLocalArray, PreviousTorrentArray, Config, db) //Updates the RunningTorrentArray with the current client data as well + var torrentlistArray = new(torrentList) //the full JSON that includes the number of torrents as the root torrentlistArray.ClientDBstruct = RunningTorrentArray torrentlistArray.Totaltorrents = len(RunningTorrentArray) torrentlistArrayJSON, _ := json.Marshal(torrentlistArray) @@ -308,7 +375,8 @@ func main() { } TorrentLocalArray = readInTorrents(db) - RunningTorrentArray = createRunningTorrentArray(tclient, TorrentLocalArray, Config, db) //Updates the RunningTorrentArray with the current client data as well + RunningTorrentArray = createRunningTorrentArray(tclient, TorrentLocalArray, PreviousTorrentArray, Config, db) //Updates the RunningTorrentArray with the current client data as well + PreviousTorrentArray = RunningTorrentArray var torrentlistArray = new(torrentList) torrentlistArray.ClientDBstruct = RunningTorrentArray torrentlistArray.Totaltorrents = len(RunningTorrentArray) diff --git a/public/static/js/bundle.js b/public/static/js/bundle.js index 734c336b..93765b65 100644 --- a/public/static/js/bundle.js +++ b/public/static/js/bundle.js @@ -433,7 +433,7 @@ var _contextTypes = __webpack_require__(459); var _contextTypes2 = _interopRequireDefault(_contextTypes); -var _jss = __webpack_require__(117); +var _jss = __webpack_require__(118); var _jssPresetDefault = __webpack_require__(226); @@ -443,11 +443,11 @@ var _ns = __webpack_require__(227); var ns = _interopRequireWildcard(_ns); -var _createMuiTheme = __webpack_require__(123); +var _createMuiTheme = __webpack_require__(124); var _createMuiTheme2 = _interopRequireDefault(_createMuiTheme); -var _themeListener = __webpack_require__(116); +var _themeListener = __webpack_require__(117); var _themeListener2 = _interopRequireDefault(_themeListener); @@ -463,7 +463,7 @@ function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } -var babelPluginFlowReactPropTypes_proptype_HigherOrderComponent = __webpack_require__(76).babelPluginFlowReactPropTypes_proptype_HigherOrderComponent || __webpack_require__(0).any; // weak +var babelPluginFlowReactPropTypes_proptype_HigherOrderComponent = __webpack_require__(78).babelPluginFlowReactPropTypes_proptype_HigherOrderComponent || __webpack_require__(0).any; // weak // New JSS instance. var jss = (0, _jss.create)((0, _jssPresetDefault2.default)()); @@ -792,7 +792,7 @@ exports.default = withStyles; exports.__esModule = true; -var _defineProperty = __webpack_require__(106); +var _defineProperty = __webpack_require__(107); var _defineProperty2 = _interopRequireDefault(_defineProperty); @@ -898,7 +898,7 @@ exports.default = function (instance, Constructor) { exports.__esModule = true; -var _defineProperty = __webpack_require__(106); +var _defineProperty = __webpack_require__(107); var _defineProperty2 = _interopRequireDefault(_defineProperty); @@ -931,7 +931,7 @@ exports.default = function () { exports.__esModule = true; -var _typeof2 = __webpack_require__(68); +var _typeof2 = __webpack_require__(70); var _typeof3 = _interopRequireDefault(_typeof2); @@ -962,7 +962,7 @@ var _create = __webpack_require__(428); var _create2 = _interopRequireDefault(_create); -var _typeof2 = __webpack_require__(68); +var _typeof2 = __webpack_require__(70); var _typeof3 = _interopRequireDefault(_typeof2); @@ -1010,11 +1010,11 @@ if (process.env.NODE_ENV !== 'production') { // By explicitly using `prop-types` you are opting into new development behavior. // http://fb.me/prop-types-in-prod var throwOnDirectAccess = true; - module.exports = __webpack_require__(613)(isValidElement, throwOnDirectAccess); + module.exports = __webpack_require__(614)(isValidElement, throwOnDirectAccess); } else { // By explicitly using `prop-types` you are opting into new production behavior. // http://fb.me/prop-types-in-prod - module.exports = __webpack_require__(616)(); + module.exports = __webpack_require__(617)(); } /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(2))) @@ -1290,6 +1290,48 @@ var _temp = function () { /***/ }), /* 19 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; +/* WEBPACK VAR INJECTION */(function(process) { + +exports.__esModule = true; + +var _shouldUpdate = __webpack_require__(560); + +var _shouldUpdate2 = _interopRequireDefault(_shouldUpdate); + +var _shallowEqual = __webpack_require__(563); + +var _shallowEqual2 = _interopRequireDefault(_shallowEqual); + +var _setDisplayName = __webpack_require__(251); + +var _setDisplayName2 = _interopRequireDefault(_setDisplayName); + +var _wrapDisplayName = __webpack_require__(252); + +var _wrapDisplayName2 = _interopRequireDefault(_wrapDisplayName); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +var pure = function pure(BaseComponent) { + var hoc = (0, _shouldUpdate2.default)(function (props, nextProps) { + return !(0, _shallowEqual2.default)(props, nextProps); + }); + + if (process.env.NODE_ENV !== 'production') { + return (0, _setDisplayName2.default)((0, _wrapDisplayName2.default)(BaseComponent, 'pure'))(hoc(BaseComponent)); + } + + return hoc(BaseComponent); +}; + +exports.default = pure; +/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(2))) + +/***/ }), +/* 20 */ /***/ (function(module, exports) { var core = module.exports = { version: '2.5.1' }; @@ -1297,7 +1339,7 @@ if (typeof __e == 'number') __e = core; // eslint-disable-line no-undef /***/ }), -/* 20 */ +/* 21 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -1307,7 +1349,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); -var _typeof2 = __webpack_require__(68); +var _typeof2 = __webpack_require__(70); var _typeof3 = _interopRequireDefault(_typeof2); @@ -1392,7 +1434,7 @@ function createChainedFunction() { /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(2))) /***/ }), -/* 21 */ +/* 22 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -1414,54 +1456,12 @@ var babelPluginFlowReactPropTypes_proptype_TransitionClasses = { exitActive: __webpack_require__(0).string }; -/***/ }), -/* 22 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/* WEBPACK VAR INJECTION */(function(process) { - -exports.__esModule = true; - -var _shouldUpdate = __webpack_require__(560); - -var _shouldUpdate2 = _interopRequireDefault(_shouldUpdate); - -var _shallowEqual = __webpack_require__(563); - -var _shallowEqual2 = _interopRequireDefault(_shallowEqual); - -var _setDisplayName = __webpack_require__(251); - -var _setDisplayName2 = _interopRequireDefault(_setDisplayName); - -var _wrapDisplayName = __webpack_require__(252); - -var _wrapDisplayName2 = _interopRequireDefault(_wrapDisplayName); - -function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } - -var pure = function pure(BaseComponent) { - var hoc = (0, _shouldUpdate2.default)(function (props, nextProps) { - return !(0, _shallowEqual2.default)(props, nextProps); - }); - - if (process.env.NODE_ENV !== 'production') { - return (0, _setDisplayName2.default)((0, _wrapDisplayName2.default)(BaseComponent, 'pure'))(hoc(BaseComponent)); - } - - return hoc(BaseComponent); -}; - -exports.default = pure; -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(2))) - /***/ }), /* 23 */ /***/ (function(module, exports, __webpack_require__) { var global = __webpack_require__(29); -var core = __webpack_require__(19); +var core = __webpack_require__(20); var ctx = __webpack_require__(40); var hide = __webpack_require__(36); var PROTOTYPE = 'prototype'; @@ -1582,8 +1582,8 @@ var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*! /* 25 */ /***/ (function(module, exports, __webpack_require__) { -var store = __webpack_require__(103)('wks'); -var uid = __webpack_require__(66); +var store = __webpack_require__(104)('wks'); +var uid = __webpack_require__(68); var Symbol = __webpack_require__(29).Symbol; var USE_SYMBOL = typeof Symbol == 'function'; @@ -1601,7 +1601,7 @@ $exports.store = store; var anObject = __webpack_require__(41); var IE8_DOM_DEFINE = __webpack_require__(193); -var toPrimitive = __webpack_require__(97); +var toPrimitive = __webpack_require__(98); var dP = Object.defineProperty; exports.f = __webpack_require__(30) ? Object.defineProperty : function defineProperty(O, P, Attributes) { @@ -1969,7 +1969,7 @@ var _inherits2 = __webpack_require__(12); var _inherits3 = _interopRequireDefault(_inherits2); -var _typeof2 = __webpack_require__(68); +var _typeof2 = __webpack_require__(70); var _typeof3 = _interopRequireDefault(_typeof2); @@ -2227,7 +2227,7 @@ Object.defineProperty(exports, 'withTheme', { } }); -var _createMuiTheme = __webpack_require__(123); +var _createMuiTheme = __webpack_require__(124); Object.defineProperty(exports, 'createMuiTheme', { enumerable: true, @@ -2439,7 +2439,7 @@ module.exports = exports['default']; /* 47 */ /***/ (function(module, exports, __webpack_require__) { -var isObject = __webpack_require__(129), +var isObject = __webpack_require__(130), now = __webpack_require__(515), toNumber = __webpack_require__(517); @@ -2691,8 +2691,8 @@ if (process.env.NODE_ENV !== 'production') { /***/ (function(module, exports, __webpack_require__) { // to indexed object, toObject with fallback for non-array-like ES3 strings -var IObject = __webpack_require__(98); -var defined = __webpack_require__(100); +var IObject = __webpack_require__(99); +var defined = __webpack_require__(101); module.exports = function (it) { return IObject(defined(it)); }; @@ -2703,7 +2703,7 @@ module.exports = function (it) { /***/ (function(module, exports, __webpack_require__) { // 7.1.13 ToObject(argument) -var defined = __webpack_require__(100); +var defined = __webpack_require__(101); module.exports = function (it) { return Object(defined(it)); }; @@ -3071,7 +3071,7 @@ exports.synchronizeLayoutWithChildren = synchronizeLayoutWithChildren; exports.validateLayout = validateLayout; exports.autoBindHandlers = autoBindHandlers; -var _lodash = __webpack_require__(86); +var _lodash = __webpack_require__(88); var _lodash2 = _interopRequireDefault(_lodash); @@ -3574,7 +3574,7 @@ module.exports = function (bitmap, value) { // 19.1.2.14 / 15.2.3.14 Object.keys(O) var $keys = __webpack_require__(195); -var enumBugKeys = __webpack_require__(104); +var enumBugKeys = __webpack_require__(105); module.exports = Object.keys || function keys(O) { return $keys(O, enumBugKeys); @@ -3631,11 +3631,11 @@ var _wrapDisplayName = __webpack_require__(52); var _wrapDisplayName2 = _interopRequireDefault(_wrapDisplayName); -var _createMuiTheme = __webpack_require__(123); +var _createMuiTheme = __webpack_require__(124); var _createMuiTheme2 = _interopRequireDefault(_createMuiTheme); -var _themeListener = __webpack_require__(116); +var _themeListener = __webpack_require__(117); var _themeListener2 = _interopRequireDefault(_themeListener); @@ -3644,7 +3644,7 @@ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { de // weak // flow sanity check (DO NOT DELETE) https://flow.org/try/#0JYWwDg9gTgLgBAJQKYEMDG8BmUIjgcilQ3wG4AoUSWOGATzCTgG84BhXSAOyS5gBUGTAL5xsuAkXQwy5OQHp5cALSq16jZuVwdccorgB3YDAAW-U0hBMAEgHk25JAA9qWAK5cMwCFyMnzS2sAHgAFHDAAZwAuFmEAPgAKcl12Tl9eGFiOcAy+QUZg1jMrJFi7ACMAKyQMOFEAMjhwiCj4gBpyAEps9J58oTCIyPiWOR00ABsUSMi4AHUAi1K4FxheABM55GkAOhzuTKHWyPaWWiCyuEqauoSx1KIuDaQoRK6H1LgiGHcoP2CBzy8GYuzBZmAkV2YGGohK1gAvMwIVDIjAUOtdvCkKJ5PEKKlhAT6ilvkhfv8FktLuRhAolFpGUy1PolMYzMtrHAAKqRFAAcyQ5CmMzmAEFVs51s9tsQYPs+kdipdytVavBGiwULEuO4QBVXmcKjq9QaoPdmHS0L40XBOUgNkD+vAEf4OZdEmKuhQDPMmBtfPh4DwHbQIHAwKK4MA-AADbGx1YAN14Fwg7n5pjgsYAsnQnZlE0QAI7uYBEOYmXbkYL2x2KvhwFBIgCMogqSIATLj4vSVMyB6lWW7TIsNmY4PZHC43LQhHAAEJSADWkBjLoIzki+DgAB8CJEQDv9-gQBtjwRJvyL-hnJNZOR6IwqePTC0onBXcxSTGTMAUJMY5mAA-LES6oKuEDrp0OjGK+oGLiua58J0dJOK40AeF4MA+H47KjsAr7vJ8mCeN4virFwpgoF4SDHFEsRAW+wxJKSqQFnwvS5M6BR0cwcFmGBSFQShcBgrs76RAkMFwD0aTcZkvH0SMYxsXAIqzFSZhMZK0pbIgcoKgpfDKaM35fGSzyvMR5kWepNogr+OEAUxZwCaYoiuii0LDGpjzkn8AIcSC4neTCJyiO5SL4Ie+A9sShIJSSak-IFWkEa+xJEuMZIUn4vDUbRFBoQYA5leow7uHygrCtMmkLrpmyynswVFO5QkQchMBnNqcC6vqhrGn1pqvBapJPC8bwfLZEwOSw7meRckI+ScKUBZSwQbMASZwHipJ0lac1MQ6wWfiOTHvIkC7esOfpwAGXBBn1SChjA4aRppMbZu5iZICmfhmOmmbZnmwVFkgpblkglbyjWx31sZ8DNswbZwB2zDdrt+JAA -var babelPluginFlowReactPropTypes_proptype_HigherOrderComponent = __webpack_require__(76).babelPluginFlowReactPropTypes_proptype_HigherOrderComponent || __webpack_require__(0).any; +var babelPluginFlowReactPropTypes_proptype_HigherOrderComponent = __webpack_require__(78).babelPluginFlowReactPropTypes_proptype_HigherOrderComponent || __webpack_require__(0).any; var defaultTheme = void 0; @@ -3733,7 +3733,7 @@ Object.defineProperty(exports, "__esModule", { value: true }); -var _Input = __webpack_require__(128); +var _Input = __webpack_require__(129); Object.defineProperty(exports, 'default', { enumerable: true, @@ -4260,10 +4260,43 @@ function updateLink (link, options, obj) { /***/ }), /* 65 */ +/***/ (function(module, __webpack_exports__, __webpack_require__) { + +"use strict"; +Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__components_Provider__ = __webpack_require__(348); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__components_connectAdvanced__ = __webpack_require__(187); +/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__connect_connect__ = __webpack_require__(356); +/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "Provider", function() { return __WEBPACK_IMPORTED_MODULE_0__components_Provider__["b"]; }); +/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "createProvider", function() { return __WEBPACK_IMPORTED_MODULE_0__components_Provider__["a"]; }); +/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "connectAdvanced", function() { return __WEBPACK_IMPORTED_MODULE_1__components_connectAdvanced__["a"]; }); +/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "connect", function() { return __WEBPACK_IMPORTED_MODULE_2__connect_connect__["a"]; }); + + + + + + +/***/ }), +/* 66 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +Object.defineProperty(exports, "__esModule", { + value: true +}); +var SORTLIST = exports.SORTLIST = 'SORTLIST'; +var CHANGE_SELECTION = exports.CHANGE_SELECTION = 'CHANGE_SELECTION'; +var CHANGE_FILTER = exports.CHANGE_FILTER = 'CHANGE_FILTER'; + +/***/ }), +/* 67 */ /***/ (function(module, exports, __webpack_require__) { // 7.1.15 ToLength -var toInteger = __webpack_require__(101); +var toInteger = __webpack_require__(102); var min = Math.min; module.exports = function (it) { return it > 0 ? min(toInteger(it), 0x1fffffffffffff) : 0; // pow(2, 53) - 1 == 9007199254740991 @@ -4271,7 +4304,7 @@ module.exports = function (it) { /***/ }), -/* 66 */ +/* 68 */ /***/ (function(module, exports) { var id = 0; @@ -4282,14 +4315,14 @@ module.exports = function (key) { /***/ }), -/* 67 */ +/* 69 */ /***/ (function(module, exports) { exports.f = {}.propertyIsEnumerable; /***/ }), -/* 68 */ +/* 70 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -4316,14 +4349,14 @@ exports.default = typeof _symbol2.default === "function" && _typeof(_iterator2.d }; /***/ }), -/* 69 */ +/* 71 */ /***/ (function(module, exports, __webpack_require__) { // 19.1.2.2 / 15.2.3.5 Object.create(O [, Properties]) var anObject = __webpack_require__(41); var dPs = __webpack_require__(413); -var enumBugKeys = __webpack_require__(104); -var IE_PROTO = __webpack_require__(102)('IE_PROTO'); +var enumBugKeys = __webpack_require__(105); +var IE_PROTO = __webpack_require__(103)('IE_PROTO'); var Empty = function () { /* empty */ }; var PROTOTYPE = 'prototype'; @@ -4363,7 +4396,7 @@ module.exports = Object.create || function create(O, Properties) { /***/ }), -/* 70 */ +/* 72 */ /***/ (function(module, exports, __webpack_require__) { var def = __webpack_require__(26).f; @@ -4376,14 +4409,14 @@ module.exports = function (it, tag, stat) { /***/ }), -/* 71 */ +/* 73 */ /***/ (function(module, exports, __webpack_require__) { var ctx = __webpack_require__(40); var call = __webpack_require__(208); var isArrayIter = __webpack_require__(209); var anObject = __webpack_require__(41); -var toLength = __webpack_require__(65); +var toLength = __webpack_require__(67); var getIterFn = __webpack_require__(210); var BREAK = {}; var RETURN = {}; @@ -4407,7 +4440,7 @@ exports.RETURN = RETURN; /***/ }), -/* 72 */ +/* 74 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -4433,7 +4466,7 @@ var _linkRule = __webpack_require__(219); var _linkRule2 = _interopRequireDefault(_linkRule); -var _StyleRule = __webpack_require__(118); +var _StyleRule = __webpack_require__(119); var _StyleRule2 = _interopRequireDefault(_StyleRule); @@ -4637,7 +4670,7 @@ var RuleList = function () { exports['default'] = RuleList; /***/ }), -/* 73 */ +/* 75 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -4651,7 +4684,7 @@ var isBrowser = (typeof window === "undefined" ? "undefined" : _typeof(window)) /***/ }), -/* 74 */ +/* 76 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -4748,7 +4781,7 @@ var deepmerge_1 = deepmerge; /***/ }), -/* 75 */ +/* 77 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -4992,13 +5025,13 @@ function lighten(color, coefficient) { } /***/ }), -/* 76 */ +/* 78 */ /***/ (function(module, exports) { /***/ }), -/* 77 */ +/* 79 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -5038,7 +5071,7 @@ function fallback(context, node) { module.exports = exports['default']; /***/ }), -/* 78 */ +/* 80 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -5602,7 +5635,7 @@ exports.default = Transition; /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(2))) /***/ }), -/* 79 */ +/* 81 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -5624,7 +5657,7 @@ Object.defineProperty(exports, 'default', { function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /***/ }), -/* 80 */ +/* 82 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -5640,7 +5673,7 @@ function ownerDocument(node) { module.exports = exports["default"]; /***/ }), -/* 81 */ +/* 83 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -5715,94 +5748,94 @@ Object.defineProperty(exports, 'ListSubheader', { function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } -/***/ }), -/* 82 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * - */ - -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. - */ -var emptyFunction = 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; - -/***/ }), -/* 83 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; - - -/** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - * - * - */ - -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. - */ -var emptyFunction = 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; - /***/ }), /* 84 */ /***/ (function(module, exports, __webpack_require__) { +"use strict"; + + +/** + * Copyright (c) 2013-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * + */ + +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. + */ +var emptyFunction = 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; + +/***/ }), +/* 85 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/** + * Copyright (c) 2013-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * + */ + +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. + */ +var emptyFunction = 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; + +/***/ }), +/* 86 */ +/***/ (function(module, exports, __webpack_require__) { + "use strict"; /* WEBPACK VAR INJECTION */(function(process) {/** * Copyright (c) 2013-present, Facebook, Inc. @@ -5860,7 +5893,7 @@ module.exports = invariant; /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(2))) /***/ }), -/* 85 */ +/* 87 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -5879,7 +5912,7 @@ module.exports = ReactPropTypesSecret; /***/ }), -/* 86 */ +/* 88 */ /***/ (function(module, exports, __webpack_require__) { /* WEBPACK VAR INJECTION */(function(global, module) {/** @@ -7731,10 +7764,10 @@ function stubFalse() { module.exports = isEqual; -/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(17), __webpack_require__(87)(module))) +/* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(17), __webpack_require__(89)(module))) /***/ }), -/* 87 */ +/* 89 */ /***/ (function(module, exports) { module.exports = function(module) { @@ -7762,7 +7795,7 @@ module.exports = function(module) { /***/ }), -/* 88 */ +/* 90 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -7804,7 +7837,7 @@ emptyFunction.thatReturnsArgument = function (arg) { module.exports = emptyFunction; /***/ }), -/* 89 */ +/* 91 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -7863,48 +7896,29 @@ function invariant(condition, format, a, b, c, d, e, f) { module.exports = invariant; /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(2))) -/***/ }), -/* 90 */ -/***/ (function(module, exports, __webpack_require__) { - -"use strict"; -/** - * Copyright (c) 2013-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ - - - -var ReactPropTypesSecret = 'SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED'; - -module.exports = ReactPropTypesSecret; - - -/***/ }), -/* 91 */ -/***/ (function(module, __webpack_exports__, __webpack_require__) { - -"use strict"; -Object.defineProperty(__webpack_exports__, "__esModule", { value: true }); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__components_Provider__ = __webpack_require__(348); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_1__components_connectAdvanced__ = __webpack_require__(186); -/* harmony import */ var __WEBPACK_IMPORTED_MODULE_2__connect_connect__ = __webpack_require__(356); -/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "Provider", function() { return __WEBPACK_IMPORTED_MODULE_0__components_Provider__["b"]; }); -/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "createProvider", function() { return __WEBPACK_IMPORTED_MODULE_0__components_Provider__["a"]; }); -/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "connectAdvanced", function() { return __WEBPACK_IMPORTED_MODULE_1__components_connectAdvanced__["a"]; }); -/* harmony reexport (binding) */ __webpack_require__.d(__webpack_exports__, "connect", function() { return __WEBPACK_IMPORTED_MODULE_2__connect_connect__["a"]; }); - - - - - - /***/ }), /* 92 */ /***/ (function(module, exports, __webpack_require__) { +"use strict"; +/** + * Copyright (c) 2013-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + + + +var ReactPropTypesSecret = 'SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED'; + +module.exports = ReactPropTypesSecret; + + +/***/ }), +/* 93 */ +/***/ (function(module, exports, __webpack_require__) { + "use strict"; @@ -7944,7 +7958,7 @@ emptyFunction.thatReturnsArgument = function (arg) { module.exports = emptyFunction; /***/ }), -/* 93 */ +/* 94 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -8004,7 +8018,7 @@ module.exports = invariant; /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(2))) /***/ }), -/* 94 */ +/* 95 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; @@ -8023,7 +8037,7 @@ module.exports = ReactPropTypesSecret; /***/ }), -/* 95 */ +/* 96 */ /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; @@ -8051,7 +8065,7 @@ function warning(message) { } /***/ }), -/* 96 */ +/* 97 */ /***/ (function(module, exports, __webpack_require__) { // style-loader: Adds some css to the DOM by adding a