├── .gitignore ├── LICENSE ├── README.md ├── StaticWebUI ├── README.md ├── index.html └── static │ ├── css │ └── myStyle.css │ └── js │ └── app.js ├── WebUI ├── .babelrc ├── .editorconfig ├── .gitignore ├── README.md ├── build │ ├── build.js │ ├── check-versions.js │ ├── dev-client.js │ ├── dev-server.js │ ├── utils.js │ ├── webpack.base.conf.js │ ├── webpack.dev.conf.js │ └── webpack.prod.conf.js ├── config │ ├── dev.env.js │ ├── index.js │ └── prod.env.js ├── index.html ├── package.json ├── src │ ├── App.vue │ ├── components │ │ ├── Body.vue │ │ ├── Footer.vue │ │ ├── Header.vue │ │ └── Hello.vue │ └── main.js └── static │ ├── .gitkeep │ ├── css │ └── bootstrap.min.css │ └── js │ ├── bootstrap.min.js │ ├── jquery.min.js │ ├── jquery.min.map │ └── myapp.js └── server ├── .gitignore ├── README.md ├── config.js ├── jsconfig.json ├── package.json ├── public ├── css │ ├── bootstrap.min.css │ ├── bootstrap.min.css.map │ ├── ie10-viewport-bug-workaround.css │ └── jumbotron.css ├── favicon.ico ├── js │ ├── app.js │ ├── bootstrap.min.js │ ├── dragdrop.min.js │ ├── html5shiv.min.js │ ├── ie-emulation-modes-warning.js │ ├── ie10-viewport-bug-workaround.js │ ├── jquery.min.js │ ├── jquery.min.map │ ├── respond.min.js │ └── socket.io-1.4.5.js └── stylesheets │ ├── bootstrap.min.css │ ├── octicons.min.css │ └── style.css ├── server.js └── views ├── error.ejs ├── foot.ejs ├── head.ejs ├── index.ejs └── nav.ejs /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/node,macos,vim 3 | 4 | ### Node ### 5 | # Logs 6 | logs 7 | *.log 8 | npm-debug.log* 9 | 10 | # Runtime data 11 | pids 12 | *.pid 13 | *.seed 14 | *.pid.lock 15 | 16 | # Directory for instrumented libs generated by jscoverage/JSCover 17 | lib-cov 18 | 19 | # Coverage directory used by tools like istanbul 20 | coverage 21 | 22 | # nyc test coverage 23 | .nyc_output 24 | 25 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 26 | .grunt 27 | 28 | # node-waf configuration 29 | .lock-wscript 30 | 31 | # Compiled binary addons (http://nodejs.org/api/addons.html) 32 | build/Release 33 | 34 | # Dependency directories 35 | node_modules 36 | jspm_packages 37 | 38 | # Optional npm cache directory 39 | .npm 40 | 41 | # Optional eslint cache 42 | .eslintcache 43 | 44 | # Optional REPL history 45 | .node_repl_history 46 | 47 | # Output of 'npm pack' 48 | *.tgz 49 | 50 | # Yarn Integrity file 51 | .yarn-integrity 52 | 53 | 54 | 55 | ### macOS ### 56 | *.DS_Store 57 | .AppleDouble 58 | .LSOverride 59 | 60 | # Icon must end with two \r 61 | Icon 62 | # Thumbnails 63 | ._* 64 | # Files that might appear in the root of a volume 65 | .DocumentRevisions-V100 66 | .fseventsd 67 | .Spotlight-V100 68 | .TemporaryItems 69 | .Trashes 70 | .VolumeIcon.icns 71 | .com.apple.timemachine.donotpresent 72 | # Directories potentially created on remote AFP share 73 | .AppleDB 74 | .AppleDesktop 75 | Network Trash Folder 76 | Temporary Items 77 | .apdisk 78 | 79 | 80 | ### Vim ### 81 | # swap 82 | [._]*.s[a-v][a-z] 83 | [._]*.sw[a-p] 84 | [._]s[a-v][a-z] 85 | [._]sw[a-p] 86 | # session 87 | Session.vim 88 | # temporary 89 | .netrwhist 90 | *~ 91 | # auto-generated tag files 92 | tags 93 | 94 | ### VisualStudioCode ### 95 | .vscode/* 96 | !.vscode/settings.json 97 | !.vscode/tasks.json 98 | !.vscode/launch.json 99 | !.vscode/extensions.json 100 | 101 | # End of https://www.gitignore.io/api/node,macos,vim -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016-2017 BtOnline, LLC 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | 22 | 23 | MIT是和BSD一样宽松的许可协议,作者只想保留版权,而无任何其他了限制. 24 | 也就是说,你必须在你的发行版里包含原许可协议的声明,无论你是以二进制发布的还是以源代码发布的。 25 | 26 | * 你可以使用,复制和修改软件 27 | * 你可以免费使用软件或出售 28 | * 唯一的限制是,它是必须附有MIT授权协议 29 | 30 | 商业软件可以使用,也可以修改MIT协议的代码,甚至可以出售MIT协议的代码。 -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # BtOnline 2 | 3 | 在线直播Bt种子,后端未动 前端先行 4 | 5 | ![](https://i.imgur.com/nlxWTMV.png) 6 | 7 | ## 项目目录 8 | 9 | ```bash 10 | ├── README.md 11 | ├── StaticWebUI // 简单的前端 12 | │   ├── index.html 13 | │   └── static 14 | ├── WebUI // Vue.js 前端 15 | │   ├── README.md 16 | │   ├── build 17 | │   ├── config 18 | │   ├── dist //npm run build 后的文件夹 19 | │   ├── index.html 20 | │   ├── package.json 21 | │   ├── src 22 | │   └── static 23 | └── server //Node.js 服务端 24 | ├── README.md 25 | ├── config.js 26 | ├── package.json 27 | ├── public 28 | ├── server.js 29 | └── views 30 | ``` 31 | 32 | ## 如何使用 33 | 34 | ```bash 35 | # 克隆项目 36 | git clone https://github.com/qfdk/BtOnline.git 37 | # 进入相关的目录,都有相应的说明 38 | ``` 39 | 40 | 把里面的`StaticWebUI`复制到服务器http根目录,直接在线访问就好。 41 | 42 | ## Credit 43 | 44 | - [webtorrent](https://github.com/feross/webtorrent) 45 | 46 | - [torrent-stream](https://github.com/mafintosh/torrent-stream) 47 | 48 | ## License 49 | 50 | MIT. Copyright (c) [BtOnline](http://bt.qfdk.me), LLC. -------------------------------------------------------------------------------- /StaticWebUI/README.md: -------------------------------------------------------------------------------- 1 | ## StaticWebUI 2 | 3 | 静态页面,直接复制所有的文件到`wwwroot`文件夹下。 4 | 5 | PS:不支持Safari!不支持Safari!不支持Safari! -------------------------------------------------------------------------------- /StaticWebUI/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | BtOnline 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 20 | 21 | 22 | 23 | 24 | 50 | 51 |
52 |
53 |
54 |
55 |
56 |
57 | Downloading 58 | Seeding 59 | 60 | sintel.torrent 61 | 62 | from 63 | to 64 | 0 peers. 65 |
66 |
67 | of
↘ 68 | 0 b/s / ↗0 b/s 69 |
70 |
71 |
72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /StaticWebUI/static/css/myStyle.css: -------------------------------------------------------------------------------- 1 | #output video { 2 | width: 100%; 3 | } 4 | #progressBar { 5 | height: 5px; 6 | width: 0%; 7 | background-color: #35b44f; 8 | transition: width .4s ease-in-out; 9 | } 10 | body.is-seed .show-seed { 11 | display: inline; 12 | } 13 | body.is-seed .show-leech { 14 | display: none; 15 | } 16 | .show-seed { 17 | display: none; 18 | } 19 | #status code { 20 | font-size: 90%; 21 | font-weight: 700; 22 | margin-left: 3px; 23 | margin-right: 3px; 24 | border-bottom: 1px dashed rgba(255,255,255,0.3); 25 | } 26 | 27 | .is-seed #hero { 28 | background-color: #154820; 29 | transition: .5s .5s background-color ease-in-out; 30 | } 31 | #hero { 32 | background-color: #2a3749; 33 | } 34 | #status { 35 | color: #fff; 36 | font-size: 17px; 37 | padding: 5px; 38 | } 39 | a:link, a:visited { 40 | color: #30a247; 41 | text-decoration: none; 42 | } -------------------------------------------------------------------------------- /StaticWebUI/static/js/app.js: -------------------------------------------------------------------------------- 1 | $(function () { 2 | $("#go").on('click', function () { 3 | 4 | var torrentId = $("#btlink").val() 5 | 6 | var client = new WebTorrent() 7 | 8 | // HTML elements 9 | var $body = document.body 10 | var $progressBar = document.querySelector('#progressBar') 11 | var $numPeers = document.querySelector('#numPeers') 12 | var $downloaded = document.querySelector('#downloaded') 13 | var $total = document.querySelector('#total') 14 | var $remaining = document.querySelector('#remaining') 15 | var $uploadSpeed = document.querySelector('#uploadSpeed') 16 | var $downloadSpeed = document.querySelector('#downloadSpeed') 17 | 18 | // Download the torrent 19 | client.add(torrentId, function (torrent) { 20 | 21 | // Stream the file in the browser 22 | torrent.files[0].appendTo('#output') 23 | 24 | // Trigger statistics refresh 25 | torrent.on('done', onDone) 26 | setInterval(onProgress, 500) 27 | onProgress() 28 | 29 | // Statistics 30 | function onProgress() { 31 | // Peers 32 | $numPeers.innerHTML = torrent.numPeers + (torrent.numPeers === 1 ? ' peer' : ' peers') 33 | 34 | // Progress 35 | var percent = Math.round(torrent.progress * 100 * 100) / 100 36 | $progressBar.style.width = percent + '%' 37 | $downloaded.innerHTML = prettyBytes(torrent.downloaded) 38 | $total.innerHTML = prettyBytes(torrent.length) 39 | 40 | // Remaining time 41 | var remaining 42 | if (torrent.done) { 43 | remaining = 'Done.' 44 | } else { 45 | remaining = moment.duration(torrent.timeRemaining / 1000, 'seconds').humanize() 46 | remaining = remaining[0].toUpperCase() + remaining.substring(1) + ' remaining.' 47 | } 48 | $remaining.innerHTML = remaining 49 | 50 | // Speed rates 51 | $downloadSpeed.innerHTML = prettyBytes(torrent.downloadSpeed) + '/s' 52 | $uploadSpeed.innerHTML = prettyBytes(torrent.uploadSpeed) + '/s' 53 | } 54 | function onDone() { 55 | $body.className += ' is-seed' 56 | onProgress() 57 | } 58 | }) 59 | 60 | // Human readable bytes util 61 | function prettyBytes(num) { 62 | var exponent, unit, neg = num < 0, units = ['B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'] 63 | if (neg) num = -num 64 | if (num < 1) return (neg ? '-' : '') + num + ' B' 65 | exponent = Math.min(Math.floor(Math.log(num) / Math.log(1000)), units.length - 1) 66 | num = Number((num / Math.pow(1000, exponent)).toFixed(2)) 67 | unit = units[exponent] 68 | return (neg ? '-' : '') + num + ' ' + unit 69 | } 70 | 71 | }); 72 | }); -------------------------------------------------------------------------------- /WebUI/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "stage-2"], 3 | "plugins": ["transform-runtime"], 4 | "comments": false 5 | } 6 | -------------------------------------------------------------------------------- /WebUI/.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /WebUI/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | dist/ 4 | npm-debug.log 5 | 6 | # Created by https://www.gitignore.io/api/linux,node 7 | 8 | ### Linux ### 9 | *~ 10 | 11 | # temporary files which can be created if a process still has a handle open of a deleted file 12 | .fuse_hidden* 13 | 14 | # KDE directory preferences 15 | .directory 16 | 17 | # Linux trash folder which might appear on any partition or disk 18 | .Trash-* 19 | 20 | # .nfs files are created when an open file is removed but is still being accessed 21 | .nfs* 22 | 23 | 24 | ### Node ### 25 | # Logs 26 | logs 27 | *.log 28 | npm-debug.log* 29 | 30 | # Runtime data 31 | pids 32 | *.pid 33 | *.seed 34 | *.pid.lock 35 | 36 | # Directory for instrumented libs generated by jscoverage/JSCover 37 | lib-cov 38 | 39 | # Coverage directory used by tools like istanbul 40 | coverage 41 | 42 | # nyc test coverage 43 | .nyc_output 44 | 45 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 46 | .grunt 47 | 48 | # node-waf configuration 49 | .lock-wscript 50 | 51 | # Compiled binary addons (http://nodejs.org/api/addons.html) 52 | build/Release 53 | 54 | # Dependency directories 55 | node_modules 56 | jspm_packages 57 | 58 | # Optional npm cache directory 59 | .npm 60 | 61 | # Optional eslint cache 62 | .eslintcache 63 | 64 | # Optional REPL history 65 | .node_repl_history 66 | 67 | # Output of 'npm pack' 68 | *.tgz 69 | 70 | # Yarn Integrity file 71 | .yarn-integrity 72 | 73 | 74 | # End of https://www.gitignore.io/api/linux,node 75 | -------------------------------------------------------------------------------- /WebUI/README.md: -------------------------------------------------------------------------------- 1 | # WebUI for BtOnline 2 | 3 | ## Build Setup 4 | 5 | ``` bash 6 | # install dependencies 7 | # 安装所有的库 8 | npm install 9 | 10 | # serve with hot reload at localhost:8000 11 | npm run dev 12 | 13 | # build for production with minification 14 | # 生产模式 最后打包在dist文件夹里面,复制到wwwroot下 15 | npm run build 16 | ``` 17 | > Tip: 18 | > Built files are meant to be served over an HTTP server. 19 | > Opening index.html over file:// won't work. 20 | 21 | For detailed explanation on how things work, checkout the [guide](http://vuejs-templates.github.io/webpack/) and [docs for vue-loader](http://vuejs.github.io/vue-loader). 22 | -------------------------------------------------------------------------------- /WebUI/build/build.js: -------------------------------------------------------------------------------- 1 | // https://github.com/shelljs/shelljs 2 | require('./check-versions')() 3 | require('shelljs/global') 4 | env.NODE_ENV = 'production' 5 | 6 | var path = require('path') 7 | var config = require('../config') 8 | var ora = require('ora') 9 | var webpack = require('webpack') 10 | var webpackConfig = require('./webpack.prod.conf') 11 | 12 | console.log( 13 | ' Tip:\n' + 14 | ' Built files are meant to be served over an HTTP server.\n' + 15 | ' Opening index.html over file:// won\'t work.\n' 16 | ) 17 | 18 | var spinner = ora('building for production...') 19 | spinner.start() 20 | 21 | var assetsPath = path.join(config.build.assetsRoot, config.build.assetsSubDirectory) 22 | rm('-rf', assetsPath) 23 | mkdir('-p', assetsPath) 24 | cp('-R', 'static/*', assetsPath) 25 | 26 | webpack(webpackConfig, function (err, stats) { 27 | spinner.stop() 28 | if (err) throw err 29 | process.stdout.write(stats.toString({ 30 | colors: true, 31 | modules: false, 32 | children: false, 33 | chunks: false, 34 | chunkModules: false 35 | }) + '\n') 36 | }) 37 | -------------------------------------------------------------------------------- /WebUI/build/check-versions.js: -------------------------------------------------------------------------------- 1 | var semver = require('semver') 2 | var chalk = require('chalk') 3 | var packageConfig = require('../package.json') 4 | var exec = function (cmd) { 5 | return require('child_process') 6 | .execSync(cmd).toString().trim() 7 | } 8 | 9 | var versionRequirements = [ 10 | { 11 | name: 'node', 12 | currentVersion: semver.clean(process.version), 13 | versionRequirement: packageConfig.engines.node 14 | }, 15 | { 16 | name: 'npm', 17 | currentVersion: exec('npm --version'), 18 | versionRequirement: packageConfig.engines.npm 19 | } 20 | ] 21 | 22 | module.exports = function () { 23 | var warnings = [] 24 | for (var i = 0; i < versionRequirements.length; i++) { 25 | var mod = versionRequirements[i] 26 | if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) { 27 | warnings.push(mod.name + ': ' + 28 | chalk.red(mod.currentVersion) + ' should be ' + 29 | chalk.green(mod.versionRequirement) 30 | ) 31 | } 32 | } 33 | 34 | if (warnings.length) { 35 | console.log('') 36 | console.log(chalk.yellow('To use this template, you must update following to modules:')) 37 | console.log() 38 | for (var i = 0; i < warnings.length; i++) { 39 | var warning = warnings[i] 40 | console.log(' ' + warning) 41 | } 42 | console.log() 43 | process.exit(1) 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /WebUI/build/dev-client.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | require('eventsource-polyfill') 3 | var hotClient = require('webpack-hot-middleware/client?noInfo=true&reload=true') 4 | 5 | hotClient.subscribe(function (event) { 6 | if (event.action === 'reload') { 7 | window.location.reload() 8 | } 9 | }) 10 | -------------------------------------------------------------------------------- /WebUI/build/dev-server.js: -------------------------------------------------------------------------------- 1 | require('./check-versions')() 2 | var config = require('../config') 3 | if (!process.env.NODE_ENV) process.env.NODE_ENV = JSON.parse(config.dev.env.NODE_ENV) 4 | var path = require('path') 5 | var express = require('express') 6 | var webpack = require('webpack') 7 | var opn = require('opn') 8 | var proxyMiddleware = require('http-proxy-middleware') 9 | var webpackConfig = require('./webpack.dev.conf') 10 | 11 | // default port where dev server listens for incoming traffic 12 | var port = process.env.PORT || config.dev.port 13 | // Define HTTP proxies to your custom API backend 14 | // https://github.com/chimurai/http-proxy-middleware 15 | var proxyTable = config.dev.proxyTable 16 | 17 | var app = express() 18 | var compiler = webpack(webpackConfig) 19 | 20 | var devMiddleware = require('webpack-dev-middleware')(compiler, { 21 | publicPath: webpackConfig.output.publicPath, 22 | stats: { 23 | colors: true, 24 | chunks: false 25 | } 26 | }) 27 | 28 | var hotMiddleware = require('webpack-hot-middleware')(compiler) 29 | // force page reload when html-webpack-plugin template changes 30 | compiler.plugin('compilation', function (compilation) { 31 | compilation.plugin('html-webpack-plugin-after-emit', function (data, cb) { 32 | hotMiddleware.publish({ action: 'reload' }) 33 | cb() 34 | }) 35 | }) 36 | 37 | // proxy api requests 38 | Object.keys(proxyTable).forEach(function (context) { 39 | var options = proxyTable[context] 40 | if (typeof options === 'string') { 41 | options = { target: options } 42 | } 43 | app.use(proxyMiddleware(context, options)) 44 | }) 45 | 46 | // handle fallback for HTML5 history API 47 | app.use(require('connect-history-api-fallback')()) 48 | 49 | // serve webpack bundle output 50 | app.use(devMiddleware) 51 | 52 | // enable hot-reload and state-preserving 53 | // compilation error display 54 | app.use(hotMiddleware) 55 | 56 | // serve pure static assets 57 | var staticPath = path.posix.join(config.dev.assetsPublicPath, config.dev.assetsSubDirectory) 58 | app.use(staticPath, express.static('./static')) 59 | 60 | module.exports = app.listen(port, function (err) { 61 | if (err) { 62 | console.log(err) 63 | return 64 | } 65 | var uri = 'http://localhost:' + port 66 | console.log('Listening at ' + uri + '\n') 67 | 68 | // when env is testing, don't need open it 69 | if (process.env.NODE_ENV !== 'testing') { 70 | opn(uri) 71 | } 72 | }) 73 | -------------------------------------------------------------------------------- /WebUI/build/utils.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var config = require('../config') 3 | var ExtractTextPlugin = require('extract-text-webpack-plugin') 4 | 5 | exports.assetsPath = function (_path) { 6 | var assetsSubDirectory = process.env.NODE_ENV === 'production' 7 | ? config.build.assetsSubDirectory 8 | : config.dev.assetsSubDirectory 9 | return path.posix.join(assetsSubDirectory, _path) 10 | } 11 | 12 | exports.cssLoaders = function (options) { 13 | options = options || {} 14 | // generate loader string to be used with extract text plugin 15 | function generateLoaders (loaders) { 16 | var sourceLoader = loaders.map(function (loader) { 17 | var extraParamChar 18 | if (/\?/.test(loader)) { 19 | loader = loader.replace(/\?/, '-loader?') 20 | extraParamChar = '&' 21 | } else { 22 | loader = loader + '-loader' 23 | extraParamChar = '?' 24 | } 25 | return loader + (options.sourceMap ? extraParamChar + 'sourceMap' : '') 26 | }).join('!') 27 | 28 | // Extract CSS when that option is specified 29 | // (which is the case during production build) 30 | if (options.extract) { 31 | return ExtractTextPlugin.extract('vue-style-loader', sourceLoader) 32 | } else { 33 | return ['vue-style-loader', sourceLoader].join('!') 34 | } 35 | } 36 | 37 | // http://vuejs.github.io/vue-loader/en/configurations/extract-css.html 38 | return { 39 | css: generateLoaders(['css']), 40 | postcss: generateLoaders(['css']), 41 | less: generateLoaders(['css', 'less']), 42 | sass: generateLoaders(['css', 'sass?indentedSyntax']), 43 | scss: generateLoaders(['css', 'sass']), 44 | stylus: generateLoaders(['css', 'stylus']), 45 | styl: generateLoaders(['css', 'stylus']) 46 | } 47 | } 48 | 49 | // Generate loaders for standalone style files (outside of .vue) 50 | exports.styleLoaders = function (options) { 51 | var output = [] 52 | var loaders = exports.cssLoaders(options) 53 | for (var extension in loaders) { 54 | var loader = loaders[extension] 55 | output.push({ 56 | test: new RegExp('\\.' + extension + '$'), 57 | loader: loader 58 | }) 59 | } 60 | return output 61 | } 62 | -------------------------------------------------------------------------------- /WebUI/build/webpack.base.conf.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var config = require('../config') 3 | var utils = require('./utils') 4 | var projectRoot = path.resolve(__dirname, '../') 5 | 6 | var env = process.env.NODE_ENV 7 | // check env & config/index.js to decide whether to enable CSS source maps for the 8 | // various preprocessor loaders added to vue-loader at the end of this file 9 | var cssSourceMapDev = (env === 'development' && config.dev.cssSourceMap) 10 | var cssSourceMapProd = (env === 'production' && config.build.productionSourceMap) 11 | var useCssSourceMap = cssSourceMapDev || cssSourceMapProd 12 | 13 | module.exports = { 14 | entry: { 15 | app: './src/main.js' 16 | }, 17 | output: { 18 | path: config.build.assetsRoot, 19 | publicPath: process.env.NODE_ENV === 'production' ? config.build.assetsPublicPath : config.dev.assetsPublicPath, 20 | filename: '[name].js' 21 | }, 22 | resolve: { 23 | extensions: ['', '.js', '.vue', '.json'], 24 | fallback: [path.join(__dirname, '../node_modules')], 25 | alias: { 26 | 'vue$': 'vue/dist/vue.common.js', 27 | 'src': path.resolve(__dirname, '../src'), 28 | 'assets': path.resolve(__dirname, '../src/assets'), 29 | 'components': path.resolve(__dirname, '../src/components') 30 | } 31 | }, 32 | resolveLoader: { 33 | fallback: [path.join(__dirname, '../node_modules')] 34 | }, 35 | module: { 36 | loaders: [ 37 | { 38 | test: /\.vue$/, 39 | loader: 'vue' 40 | }, 41 | { 42 | test: /\.js$/, 43 | loader: 'babel', 44 | include: projectRoot, 45 | exclude: /node_modules(?!(.*vue-strap))/ 46 | }, 47 | { 48 | test: /\.json$/, 49 | loader: 'json' 50 | }, 51 | { 52 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, 53 | loader: 'url', 54 | query: { 55 | limit: 10000, 56 | name: utils.assetsPath('img/[name].[hash:7].[ext]') 57 | } 58 | }, 59 | { 60 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 61 | loader: 'url', 62 | query: { 63 | limit: 10000, 64 | name: utils.assetsPath('fonts/[name].[hash:7].[ext]') 65 | } 66 | } 67 | ] 68 | }, 69 | vue: { 70 | loaders: utils.cssLoaders({ sourceMap: useCssSourceMap }), 71 | postcss: [ 72 | require('autoprefixer')({ 73 | browsers: ['last 2 versions'] 74 | }) 75 | ] 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /WebUI/build/webpack.dev.conf.js: -------------------------------------------------------------------------------- 1 | var config = require('../config') 2 | var webpack = require('webpack') 3 | var merge = require('webpack-merge') 4 | var utils = require('./utils') 5 | var baseWebpackConfig = require('./webpack.base.conf') 6 | var HtmlWebpackPlugin = require('html-webpack-plugin') 7 | 8 | // add hot-reload related code to entry chunks 9 | Object.keys(baseWebpackConfig.entry).forEach(function (name) { 10 | baseWebpackConfig.entry[name] = ['./build/dev-client'].concat(baseWebpackConfig.entry[name]) 11 | }) 12 | 13 | module.exports = merge(baseWebpackConfig, { 14 | module: { 15 | loaders: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap }) 16 | }, 17 | // eval-source-map is faster for development 18 | devtool: '#eval-source-map', 19 | plugins: [ 20 | new webpack.DefinePlugin({ 21 | 'process.env': config.dev.env 22 | }), 23 | // https://github.com/glenjamin/webpack-hot-middleware#installation--usage 24 | new webpack.optimize.OccurrenceOrderPlugin(), 25 | new webpack.HotModuleReplacementPlugin(), 26 | new webpack.NoErrorsPlugin(), 27 | // https://github.com/ampedandwired/html-webpack-plugin 28 | new HtmlWebpackPlugin({ 29 | filename: 'index.html', 30 | template: 'index.html', 31 | inject: true 32 | }) 33 | ] 34 | }) 35 | -------------------------------------------------------------------------------- /WebUI/build/webpack.prod.conf.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | var config = require('../config') 3 | var utils = require('./utils') 4 | var webpack = require('webpack') 5 | var merge = require('webpack-merge') 6 | var baseWebpackConfig = require('./webpack.base.conf') 7 | var ExtractTextPlugin = require('extract-text-webpack-plugin') 8 | var HtmlWebpackPlugin = require('html-webpack-plugin') 9 | var env = config.build.env 10 | 11 | var webpackConfig = merge(baseWebpackConfig, { 12 | module: { 13 | loaders: utils.styleLoaders({ sourceMap: config.build.productionSourceMap, extract: true }) 14 | }, 15 | devtool: config.build.productionSourceMap ? '#source-map' : false, 16 | output: { 17 | path: config.build.assetsRoot, 18 | filename: utils.assetsPath('js/[name].[chunkhash].js'), 19 | chunkFilename: utils.assetsPath('js/[id].[chunkhash].js') 20 | }, 21 | vue: { 22 | loaders: utils.cssLoaders({ 23 | sourceMap: config.build.productionSourceMap, 24 | extract: true 25 | }) 26 | }, 27 | plugins: [ 28 | // http://vuejs.github.io/vue-loader/en/workflow/production.html 29 | new webpack.DefinePlugin({ 30 | 'process.env': env 31 | }), 32 | new webpack.optimize.UglifyJsPlugin({ 33 | compress: { 34 | warnings: false 35 | } 36 | }), 37 | new webpack.optimize.OccurrenceOrderPlugin(), 38 | // extract css into its own file 39 | new ExtractTextPlugin(utils.assetsPath('css/[name].[contenthash].css')), 40 | // generate dist index.html with correct asset hash for caching. 41 | // you can customize output by editing /index.html 42 | // see https://github.com/ampedandwired/html-webpack-plugin 43 | new HtmlWebpackPlugin({ 44 | filename: config.build.index, 45 | template: 'index.html', 46 | inject: true, 47 | minify: { 48 | removeComments: true, 49 | collapseWhitespace: true, 50 | removeAttributeQuotes: true 51 | // more options: 52 | // https://github.com/kangax/html-minifier#options-quick-reference 53 | }, 54 | // necessary to consistently work with multiple chunks via CommonsChunkPlugin 55 | chunksSortMode: 'dependency' 56 | }), 57 | // split vendor js into its own file 58 | new webpack.optimize.CommonsChunkPlugin({ 59 | name: 'vendor', 60 | minChunks: function (module, count) { 61 | // any required modules inside node_modules are extracted to vendor 62 | return ( 63 | module.resource && 64 | /\.js$/.test(module.resource) && 65 | module.resource.indexOf( 66 | path.join(__dirname, '../node_modules') 67 | ) === 0 68 | ) 69 | } 70 | }), 71 | // extract webpack runtime and module manifest to its own file in order to 72 | // prevent vendor hash from being updated whenever app bundle is updated 73 | new webpack.optimize.CommonsChunkPlugin({ 74 | name: 'manifest', 75 | chunks: ['vendor'] 76 | }) 77 | ] 78 | }) 79 | 80 | if (config.build.productionGzip) { 81 | var CompressionWebpackPlugin = require('compression-webpack-plugin') 82 | 83 | webpackConfig.plugins.push( 84 | new CompressionWebpackPlugin({ 85 | asset: '[path].gz[query]', 86 | algorithm: 'gzip', 87 | test: new RegExp( 88 | '\\.(' + 89 | config.build.productionGzipExtensions.join('|') + 90 | ')$' 91 | ), 92 | threshold: 10240, 93 | minRatio: 0.8 94 | }) 95 | ) 96 | } 97 | 98 | module.exports = webpackConfig 99 | -------------------------------------------------------------------------------- /WebUI/config/dev.env.js: -------------------------------------------------------------------------------- 1 | var merge = require('webpack-merge') 2 | var prodEnv = require('./prod.env') 3 | 4 | module.exports = merge(prodEnv, { 5 | NODE_ENV: '"development"' 6 | }) 7 | -------------------------------------------------------------------------------- /WebUI/config/index.js: -------------------------------------------------------------------------------- 1 | // see http://vuejs-templates.github.io/webpack for documentation. 2 | var path = require('path') 3 | 4 | module.exports = { 5 | build: { 6 | env: require('./prod.env'), 7 | index: path.resolve(__dirname, '../dist/index.html'), 8 | assetsRoot: path.resolve(__dirname, '../dist'), 9 | assetsSubDirectory: 'static', 10 | assetsPublicPath: '/', 11 | productionSourceMap: true, 12 | // Gzip off by default as many popular static hosts such as 13 | // Surge or Netlify already gzip all static assets for you. 14 | // Before setting to `true`, make sure to: 15 | // npm install --save-dev compression-webpack-plugin 16 | productionGzip: false, 17 | productionGzipExtensions: ['js', 'css'] 18 | }, 19 | dev: { 20 | env: require('./dev.env'), 21 | port: 8000, 22 | assetsSubDirectory: 'static', 23 | assetsPublicPath: '/', 24 | proxyTable: {}, 25 | // CSS Sourcemaps off by default because relative paths are "buggy" 26 | // with this option, according to the CSS-Loader README 27 | // (https://github.com/webpack/css-loader#sourcemaps) 28 | // In our experience, they generally work as expected, 29 | // just be aware of this issue when enabling this option. 30 | cssSourceMap: false 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /WebUI/config/prod.env.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | NODE_ENV: '"production"' 3 | } 4 | -------------------------------------------------------------------------------- /WebUI/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | BtOnline! 8 | 9 | 10 | 11 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /WebUI/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ui", 3 | "version": "1.0.0", 4 | "description": "webUI for fuzzing-api", 5 | "author": "HAOZHI Li ", 6 | "private": true, 7 | "scripts": { 8 | "dev": "node build/dev-server.js", 9 | "build": "node build/build.js" 10 | }, 11 | "dependencies": { 12 | "vue": "^2.1.0", 13 | "vue-resource": "^1.0.3", 14 | "vue-strap": "git+https://github.com/wffranco/vue-strap.git" 15 | }, 16 | "devDependencies": { 17 | "autoprefixer": "^6.4.0", 18 | "babel-core": "^6.0.0", 19 | "babel-loader": "^6.0.0", 20 | "babel-plugin-transform-runtime": "^6.0.0", 21 | "babel-preset-es2015": "^6.0.0", 22 | "babel-preset-stage-2": "^6.0.0", 23 | "babel-register": "^6.0.0", 24 | "chalk": "^1.1.3", 25 | "connect-history-api-fallback": "^1.1.0", 26 | "css-loader": "^0.25.0", 27 | "eventsource-polyfill": "^0.9.6", 28 | "express": "^4.13.3", 29 | "extract-text-webpack-plugin": "^1.0.1", 30 | "file-loader": "^0.9.0", 31 | "function-bind": "^1.0.2", 32 | "html-webpack-plugin": "^2.8.1", 33 | "http-proxy-middleware": "^0.17.2", 34 | "json-loader": "^0.5.4", 35 | "semver": "^5.3.0", 36 | "opn": "^4.0.2", 37 | "ora": "^0.3.0", 38 | "shelljs": "^0.7.4", 39 | "url-loader": "^0.5.7", 40 | "vue-loader": "^10.0.0", 41 | "vue-style-loader": "^1.0.0", 42 | "vue-template-compiler": "^2.1.0", 43 | "webpack": "^1.13.2", 44 | "webpack-dev-middleware": "^1.8.3", 45 | "webpack-hot-middleware": "^2.12.2", 46 | "webpack-merge": "^0.14.1" 47 | }, 48 | "engines": { 49 | "node": ">= 4.0.0", 50 | "npm": ">= 3.0.0" 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /WebUI/src/App.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 24 | 25 | 28 | -------------------------------------------------------------------------------- /WebUI/src/components/Body.vue: -------------------------------------------------------------------------------- 1 | 56 | 57 | 156 | 157 | 201 | 256 | 257 | 356 | 357 | 401 | -------------------------------------------------------------------------------- /WebUI/src/components/Footer.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 18 | 19 | 21 | -------------------------------------------------------------------------------- /WebUI/src/components/Header.vue: -------------------------------------------------------------------------------- 1 | 32 | 33 | 43 | 44 | 47 | -------------------------------------------------------------------------------- /WebUI/src/components/Hello.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 18 | 19 | 20 | 39 | -------------------------------------------------------------------------------- /WebUI/src/main.js: -------------------------------------------------------------------------------- 1 | // The Vue build version to load with the `import` command 2 | // (runtime-only or standalone) has been set in webpack.base.conf with an alias. 3 | import Vue from 'vue' 4 | import vueResource from 'vue-resource' 5 | import App from './App' 6 | 7 | Vue.use(vueResource) 8 | 9 | /* eslint-disable no-new */ 10 | new Vue({ 11 | el: '#app', 12 | template: '', 13 | components: { App } 14 | }) 15 | -------------------------------------------------------------------------------- /WebUI/static/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qfdk/BtOnline/285ab4b2c2fc17261b1377e1ee826d710a92160b/WebUI/static/.gitkeep -------------------------------------------------------------------------------- /WebUI/static/js/bootstrap.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.3.7 (http://getbootstrap.com) 3 | * Copyright 2011-2016 Twitter, Inc. 4 | * Licensed under the MIT license 5 | */ 6 | if("undefined"==typeof jQuery)throw new Error("Bootstrap's JavaScript requires jQuery");+function(a){"use strict";var b=a.fn.jquery.split(" ")[0].split(".");if(b[0]<2&&b[1]<9||1==b[0]&&9==b[1]&&b[2]<1||b[0]>3)throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher, but lower than version 4")}(jQuery),+function(a){"use strict";function b(){var a=document.createElement("bootstrap"),b={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"oTransitionEnd otransitionend",transition:"transitionend"};for(var c in b)if(void 0!==a.style[c])return{end:b[c]};return!1}a.fn.emulateTransitionEnd=function(b){var c=!1,d=this;a(this).one("bsTransitionEnd",function(){c=!0});var e=function(){c||a(d).trigger(a.support.transition.end)};return setTimeout(e,b),this},a(function(){a.support.transition=b(),a.support.transition&&(a.event.special.bsTransitionEnd={bindType:a.support.transition.end,delegateType:a.support.transition.end,handle:function(b){if(a(b.target).is(this))return b.handleObj.handler.apply(this,arguments)}})})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var c=a(this),e=c.data("bs.alert");e||c.data("bs.alert",e=new d(this)),"string"==typeof b&&e[b].call(c)})}var c='[data-dismiss="alert"]',d=function(b){a(b).on("click",c,this.close)};d.VERSION="3.3.7",d.TRANSITION_DURATION=150,d.prototype.close=function(b){function c(){g.detach().trigger("closed.bs.alert").remove()}var e=a(this),f=e.attr("data-target");f||(f=e.attr("href"),f=f&&f.replace(/.*(?=#[^\s]*$)/,""));var g=a("#"===f?[]:f);b&&b.preventDefault(),g.length||(g=e.closest(".alert")),g.trigger(b=a.Event("close.bs.alert")),b.isDefaultPrevented()||(g.removeClass("in"),a.support.transition&&g.hasClass("fade")?g.one("bsTransitionEnd",c).emulateTransitionEnd(d.TRANSITION_DURATION):c())};var e=a.fn.alert;a.fn.alert=b,a.fn.alert.Constructor=d,a.fn.alert.noConflict=function(){return a.fn.alert=e,this},a(document).on("click.bs.alert.data-api",c,d.prototype.close)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.button"),f="object"==typeof b&&b;e||d.data("bs.button",e=new c(this,f)),"toggle"==b?e.toggle():b&&e.setState(b)})}var c=function(b,d){this.$element=a(b),this.options=a.extend({},c.DEFAULTS,d),this.isLoading=!1};c.VERSION="3.3.7",c.DEFAULTS={loadingText:"loading..."},c.prototype.setState=function(b){var c="disabled",d=this.$element,e=d.is("input")?"val":"html",f=d.data();b+="Text",null==f.resetText&&d.data("resetText",d[e]()),setTimeout(a.proxy(function(){d[e](null==f[b]?this.options[b]:f[b]),"loadingText"==b?(this.isLoading=!0,d.addClass(c).attr(c,c).prop(c,!0)):this.isLoading&&(this.isLoading=!1,d.removeClass(c).removeAttr(c).prop(c,!1))},this),0)},c.prototype.toggle=function(){var a=!0,b=this.$element.closest('[data-toggle="buttons"]');if(b.length){var c=this.$element.find("input");"radio"==c.prop("type")?(c.prop("checked")&&(a=!1),b.find(".active").removeClass("active"),this.$element.addClass("active")):"checkbox"==c.prop("type")&&(c.prop("checked")!==this.$element.hasClass("active")&&(a=!1),this.$element.toggleClass("active")),c.prop("checked",this.$element.hasClass("active")),a&&c.trigger("change")}else this.$element.attr("aria-pressed",!this.$element.hasClass("active")),this.$element.toggleClass("active")};var d=a.fn.button;a.fn.button=b,a.fn.button.Constructor=c,a.fn.button.noConflict=function(){return a.fn.button=d,this},a(document).on("click.bs.button.data-api",'[data-toggle^="button"]',function(c){var d=a(c.target).closest(".btn");b.call(d,"toggle"),a(c.target).is('input[type="radio"], input[type="checkbox"]')||(c.preventDefault(),d.is("input,button")?d.trigger("focus"):d.find("input:visible,button:visible").first().trigger("focus"))}).on("focus.bs.button.data-api blur.bs.button.data-api",'[data-toggle^="button"]',function(b){a(b.target).closest(".btn").toggleClass("focus",/^focus(in)?$/.test(b.type))})}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.carousel"),f=a.extend({},c.DEFAULTS,d.data(),"object"==typeof b&&b),g="string"==typeof b?b:f.slide;e||d.data("bs.carousel",e=new c(this,f)),"number"==typeof b?e.to(b):g?e[g]():f.interval&&e.pause().cycle()})}var c=function(b,c){this.$element=a(b),this.$indicators=this.$element.find(".carousel-indicators"),this.options=c,this.paused=null,this.sliding=null,this.interval=null,this.$active=null,this.$items=null,this.options.keyboard&&this.$element.on("keydown.bs.carousel",a.proxy(this.keydown,this)),"hover"==this.options.pause&&!("ontouchstart"in document.documentElement)&&this.$element.on("mouseenter.bs.carousel",a.proxy(this.pause,this)).on("mouseleave.bs.carousel",a.proxy(this.cycle,this))};c.VERSION="3.3.7",c.TRANSITION_DURATION=600,c.DEFAULTS={interval:5e3,pause:"hover",wrap:!0,keyboard:!0},c.prototype.keydown=function(a){if(!/input|textarea/i.test(a.target.tagName)){switch(a.which){case 37:this.prev();break;case 39:this.next();break;default:return}a.preventDefault()}},c.prototype.cycle=function(b){return b||(this.paused=!1),this.interval&&clearInterval(this.interval),this.options.interval&&!this.paused&&(this.interval=setInterval(a.proxy(this.next,this),this.options.interval)),this},c.prototype.getItemIndex=function(a){return this.$items=a.parent().children(".item"),this.$items.index(a||this.$active)},c.prototype.getItemForDirection=function(a,b){var c=this.getItemIndex(b),d="prev"==a&&0===c||"next"==a&&c==this.$items.length-1;if(d&&!this.options.wrap)return b;var e="prev"==a?-1:1,f=(c+e)%this.$items.length;return this.$items.eq(f)},c.prototype.to=function(a){var b=this,c=this.getItemIndex(this.$active=this.$element.find(".item.active"));if(!(a>this.$items.length-1||a<0))return this.sliding?this.$element.one("slid.bs.carousel",function(){b.to(a)}):c==a?this.pause().cycle():this.slide(a>c?"next":"prev",this.$items.eq(a))},c.prototype.pause=function(b){return b||(this.paused=!0),this.$element.find(".next, .prev").length&&a.support.transition&&(this.$element.trigger(a.support.transition.end),this.cycle(!0)),this.interval=clearInterval(this.interval),this},c.prototype.next=function(){if(!this.sliding)return this.slide("next")},c.prototype.prev=function(){if(!this.sliding)return this.slide("prev")},c.prototype.slide=function(b,d){var e=this.$element.find(".item.active"),f=d||this.getItemForDirection(b,e),g=this.interval,h="next"==b?"left":"right",i=this;if(f.hasClass("active"))return this.sliding=!1;var j=f[0],k=a.Event("slide.bs.carousel",{relatedTarget:j,direction:h});if(this.$element.trigger(k),!k.isDefaultPrevented()){if(this.sliding=!0,g&&this.pause(),this.$indicators.length){this.$indicators.find(".active").removeClass("active");var l=a(this.$indicators.children()[this.getItemIndex(f)]);l&&l.addClass("active")}var m=a.Event("slid.bs.carousel",{relatedTarget:j,direction:h});return a.support.transition&&this.$element.hasClass("slide")?(f.addClass(b),f[0].offsetWidth,e.addClass(h),f.addClass(h),e.one("bsTransitionEnd",function(){f.removeClass([b,h].join(" ")).addClass("active"),e.removeClass(["active",h].join(" ")),i.sliding=!1,setTimeout(function(){i.$element.trigger(m)},0)}).emulateTransitionEnd(c.TRANSITION_DURATION)):(e.removeClass("active"),f.addClass("active"),this.sliding=!1,this.$element.trigger(m)),g&&this.cycle(),this}};var d=a.fn.carousel;a.fn.carousel=b,a.fn.carousel.Constructor=c,a.fn.carousel.noConflict=function(){return a.fn.carousel=d,this};var e=function(c){var d,e=a(this),f=a(e.attr("data-target")||(d=e.attr("href"))&&d.replace(/.*(?=#[^\s]+$)/,""));if(f.hasClass("carousel")){var g=a.extend({},f.data(),e.data()),h=e.attr("data-slide-to");h&&(g.interval=!1),b.call(f,g),h&&f.data("bs.carousel").to(h),c.preventDefault()}};a(document).on("click.bs.carousel.data-api","[data-slide]",e).on("click.bs.carousel.data-api","[data-slide-to]",e),a(window).on("load",function(){a('[data-ride="carousel"]').each(function(){var c=a(this);b.call(c,c.data())})})}(jQuery),+function(a){"use strict";function b(b){var c,d=b.attr("data-target")||(c=b.attr("href"))&&c.replace(/.*(?=#[^\s]+$)/,"");return a(d)}function c(b){return this.each(function(){var c=a(this),e=c.data("bs.collapse"),f=a.extend({},d.DEFAULTS,c.data(),"object"==typeof b&&b);!e&&f.toggle&&/show|hide/.test(b)&&(f.toggle=!1),e||c.data("bs.collapse",e=new d(this,f)),"string"==typeof b&&e[b]()})}var d=function(b,c){this.$element=a(b),this.options=a.extend({},d.DEFAULTS,c),this.$trigger=a('[data-toggle="collapse"][href="#'+b.id+'"],[data-toggle="collapse"][data-target="#'+b.id+'"]'),this.transitioning=null,this.options.parent?this.$parent=this.getParent():this.addAriaAndCollapsedClass(this.$element,this.$trigger),this.options.toggle&&this.toggle()};d.VERSION="3.3.7",d.TRANSITION_DURATION=350,d.DEFAULTS={toggle:!0},d.prototype.dimension=function(){var a=this.$element.hasClass("width");return a?"width":"height"},d.prototype.show=function(){if(!this.transitioning&&!this.$element.hasClass("in")){var b,e=this.$parent&&this.$parent.children(".panel").children(".in, .collapsing");if(!(e&&e.length&&(b=e.data("bs.collapse"),b&&b.transitioning))){var f=a.Event("show.bs.collapse");if(this.$element.trigger(f),!f.isDefaultPrevented()){e&&e.length&&(c.call(e,"hide"),b||e.data("bs.collapse",null));var g=this.dimension();this.$element.removeClass("collapse").addClass("collapsing")[g](0).attr("aria-expanded",!0),this.$trigger.removeClass("collapsed").attr("aria-expanded",!0),this.transitioning=1;var h=function(){this.$element.removeClass("collapsing").addClass("collapse in")[g](""),this.transitioning=0,this.$element.trigger("shown.bs.collapse")};if(!a.support.transition)return h.call(this);var i=a.camelCase(["scroll",g].join("-"));this.$element.one("bsTransitionEnd",a.proxy(h,this)).emulateTransitionEnd(d.TRANSITION_DURATION)[g](this.$element[0][i])}}}},d.prototype.hide=function(){if(!this.transitioning&&this.$element.hasClass("in")){var b=a.Event("hide.bs.collapse");if(this.$element.trigger(b),!b.isDefaultPrevented()){var c=this.dimension();this.$element[c](this.$element[c]())[0].offsetHeight,this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded",!1),this.$trigger.addClass("collapsed").attr("aria-expanded",!1),this.transitioning=1;var e=function(){this.transitioning=0,this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse")};return a.support.transition?void this.$element[c](0).one("bsTransitionEnd",a.proxy(e,this)).emulateTransitionEnd(d.TRANSITION_DURATION):e.call(this)}}},d.prototype.toggle=function(){this[this.$element.hasClass("in")?"hide":"show"]()},d.prototype.getParent=function(){return a(this.options.parent).find('[data-toggle="collapse"][data-parent="'+this.options.parent+'"]').each(a.proxy(function(c,d){var e=a(d);this.addAriaAndCollapsedClass(b(e),e)},this)).end()},d.prototype.addAriaAndCollapsedClass=function(a,b){var c=a.hasClass("in");a.attr("aria-expanded",c),b.toggleClass("collapsed",!c).attr("aria-expanded",c)};var e=a.fn.collapse;a.fn.collapse=c,a.fn.collapse.Constructor=d,a.fn.collapse.noConflict=function(){return a.fn.collapse=e,this},a(document).on("click.bs.collapse.data-api",'[data-toggle="collapse"]',function(d){var e=a(this);e.attr("data-target")||d.preventDefault();var f=b(e),g=f.data("bs.collapse"),h=g?"toggle":e.data();c.call(f,h)})}(jQuery),+function(a){"use strict";function b(b){var c=b.attr("data-target");c||(c=b.attr("href"),c=c&&/#[A-Za-z]/.test(c)&&c.replace(/.*(?=#[^\s]*$)/,""));var d=c&&a(c);return d&&d.length?d:b.parent()}function c(c){c&&3===c.which||(a(e).remove(),a(f).each(function(){var d=a(this),e=b(d),f={relatedTarget:this};e.hasClass("open")&&(c&&"click"==c.type&&/input|textarea/i.test(c.target.tagName)&&a.contains(e[0],c.target)||(e.trigger(c=a.Event("hide.bs.dropdown",f)),c.isDefaultPrevented()||(d.attr("aria-expanded","false"),e.removeClass("open").trigger(a.Event("hidden.bs.dropdown",f)))))}))}function d(b){return this.each(function(){var c=a(this),d=c.data("bs.dropdown");d||c.data("bs.dropdown",d=new g(this)),"string"==typeof b&&d[b].call(c)})}var e=".dropdown-backdrop",f='[data-toggle="dropdown"]',g=function(b){a(b).on("click.bs.dropdown",this.toggle)};g.VERSION="3.3.7",g.prototype.toggle=function(d){var e=a(this);if(!e.is(".disabled, :disabled")){var f=b(e),g=f.hasClass("open");if(c(),!g){"ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length&&a(document.createElement("div")).addClass("dropdown-backdrop").insertAfter(a(this)).on("click",c);var h={relatedTarget:this};if(f.trigger(d=a.Event("show.bs.dropdown",h)),d.isDefaultPrevented())return;e.trigger("focus").attr("aria-expanded","true"),f.toggleClass("open").trigger(a.Event("shown.bs.dropdown",h))}return!1}},g.prototype.keydown=function(c){if(/(38|40|27|32)/.test(c.which)&&!/input|textarea/i.test(c.target.tagName)){var d=a(this);if(c.preventDefault(),c.stopPropagation(),!d.is(".disabled, :disabled")){var e=b(d),g=e.hasClass("open");if(!g&&27!=c.which||g&&27==c.which)return 27==c.which&&e.find(f).trigger("focus"),d.trigger("click");var h=" li:not(.disabled):visible a",i=e.find(".dropdown-menu"+h);if(i.length){var j=i.index(c.target);38==c.which&&j>0&&j--,40==c.which&&jdocument.documentElement.clientHeight;this.$element.css({paddingLeft:!this.bodyIsOverflowing&&a?this.scrollbarWidth:"",paddingRight:this.bodyIsOverflowing&&!a?this.scrollbarWidth:""})},c.prototype.resetAdjustments=function(){this.$element.css({paddingLeft:"",paddingRight:""})},c.prototype.checkScrollbar=function(){var a=window.innerWidth;if(!a){var b=document.documentElement.getBoundingClientRect();a=b.right-Math.abs(b.left)}this.bodyIsOverflowing=document.body.clientWidth
',trigger:"hover focus",title:"",delay:0,html:!1,container:!1,viewport:{selector:"body",padding:0}},c.prototype.init=function(b,c,d){if(this.enabled=!0,this.type=b,this.$element=a(c),this.options=this.getOptions(d),this.$viewport=this.options.viewport&&a(a.isFunction(this.options.viewport)?this.options.viewport.call(this,this.$element):this.options.viewport.selector||this.options.viewport),this.inState={click:!1,hover:!1,focus:!1},this.$element[0]instanceof document.constructor&&!this.options.selector)throw new Error("`selector` option must be specified when initializing "+this.type+" on the window.document object!");for(var e=this.options.trigger.split(" "),f=e.length;f--;){var g=e[f];if("click"==g)this.$element.on("click."+this.type,this.options.selector,a.proxy(this.toggle,this));else if("manual"!=g){var h="hover"==g?"mouseenter":"focusin",i="hover"==g?"mouseleave":"focusout";this.$element.on(h+"."+this.type,this.options.selector,a.proxy(this.enter,this)),this.$element.on(i+"."+this.type,this.options.selector,a.proxy(this.leave,this))}}this.options.selector?this._options=a.extend({},this.options,{trigger:"manual",selector:""}):this.fixTitle()},c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.getOptions=function(b){return b=a.extend({},this.getDefaults(),this.$element.data(),b),b.delay&&"number"==typeof b.delay&&(b.delay={show:b.delay,hide:b.delay}),b},c.prototype.getDelegateOptions=function(){var b={},c=this.getDefaults();return this._options&&a.each(this._options,function(a,d){c[a]!=d&&(b[a]=d)}),b},c.prototype.enter=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);return c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusin"==b.type?"focus":"hover"]=!0),c.tip().hasClass("in")||"in"==c.hoverState?void(c.hoverState="in"):(clearTimeout(c.timeout),c.hoverState="in",c.options.delay&&c.options.delay.show?void(c.timeout=setTimeout(function(){"in"==c.hoverState&&c.show()},c.options.delay.show)):c.show())},c.prototype.isInStateTrue=function(){for(var a in this.inState)if(this.inState[a])return!0;return!1},c.prototype.leave=function(b){var c=b instanceof this.constructor?b:a(b.currentTarget).data("bs."+this.type);if(c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c)),b instanceof a.Event&&(c.inState["focusout"==b.type?"focus":"hover"]=!1),!c.isInStateTrue())return clearTimeout(c.timeout),c.hoverState="out",c.options.delay&&c.options.delay.hide?void(c.timeout=setTimeout(function(){"out"==c.hoverState&&c.hide()},c.options.delay.hide)):c.hide()},c.prototype.show=function(){var b=a.Event("show.bs."+this.type);if(this.hasContent()&&this.enabled){this.$element.trigger(b);var d=a.contains(this.$element[0].ownerDocument.documentElement,this.$element[0]);if(b.isDefaultPrevented()||!d)return;var e=this,f=this.tip(),g=this.getUID(this.type);this.setContent(),f.attr("id",g),this.$element.attr("aria-describedby",g),this.options.animation&&f.addClass("fade");var h="function"==typeof this.options.placement?this.options.placement.call(this,f[0],this.$element[0]):this.options.placement,i=/\s?auto?\s?/i,j=i.test(h);j&&(h=h.replace(i,"")||"top"),f.detach().css({top:0,left:0,display:"block"}).addClass(h).data("bs."+this.type,this),this.options.container?f.appendTo(this.options.container):f.insertAfter(this.$element),this.$element.trigger("inserted.bs."+this.type);var k=this.getPosition(),l=f[0].offsetWidth,m=f[0].offsetHeight;if(j){var n=h,o=this.getPosition(this.$viewport);h="bottom"==h&&k.bottom+m>o.bottom?"top":"top"==h&&k.top-mo.width?"left":"left"==h&&k.left-lg.top+g.height&&(e.top=g.top+g.height-i)}else{var j=b.left-f,k=b.left+f+c;jg.right&&(e.left=g.left+g.width-k)}return e},c.prototype.getTitle=function(){var a,b=this.$element,c=this.options;return a=b.attr("data-original-title")||("function"==typeof c.title?c.title.call(b[0]):c.title)},c.prototype.getUID=function(a){do a+=~~(1e6*Math.random());while(document.getElementById(a));return a},c.prototype.tip=function(){if(!this.$tip&&(this.$tip=a(this.options.template),1!=this.$tip.length))throw new Error(this.type+" `template` option must consist of exactly 1 top-level element!");return this.$tip},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".tooltip-arrow")},c.prototype.enable=function(){this.enabled=!0},c.prototype.disable=function(){this.enabled=!1},c.prototype.toggleEnabled=function(){this.enabled=!this.enabled},c.prototype.toggle=function(b){var c=this;b&&(c=a(b.currentTarget).data("bs."+this.type),c||(c=new this.constructor(b.currentTarget,this.getDelegateOptions()),a(b.currentTarget).data("bs."+this.type,c))),b?(c.inState.click=!c.inState.click,c.isInStateTrue()?c.enter(c):c.leave(c)):c.tip().hasClass("in")?c.leave(c):c.enter(c)},c.prototype.destroy=function(){var a=this;clearTimeout(this.timeout),this.hide(function(){a.$element.off("."+a.type).removeData("bs."+a.type),a.$tip&&a.$tip.detach(),a.$tip=null,a.$arrow=null,a.$viewport=null,a.$element=null})};var d=a.fn.tooltip;a.fn.tooltip=b,a.fn.tooltip.Constructor=c,a.fn.tooltip.noConflict=function(){return a.fn.tooltip=d,this}}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.popover"),f="object"==typeof b&&b;!e&&/destroy|hide/.test(b)||(e||d.data("bs.popover",e=new c(this,f)),"string"==typeof b&&e[b]())})}var c=function(a,b){this.init("popover",a,b)};if(!a.fn.tooltip)throw new Error("Popover requires tooltip.js");c.VERSION="3.3.7",c.DEFAULTS=a.extend({},a.fn.tooltip.Constructor.DEFAULTS,{placement:"right",trigger:"click",content:"",template:''}),c.prototype=a.extend({},a.fn.tooltip.Constructor.prototype),c.prototype.constructor=c,c.prototype.getDefaults=function(){return c.DEFAULTS},c.prototype.setContent=function(){var a=this.tip(),b=this.getTitle(),c=this.getContent();a.find(".popover-title")[this.options.html?"html":"text"](b),a.find(".popover-content").children().detach().end()[this.options.html?"string"==typeof c?"html":"append":"text"](c),a.removeClass("fade top bottom left right in"),a.find(".popover-title").html()||a.find(".popover-title").hide()},c.prototype.hasContent=function(){return this.getTitle()||this.getContent()},c.prototype.getContent=function(){var a=this.$element,b=this.options;return a.attr("data-content")||("function"==typeof b.content?b.content.call(a[0]):b.content)},c.prototype.arrow=function(){return this.$arrow=this.$arrow||this.tip().find(".arrow")};var d=a.fn.popover;a.fn.popover=b,a.fn.popover.Constructor=c,a.fn.popover.noConflict=function(){return a.fn.popover=d,this}}(jQuery),+function(a){"use strict";function b(c,d){this.$body=a(document.body),this.$scrollElement=a(a(c).is(document.body)?window:c),this.options=a.extend({},b.DEFAULTS,d),this.selector=(this.options.target||"")+" .nav li > a",this.offsets=[],this.targets=[],this.activeTarget=null,this.scrollHeight=0,this.$scrollElement.on("scroll.bs.scrollspy",a.proxy(this.process,this)),this.refresh(),this.process()}function c(c){return this.each(function(){var d=a(this),e=d.data("bs.scrollspy"),f="object"==typeof c&&c;e||d.data("bs.scrollspy",e=new b(this,f)),"string"==typeof c&&e[c]()})}b.VERSION="3.3.7",b.DEFAULTS={offset:10},b.prototype.getScrollHeight=function(){return this.$scrollElement[0].scrollHeight||Math.max(this.$body[0].scrollHeight,document.documentElement.scrollHeight)},b.prototype.refresh=function(){var b=this,c="offset",d=0;this.offsets=[],this.targets=[],this.scrollHeight=this.getScrollHeight(),a.isWindow(this.$scrollElement[0])||(c="position",d=this.$scrollElement.scrollTop()),this.$body.find(this.selector).map(function(){var b=a(this),e=b.data("target")||b.attr("href"),f=/^#./.test(e)&&a(e);return f&&f.length&&f.is(":visible")&&[[f[c]().top+d,e]]||null}).sort(function(a,b){return a[0]-b[0]}).each(function(){b.offsets.push(this[0]),b.targets.push(this[1])})},b.prototype.process=function(){var a,b=this.$scrollElement.scrollTop()+this.options.offset,c=this.getScrollHeight(),d=this.options.offset+c-this.$scrollElement.height(),e=this.offsets,f=this.targets,g=this.activeTarget;if(this.scrollHeight!=c&&this.refresh(),b>=d)return g!=(a=f[f.length-1])&&this.activate(a);if(g&&b=e[a]&&(void 0===e[a+1]||b .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!1),b.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded",!0),h?(b[0].offsetWidth,b.addClass("in")):b.removeClass("fade"),b.parent(".dropdown-menu").length&&b.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded",!0),e&&e()}var g=d.find("> .active"),h=e&&a.support.transition&&(g.length&&g.hasClass("fade")||!!d.find("> .fade").length);g.length&&h?g.one("bsTransitionEnd",f).emulateTransitionEnd(c.TRANSITION_DURATION):f(),g.removeClass("in")};var d=a.fn.tab;a.fn.tab=b,a.fn.tab.Constructor=c,a.fn.tab.noConflict=function(){return a.fn.tab=d,this};var e=function(c){c.preventDefault(),b.call(a(this),"show")};a(document).on("click.bs.tab.data-api",'[data-toggle="tab"]',e).on("click.bs.tab.data-api",'[data-toggle="pill"]',e)}(jQuery),+function(a){"use strict";function b(b){return this.each(function(){var d=a(this),e=d.data("bs.affix"),f="object"==typeof b&&b;e||d.data("bs.affix",e=new c(this,f)),"string"==typeof b&&e[b]()})}var c=function(b,d){this.options=a.extend({},c.DEFAULTS,d),this.$target=a(this.options.target).on("scroll.bs.affix.data-api",a.proxy(this.checkPosition,this)).on("click.bs.affix.data-api",a.proxy(this.checkPositionWithEventLoop,this)),this.$element=a(b),this.affixed=null,this.unpin=null,this.pinnedOffset=null,this.checkPosition()};c.VERSION="3.3.7",c.RESET="affix affix-top affix-bottom",c.DEFAULTS={offset:0,target:window},c.prototype.getState=function(a,b,c,d){var e=this.$target.scrollTop(),f=this.$element.offset(),g=this.$target.height();if(null!=c&&"top"==this.affixed)return e=a-d&&"bottom"},c.prototype.getPinnedOffset=function(){if(this.pinnedOffset)return this.pinnedOffset;this.$element.removeClass(c.RESET).addClass("affix");var a=this.$target.scrollTop(),b=this.$element.offset();return this.pinnedOffset=b.top-a},c.prototype.checkPositionWithEventLoop=function(){setTimeout(a.proxy(this.checkPosition,this),1)},c.prototype.checkPosition=function(){if(this.$element.is(":visible")){var b=this.$element.height(),d=this.options.offset,e=d.top,f=d.bottom,g=Math.max(a(document).height(),a(document.body).height());"object"!=typeof d&&(f=e=d),"function"==typeof e&&(e=d.top(this.$element)),"function"==typeof f&&(f=d.bottom(this.$element));var h=this.getState(g,b,e,f);if(this.affixed!=h){null!=this.unpin&&this.$element.css("top","");var i="affix"+(h?"-"+h:""),j=a.Event(i+".bs.affix");if(this.$element.trigger(j),j.isDefaultPrevented())return;this.affixed=h,this.unpin="bottom"==h?this.getPinnedOffset():null,this.$element.removeClass(c.RESET).addClass(i).trigger(i.replace("affix","affixed")+".bs.affix")}"bottom"==h&&this.$element.offset({top:g-b-f})}};var d=a.fn.affix;a.fn.affix=b,a.fn.affix.Constructor=c,a.fn.affix.noConflict=function(){return a.fn.affix=d,this},a(window).on("load",function(){a('[data-spy="affix"]').each(function(){var c=a(this),d=c.data();d.offset=d.offset||{},null!=d.offsetBottom&&(d.offset.bottom=d.offsetBottom),null!=d.offsetTop&&(d.offset.top=d.offsetTop),b.call(c,d)})})}(jQuery); -------------------------------------------------------------------------------- /WebUI/static/js/myapp.js: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qfdk/BtOnline/285ab4b2c2fc17261b1377e1ee826d710a92160b/WebUI/static/js/myapp.js -------------------------------------------------------------------------------- /server/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/node,macos,vim 3 | 4 | ### Node ### 5 | # Logs 6 | logs 7 | *.log 8 | npm-debug.log* 9 | 10 | # Runtime data 11 | pids 12 | *.pid 13 | *.seed 14 | *.pid.lock 15 | 16 | # Directory for instrumented libs generated by jscoverage/JSCover 17 | lib-cov 18 | 19 | # Coverage directory used by tools like istanbul 20 | coverage 21 | 22 | # nyc test coverage 23 | .nyc_output 24 | 25 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 26 | .grunt 27 | 28 | # node-waf configuration 29 | .lock-wscript 30 | 31 | # Compiled binary addons (http://nodejs.org/api/addons.html) 32 | build/Release 33 | 34 | # Dependency directories 35 | node_modules 36 | jspm_packages 37 | typings 38 | # Optional npm cache directory 39 | .npm 40 | 41 | # Optional eslint cache 42 | .eslintcache 43 | 44 | # Optional REPL history 45 | .node_repl_history 46 | 47 | # Output of 'npm pack' 48 | *.tgz 49 | 50 | # Yarn Integrity file 51 | .yarn-integrity 52 | 53 | 54 | 55 | ### macOS ### 56 | *.DS_Store 57 | .AppleDouble 58 | .LSOverride 59 | 60 | # Icon must end with two \r 61 | Icon 62 | # Thumbnails 63 | ._* 64 | # Files that might appear in the root of a volume 65 | .DocumentRevisions-V100 66 | .fseventsd 67 | .Spotlight-V100 68 | .TemporaryItems 69 | .Trashes 70 | .VolumeIcon.icns 71 | .com.apple.timemachine.donotpresent 72 | # Directories potentially created on remote AFP share 73 | .AppleDB 74 | .AppleDesktop 75 | Network Trash Folder 76 | Temporary Items 77 | .apdisk 78 | 79 | 80 | ### Vim ### 81 | # swap 82 | [._]*.s[a-v][a-z] 83 | [._]*.sw[a-p] 84 | [._]s[a-v][a-z] 85 | [._]sw[a-p] 86 | # session 87 | Session.vim 88 | # temporary 89 | .netrwhist 90 | *~ 91 | # auto-generated tag files 92 | tags 93 | 94 | ### VisualStudioCode ### 95 | .vscode/* 96 | !.vscode/settings.json 97 | !.vscode/tasks.json 98 | !.vscode/launch.json 99 | !.vscode/extensions.json 100 | 101 | # End of https://www.gitignore.io/api/node,macos,vim -------------------------------------------------------------------------------- /server/README.md: -------------------------------------------------------------------------------- 1 | # Server 2 | 3 | ## 安装 Node.js最新版本 4 | 5 | ```bash 6 | sudo apt-get install npm 7 | sudo npm install n -g 8 | sudo n latest 9 | ``` 10 | 11 | ## 编译并启动服务器 12 | 13 | ```bash 14 | npm install 15 | npm start 16 | ``` 17 | 18 | 默认端口: `3000`可以通过php 进行跳转,或者直接修改端口 :) 19 | 20 | 成功的话就可以看到界面了,虽然很丑陋,有时间进行修补。 -------------------------------------------------------------------------------- /server/config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | announce: [], // Torrent trackers to use (added to list in .torrent or magnet uri) 3 | maxWebConns: 99, // Max number of simultaneous connections per web seed [default=4] 4 | path: '/Users/qfdk/', 5 | dirPort:8888 6 | } 7 | -------------------------------------------------------------------------------- /server/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es6", 4 | "module": "commonjs" 5 | }, 6 | "exclude": [ 7 | "node_modules" 8 | ] 9 | } -------------------------------------------------------------------------------- /server/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "btonline", 3 | "version": "1.0.0", 4 | "description": "bt online", 5 | "main": "server.js", 6 | "scripts": { 7 | "start": "node server.js" 8 | }, 9 | "keywords": [ 10 | "Node.js", 11 | "Socket.io" 12 | ], 13 | "author": "qfdk", 14 | "license": "ISC", 15 | "dependencies": { 16 | "chai": "^3.5.0", 17 | "ejs": "^2.4.1", 18 | "express": "^4.13.4", 19 | "serve-favicon": "^2.3.0", 20 | "socket.io": "^1.4.5", 21 | "webtorrent": "^0.98.0" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /server/public/css/ie10-viewport-bug-workaround.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * IE10 viewport hack for Surface/desktop Windows 8 bug 3 | * Copyright 2014-2015 Twitter, Inc. 4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5 | */ 6 | 7 | /* 8 | * See the Getting Started docs for more information: 9 | * http://getbootstrap.com/getting-started/#support-ie10-width 10 | */ 11 | @-webkit-viewport { width: device-width; } 12 | @-moz-viewport { width: device-width; } 13 | @-ms-viewport { width: device-width; } 14 | @-o-viewport { width: device-width; } 15 | @viewport { width: device-width; } 16 | -------------------------------------------------------------------------------- /server/public/css/jumbotron.css: -------------------------------------------------------------------------------- 1 | /* Move down content because we have a fixed navbar that is 50px tall */ 2 | 3 | body { 4 | padding-top: 70px; 5 | padding-bottom: 20px; 6 | } 7 | #output video { 8 | width: 100%; 9 | } 10 | #progressBar { 11 | height: 5px; 12 | width: 0%; 13 | background-color: #35b44f; 14 | transition: width .4s ease-in-out; 15 | } 16 | body.is-seed .show-seed { 17 | display: inline; 18 | } 19 | body.is-seed .show-leech { 20 | display: none; 21 | } 22 | .show-seed { 23 | display: none; 24 | } 25 | #status code { 26 | font-size: 90%; 27 | font-weight: 700; 28 | margin-left: 3px; 29 | margin-right: 3px; 30 | border-bottom: 1px dashed rgba(255,255,255,0.3); 31 | } 32 | 33 | .is-seed #hero { 34 | background-color: #154820; 35 | transition: .5s .5s background-color ease-in-out; 36 | } 37 | #hero { 38 | background-color: #2a3749; 39 | } 40 | #status { 41 | color: #fff; 42 | font-size: 17px; 43 | padding: 5px; 44 | } 45 | a:link, a:visited { 46 | color: #30a247; 47 | text-decoration: none; 48 | } -------------------------------------------------------------------------------- /server/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/qfdk/BtOnline/285ab4b2c2fc17261b1377e1ee826d710a92160b/server/public/favicon.ico -------------------------------------------------------------------------------- /server/public/js/app.js: -------------------------------------------------------------------------------- 1 | var client = new WebTorrent() 2 | var socket = io.connect('http://' + window.location['hostname'] + ':3000') 3 | 4 | DragDrop('body', function (files) { 5 | client.seed(files, function (torrent) { 6 | log('拖拽文件:' + torrent.name) 7 | log('正在做种:' + torrent.magnetURI) 8 | log('Hash:' + torrent.infoHash) 9 | }) 10 | }) 11 | 12 | client.on('error', function (err) { 13 | log(err.message) 14 | }) 15 | 16 | $('#download').on('click', function (e) { 17 | e.preventDefault() 18 | $('.log').html('') 19 | log('正在添加下载任务 .. ') 20 | var torrentId = document.querySelector('form input[name=torrentId]').value 21 | // var url = "http://" + window.location['hostname'] + ":3000/download?url=" + torrentId 22 | socket.emit('download', { torrentId: torrentId }) 23 | }) 24 | 25 | socket.on('showDownloadInfo', function (data) { 26 | $('.log').html('') 27 | var json = JSON.parse(data) 28 | console.log(json) 29 | if (json.isDownloading) { 30 | $('.log').html('正在下载 ...') 31 | var tmp = (json.progress * 100).toFixed(1) 32 | $('.progress-bar').attr('aria-valuenow', tmp) 33 | $('.progress-bar').attr('style', 'width:' + tmp + '%') 34 | $('.progress-bar').html(tmp + '%') 35 | $('#speed').html(json.downSpeed + '/S') 36 | } else { 37 | console.log('im ok') 38 | $('.progress-bar').attr('aria-valuenow', 100) 39 | $('.progress-bar').attr('style', 'width:100%') 40 | $('.progress-bar').html('100% 下载完成') 41 | $('#speed').html('访问 http://' + window.location['hostname'] + ':8888 进行查看') 42 | $('.log').html('下载完成.') 43 | } 44 | }) 45 | 46 | function log (str) { 47 | var p = document.createElement('p') 48 | p.innerHTML = str 49 | var para = document.createElement('p') 50 | para.appendChild(p) 51 | var element = document.querySelector('.log') 52 | element.insertBefore(para, element.firstChild) 53 | } 54 | 55 | /** 56 | * 转换并显示下载速度 57 | * show the downloadSpeed for human 58 | */ 59 | function prettyBytes (num) { 60 | var exponent, unit, neg = num < 0, units = ['B', 'kB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'] 61 | if (neg) num = -num 62 | if (num < 1) return (neg ? '-' : '') + num + ' B' 63 | exponent = Math.min(Math.floor(Math.log(num) / Math.log(1000)), units.length - 1) 64 | num = Number((num / Math.pow(1000, exponent)).toFixed(2)) 65 | unit = units[exponent] 66 | return (neg ? '-' : '') + num + ' ' + unit 67 | } 68 | 69 | $('#online').on('click', function (e) { 70 | e.preventDefault() 71 | $('.log').html('') 72 | log('正在添加任务 .. ') 73 | var torrentId = document.querySelector('form input[name=torrentId]').value 74 | client.add(torrentId, onTorrent) 75 | }) 76 | 77 | function onTorrent (torrent) { 78 | // Print out progress every 5 seconds 79 | var interval = setInterval(function () { 80 | var tmp = (torrent.progress * 100).toFixed(1) 81 | $('.progress-bar').attr('aria-valuenow', tmp) 82 | $('.progress-bar').attr('style', 'width:' + tmp + '%') 83 | $('.progress-bar').html(tmp + ' %') 84 | $('#speed').html(prettyBytes(torrent.downloadSpeed) + '/S') 85 | // log('Progress: ' + (torrent.progress * 100).toFixed(1) + '%') 86 | }, 5000) 87 | 88 | log( 89 | 'Torrent info hash: ' + torrent.infoHash + ' ' + 90 | '[Magnet URI] ' + 91 | '[Download .torrent]' 92 | ) 93 | 94 | torrent.on('done', function () { 95 | clearInterval(interval) 96 | }) 97 | 98 | // Render all files into to the page 99 | torrent.files.forEach(function (file) { 100 | // file.appendTo('.log') 101 | log(file.name) 102 | file.getBlobURL(function (err, url) { 103 | if (err) return log(err.message) 104 | log('File done.') 105 | log('Download full file: ' + file.name + '') 106 | }) 107 | }) 108 | } 109 | -------------------------------------------------------------------------------- /server/public/js/bootstrap.min.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.3.6 (http://getbootstrap.com) 3 | * Copyright 2011-2015 Twitter, Inc. 4 | * Licensed under the MIT license 5 | */ 6 | if ("undefined" == typeof jQuery) 7 | throw new Error("Bootstrap's JavaScript requires jQuery"); 8 | + function(a) { 9 | "use strict"; 10 | var b = a.fn.jquery.split(" ")[0].split("."); 11 | if (b[0] < 2 && b[1] < 9 || 1 == b[0] && 9 == b[1] && b[2] < 1 || b[0] > 2) 12 | throw new Error("Bootstrap's JavaScript requires jQuery version 1.9.1 or higher, but lower than version 3") 13 | }(jQuery), + function(a) { 14 | "use strict"; 15 | function b() { 16 | var a = document.createElement("bootstrap"), b = { 17 | WebkitTransition: "webkitTransitionEnd", 18 | MozTransition: "transitionend", 19 | OTransition: "oTransitionEnd otransitionend", 20 | transition: "transitionend" 21 | }; 22 | for (var c in b) 23 | if (void 0 !== a.style[c]) 24 | return { 25 | end: b[c] 26 | }; 27 | return !1 28 | } 29 | a.fn.emulateTransitionEnd = function(b) { 30 | var c=!1, d = this; 31 | a(this).one("bsTransitionEnd", function() { 32 | c=!0 33 | }); 34 | var e = function() { 35 | c || a(d).trigger(a.support.transition.end) 36 | }; 37 | return setTimeout(e, b), this 38 | }, a(function() { 39 | a.support.transition = b(), a.support.transition && (a.event.special.bsTransitionEnd = { 40 | bindType: a.support.transition.end, 41 | delegateType: a.support.transition.end, 42 | handle: function(b) { 43 | return a(b.target).is(this) ? b.handleObj.handler.apply(this, arguments) : void 0 44 | } 45 | }) 46 | }) 47 | }(jQuery), + function(a) { 48 | "use strict"; 49 | function b(b) { 50 | return this.each(function() { 51 | var c = a(this), e = c.data("bs.alert"); 52 | e || c.data("bs.alert", e = new d(this)), "string" == typeof b && e[b].call(c) 53 | }) 54 | } 55 | var c = '[data-dismiss="alert"]', d = function(b) { 56 | a(b).on("click", c, this.close) 57 | }; 58 | d.VERSION = "3.3.6", d.TRANSITION_DURATION = 150, d.prototype.close = function(b) { 59 | function c() { 60 | g.detach().trigger("closed.bs.alert").remove() 61 | } 62 | var e = a(this), f = e.attr("data-target"); 63 | f || (f = e.attr("href"), f = f && f.replace(/.*(?=#[^\s]*$)/, "")); 64 | var g = a(f); 65 | b && b.preventDefault(), g.length || (g = e.closest(".alert")), g.trigger(b = a.Event("close.bs.alert")), b.isDefaultPrevented() || (g.removeClass("in"), a.support.transition && g.hasClass("fade") ? g.one("bsTransitionEnd", c).emulateTransitionEnd(d.TRANSITION_DURATION) : c()) 66 | }; 67 | var e = a.fn.alert; 68 | a.fn.alert = b, a.fn.alert.Constructor = d, a.fn.alert.noConflict = function() { 69 | return a.fn.alert = e, this 70 | }, a(document).on("click.bs.alert.data-api", c, d.prototype.close) 71 | }(jQuery), + function(a) { 72 | "use strict"; 73 | function b(b) { 74 | return this.each(function() { 75 | var d = a(this), e = d.data("bs.button"), f = "object" == typeof b && b; 76 | e || d.data("bs.button", e = new c(this, f)), "toggle" == b ? e.toggle() : b && e.setState(b) 77 | }) 78 | } 79 | var c = function(b, d) { 80 | this.$element = a(b), this.options = a.extend({}, c.DEFAULTS, d), this.isLoading=!1 81 | }; 82 | c.VERSION = "3.3.6", c.DEFAULTS = { 83 | loadingText: "loading..." 84 | }, c.prototype.setState = function(b) { 85 | var c = "disabled", d = this.$element, e = d.is("input") ? "val": "html", f = d.data(); 86 | b += "Text", null == f.resetText && d.data("resetText", d[e]()), setTimeout(a.proxy(function() { 87 | d[e](null == f[b] ? this.options[b] : f[b]), "loadingText" == b ? (this.isLoading=!0, d.addClass(c).attr(c, c)) : this.isLoading && (this.isLoading=!1, d.removeClass(c).removeAttr(c)) 88 | }, this), 0) 89 | }, c.prototype.toggle = function() { 90 | var a=!0, b = this.$element.closest('[data-toggle="buttons"]'); 91 | if (b.length) { 92 | var c = this.$element.find("input"); 93 | "radio" == c.prop("type") ? (c.prop("checked") && (a=!1), b.find(".active").removeClass("active"), this.$element.addClass("active")) : "checkbox" == c.prop("type") && (c.prop("checked") !== this.$element.hasClass("active") && (a=!1), this.$element.toggleClass("active")), c.prop("checked", this.$element.hasClass("active")), a && c.trigger("change") 94 | } else 95 | this.$element.attr("aria-pressed", !this.$element.hasClass("active")), this.$element.toggleClass("active") 96 | }; 97 | var d = a.fn.button; 98 | a.fn.button = b, a.fn.button.Constructor = c, a.fn.button.noConflict = function() { 99 | return a.fn.button = d, this 100 | }, a(document).on("click.bs.button.data-api", '[data-toggle^="button"]', function(c) { 101 | var d = a(c.target); 102 | d.hasClass("btn") || (d = d.closest(".btn")), b.call(d, "toggle"), a(c.target).is('input[type="radio"]') || a(c.target).is('input[type="checkbox"]') || c.preventDefault() 103 | }).on("focus.bs.button.data-api blur.bs.button.data-api", '[data-toggle^="button"]', function(b) { 104 | a(b.target).closest(".btn").toggleClass("focus", /^focus(in)?$/.test(b.type)) 105 | }) 106 | }(jQuery), + function(a) { 107 | "use strict"; 108 | function b(b) { 109 | return this.each(function() { 110 | var d = a(this), e = d.data("bs.carousel"), f = a.extend({}, c.DEFAULTS, d.data(), "object" == typeof b && b), g = "string" == typeof b ? b: f.slide; 111 | e || d.data("bs.carousel", e = new c(this, f)), "number" == typeof b ? e.to(b) : g ? e[g]() : f.interval && e.pause().cycle() 112 | }) 113 | } 114 | var c = function(b, c) { 115 | this.$element = a(b), this.$indicators = this.$element.find(".carousel-indicators"), this.options = c, this.paused = null, this.sliding = null, this.interval = null, this.$active = null, this.$items = null, this.options.keyboard && this.$element.on("keydown.bs.carousel", a.proxy(this.keydown, this)), "hover" == this.options.pause&&!("ontouchstart"in document.documentElement) && this.$element.on("mouseenter.bs.carousel", a.proxy(this.pause, this)).on("mouseleave.bs.carousel", a.proxy(this.cycle, this)) 116 | }; 117 | c.VERSION = "3.3.6", c.TRANSITION_DURATION = 600, c.DEFAULTS = { 118 | interval: 5e3, 119 | pause: "hover", 120 | wrap: !0, 121 | keyboard: !0 122 | }, c.prototype.keydown = function(a) { 123 | if (!/input|textarea/i.test(a.target.tagName)) { 124 | switch (a.which) { 125 | case 37: 126 | this.prev(); 127 | break; 128 | case 39: 129 | this.next(); 130 | break; 131 | default: 132 | return 133 | } 134 | a.preventDefault() 135 | } 136 | }, c.prototype.cycle = function(b) { 137 | return b || (this.paused=!1), this.interval && clearInterval(this.interval), this.options.interval&&!this.paused && (this.interval = setInterval(a.proxy(this.next, this), this.options.interval)), this 138 | }, c.prototype.getItemIndex = function(a) { 139 | return this.$items = a.parent().children(".item"), this.$items.index(a || this.$active) 140 | }, c.prototype.getItemForDirection = function(a, b) { 141 | var c = this.getItemIndex(b), d = "prev" == a && 0 === c || "next" == a && c == this.$items.length - 1; 142 | if (d&&!this.options.wrap) 143 | return b; 144 | var e = "prev" == a?-1 : 1, f = (c + e)%this.$items.length; 145 | return this.$items.eq(f) 146 | }, c.prototype.to = function(a) { 147 | var b = this, c = this.getItemIndex(this.$active = this.$element.find(".item.active")); 148 | return a > this.$items.length - 1 || 0 > a ? void 0 : this.sliding ? this.$element.one("slid.bs.carousel", function() { 149 | b.to(a) 150 | }) : c == a ? this.pause().cycle() : this.slide(a > c ? "next" : "prev", this.$items.eq(a)) 151 | }, c.prototype.pause = function(b) { 152 | return b || (this.paused=!0), this.$element.find(".next, .prev").length && a.support.transition && (this.$element.trigger(a.support.transition.end), this.cycle(!0)), this.interval = clearInterval(this.interval), this 153 | }, c.prototype.next = function() { 154 | return this.sliding ? void 0 : this.slide("next") 155 | }, c.prototype.prev = function() { 156 | return this.sliding ? void 0 : this.slide("prev") 157 | }, c.prototype.slide = function(b, d) { 158 | var e = this.$element.find(".item.active"), f = d || this.getItemForDirection(b, e), g = this.interval, h = "next" == b ? "left": "right", i = this; 159 | if (f.hasClass("active")) 160 | return this.sliding=!1; 161 | var j = f[0], k = a.Event("slide.bs.carousel", { 162 | relatedTarget: j, 163 | direction: h 164 | }); 165 | if (this.$element.trigger(k), !k.isDefaultPrevented()) { 166 | if (this.sliding=!0, g && this.pause(), this.$indicators.length) { 167 | this.$indicators.find(".active").removeClass("active"); 168 | var l = a(this.$indicators.children()[this.getItemIndex(f)]); 169 | l && l.addClass("active") 170 | } 171 | var m = a.Event("slid.bs.carousel", { 172 | relatedTarget: j, 173 | direction: h 174 | }); 175 | return a.support.transition && this.$element.hasClass("slide") ? (f.addClass(b), f[0].offsetWidth, e.addClass(h), f.addClass(h), e.one("bsTransitionEnd", function() { 176 | f.removeClass([b, h].join(" ")).addClass("active"), e.removeClass(["active", h].join(" ")), i.sliding=!1, setTimeout(function() { 177 | i.$element.trigger(m) 178 | }, 0) 179 | }).emulateTransitionEnd(c.TRANSITION_DURATION)) : (e.removeClass("active"), f.addClass("active"), this.sliding=!1, this.$element.trigger(m)), g && this.cycle(), this 180 | } 181 | }; 182 | var d = a.fn.carousel; 183 | a.fn.carousel = b, a.fn.carousel.Constructor = c, a.fn.carousel.noConflict = function() { 184 | return a.fn.carousel = d, this 185 | }; 186 | var e = function(c) { 187 | var d, e = a(this), f = a(e.attr("data-target") || (d = e.attr("href")) && d.replace(/.*(?=#[^\s]+$)/, "")); 188 | if (f.hasClass("carousel")) { 189 | var g = a.extend({}, f.data(), e.data()), h = e.attr("data-slide-to"); 190 | h && (g.interval=!1), b.call(f, g), h && f.data("bs.carousel").to(h), c.preventDefault() 191 | } 192 | }; 193 | a(document).on("click.bs.carousel.data-api", "[data-slide]", e).on("click.bs.carousel.data-api", "[data-slide-to]", e), a(window).on("load", function() { 194 | a('[data-ride="carousel"]').each(function() { 195 | var c = a(this); 196 | b.call(c, c.data()) 197 | }) 198 | }) 199 | }(jQuery), + function(a) { 200 | "use strict"; 201 | function b(b) { 202 | var c, d = b.attr("data-target") || (c = b.attr("href")) && c.replace(/.*(?=#[^\s]+$)/, ""); 203 | return a(d) 204 | } 205 | function c(b) { 206 | return this.each(function() { 207 | var c = a(this), e = c.data("bs.collapse"), f = a.extend({}, d.DEFAULTS, c.data(), "object" == typeof b && b); 208 | !e && f.toggle && /show|hide/.test(b) && (f.toggle=!1), e || c.data("bs.collapse", e = new d(this, f)), "string" == typeof b && e[b]() 209 | }) 210 | } 211 | var d = function(b, c) { 212 | this.$element = a(b), this.options = a.extend({}, d.DEFAULTS, c), this.$trigger = a('[data-toggle="collapse"][href="#' + b.id + '"],[data-toggle="collapse"][data-target="#' + b.id + '"]'), this.transitioning = null, this.options.parent ? this.$parent = this.getParent() : this.addAriaAndCollapsedClass(this.$element, this.$trigger), this.options.toggle && this.toggle() 213 | }; 214 | d.VERSION = "3.3.6", d.TRANSITION_DURATION = 350, d.DEFAULTS = { 215 | toggle: !0 216 | }, d.prototype.dimension = function() { 217 | var a = this.$element.hasClass("width"); 218 | return a ? "width" : "height" 219 | }, d.prototype.show = function() { 220 | if (!this.transitioning&&!this.$element.hasClass("in")) { 221 | var b, e = this.$parent && this.$parent.children(".panel").children(".in, .collapsing"); 222 | if (!(e && e.length && (b = e.data("bs.collapse"), b && b.transitioning))) { 223 | var f = a.Event("show.bs.collapse"); 224 | if (this.$element.trigger(f), !f.isDefaultPrevented()) { 225 | e && e.length && (c.call(e, "hide"), b || e.data("bs.collapse", null)); 226 | var g = this.dimension(); 227 | this.$element.removeClass("collapse").addClass("collapsing")[g](0).attr("aria-expanded", !0), this.$trigger.removeClass("collapsed").attr("aria-expanded", !0), this.transitioning = 1; 228 | var h = function() { 229 | this.$element.removeClass("collapsing").addClass("collapse in")[g](""), this.transitioning = 0, this.$element.trigger("shown.bs.collapse") 230 | }; 231 | if (!a.support.transition) 232 | return h.call(this); 233 | var i = a.camelCase(["scroll", g].join("-")); 234 | this.$element.one("bsTransitionEnd", a.proxy(h, this)).emulateTransitionEnd(d.TRANSITION_DURATION)[g](this.$element[0][i]) 235 | } 236 | } 237 | } 238 | }, d.prototype.hide = function() { 239 | if (!this.transitioning && this.$element.hasClass("in")) { 240 | var b = a.Event("hide.bs.collapse"); 241 | if (this.$element.trigger(b), !b.isDefaultPrevented()) { 242 | var c = this.dimension(); 243 | this.$element[c](this.$element[c]())[0].offsetHeight, this.$element.addClass("collapsing").removeClass("collapse in").attr("aria-expanded", !1), this.$trigger.addClass("collapsed").attr("aria-expanded", !1), this.transitioning = 1; 244 | var e = function() { 245 | this.transitioning = 0, this.$element.removeClass("collapsing").addClass("collapse").trigger("hidden.bs.collapse") 246 | }; 247 | return a.support.transition ? void this.$element[c](0).one("bsTransitionEnd", a.proxy(e, this)).emulateTransitionEnd(d.TRANSITION_DURATION) : e.call(this) 248 | } 249 | } 250 | }, d.prototype.toggle = function() { 251 | this[this.$element.hasClass("in") ? "hide": "show"]() 252 | }, d.prototype.getParent = function() { 253 | return a(this.options.parent).find('[data-toggle="collapse"][data-parent="' + this.options.parent + '"]').each(a.proxy(function(c, d) { 254 | var e = a(d); 255 | this.addAriaAndCollapsedClass(b(e), e) 256 | }, this)).end() 257 | }, d.prototype.addAriaAndCollapsedClass = function(a, b) { 258 | var c = a.hasClass("in"); 259 | a.attr("aria-expanded", c), b.toggleClass("collapsed", !c).attr("aria-expanded", c) 260 | }; 261 | var e = a.fn.collapse; 262 | a.fn.collapse = c, a.fn.collapse.Constructor = d, a.fn.collapse.noConflict = function() { 263 | return a.fn.collapse = e, this 264 | }, a(document).on("click.bs.collapse.data-api", '[data-toggle="collapse"]', function(d) { 265 | var e = a(this); 266 | e.attr("data-target") || d.preventDefault(); 267 | var f = b(e), g = f.data("bs.collapse"), h = g ? "toggle": e.data(); 268 | c.call(f, h) 269 | }) 270 | }(jQuery), + function(a) { 271 | "use strict"; 272 | function b(b) { 273 | var c = b.attr("data-target"); 274 | c || (c = b.attr("href"), c = c && /#[A-Za-z]/.test(c) && c.replace(/.*(?=#[^\s]*$)/, "")); 275 | var d = c && a(c); 276 | return d && d.length ? d : b.parent() 277 | } 278 | function c(c) { 279 | c && 3 === c.which || (a(e).remove(), a(f).each(function() { 280 | var d = a(this), e = b(d), f = { 281 | relatedTarget: this 282 | }; 283 | e.hasClass("open") && (c && "click" == c.type && /input|textarea/i.test(c.target.tagName) && a.contains(e[0], c.target) || (e.trigger(c = a.Event("hide.bs.dropdown", f)), c.isDefaultPrevented() || (d.attr("aria-expanded", "false"), e.removeClass("open").trigger(a.Event("hidden.bs.dropdown", f))))) 284 | })) 285 | } 286 | function d(b) { 287 | return this.each(function() { 288 | var c = a(this), d = c.data("bs.dropdown"); 289 | d || c.data("bs.dropdown", d = new g(this)), "string" == typeof b && d[b].call(c) 290 | }) 291 | } 292 | var e = ".dropdown-backdrop", f = '[data-toggle="dropdown"]', g = function(b) { 293 | a(b).on("click.bs.dropdown", this.toggle) 294 | }; 295 | g.VERSION = "3.3.6", g.prototype.toggle = function(d) { 296 | var e = a(this); 297 | if (!e.is(".disabled, :disabled")) { 298 | var f = b(e), g = f.hasClass("open"); 299 | if (c(), !g) { 300 | "ontouchstart"in document.documentElement&&!f.closest(".navbar-nav").length && a(document.createElement("div")).addClass("dropdown-backdrop").insertAfter(a(this)).on("click", c); 301 | var h = { 302 | relatedTarget: this 303 | }; 304 | if (f.trigger(d = a.Event("show.bs.dropdown", h)), d.isDefaultPrevented()) 305 | return; 306 | e.trigger("focus").attr("aria-expanded", "true"), f.toggleClass("open").trigger(a.Event("shown.bs.dropdown", h)) 307 | } 308 | return !1 309 | } 310 | }, g.prototype.keydown = function(c) { 311 | if (/(38|40|27|32)/.test(c.which)&&!/input|textarea/i.test(c.target.tagName)) { 312 | var d = a(this); 313 | if (c.preventDefault(), c.stopPropagation(), !d.is(".disabled, :disabled")) { 314 | var e = b(d), g = e.hasClass("open"); 315 | if (!g && 27 != c.which || g && 27 == c.which) 316 | return 27 == c.which && e.find(f).trigger("focus"), d.trigger("click"); 317 | var h = " li:not(.disabled):visible a", i = e.find(".dropdown-menu" + h); 318 | if (i.length) { 319 | var j = i.index(c.target); 320 | 38 == c.which && j > 0 && j--, 40 == c.which && j < i.length - 1 && j++, ~j || (j = 0), i.eq(j).trigger("focus") 321 | } 322 | } 323 | } 324 | }; 325 | var h = a.fn.dropdown; 326 | a.fn.dropdown = d, a.fn.dropdown.Constructor = g, a.fn.dropdown.noConflict = function() { 327 | return a.fn.dropdown = h, this 328 | }, a(document).on("click.bs.dropdown.data-api", c).on("click.bs.dropdown.data-api", ".dropdown form", function(a) { 329 | a.stopPropagation() 330 | }).on("click.bs.dropdown.data-api", f, g.prototype.toggle).on("keydown.bs.dropdown.data-api", f, g.prototype.keydown).on("keydown.bs.dropdown.data-api", ".dropdown-menu", g.prototype.keydown) 331 | }(jQuery), + function(a) { 332 | "use strict"; 333 | function b(b, d) { 334 | return this.each(function() { 335 | var e = a(this), f = e.data("bs.modal"), g = a.extend({}, c.DEFAULTS, e.data(), "object" == typeof b && b); 336 | f || e.data("bs.modal", f = new c(this, g)), "string" == typeof b ? f[b](d) : g.show && f.show(d) 337 | }) 338 | } 339 | var c = function(b, c) { 340 | this.options = c, this.$body = a(document.body), this.$element = a(b), this.$dialog = this.$element.find(".modal-dialog"), this.$backdrop = null, this.isShown = null, this.originalBodyPad = null, this.scrollbarWidth = 0, this.ignoreBackdropClick=!1, this.options.remote && this.$element.find(".modal-content").load(this.options.remote, a.proxy(function() { 341 | this.$element.trigger("loaded.bs.modal") 342 | }, this)) 343 | }; 344 | c.VERSION = "3.3.6", c.TRANSITION_DURATION = 300, c.BACKDROP_TRANSITION_DURATION = 150, c.DEFAULTS = { 345 | backdrop: !0, 346 | keyboard: !0, 347 | show: !0 348 | }, c.prototype.toggle = function(a) { 349 | return this.isShown ? this.hide() : this.show(a) 350 | }, c.prototype.show = function(b) { 351 | var d = this, e = a.Event("show.bs.modal", { 352 | relatedTarget: b 353 | }); 354 | this.$element.trigger(e), this.isShown || e.isDefaultPrevented() || (this.isShown=!0, this.checkScrollbar(), this.setScrollbar(), this.$body.addClass("modal-open"), this.escape(), this.resize(), this.$element.on("click.dismiss.bs.modal", '[data-dismiss="modal"]', a.proxy(this.hide, this)), this.$dialog.on("mousedown.dismiss.bs.modal", function() { 355 | d.$element.one("mouseup.dismiss.bs.modal", function(b) { 356 | a(b.target).is(d.$element) && (d.ignoreBackdropClick=!0) 357 | }) 358 | }), this.backdrop(function() { 359 | var e = a.support.transition && d.$element.hasClass("fade"); 360 | d.$element.parent().length || d.$element.appendTo(d.$body), d.$element.show().scrollTop(0), d.adjustDialog(), e && d.$element[0].offsetWidth, d.$element.addClass("in"), d.enforceFocus(); 361 | var f = a.Event("shown.bs.modal", { 362 | relatedTarget: b 363 | }); 364 | e ? d.$dialog.one("bsTransitionEnd", function() { 365 | d.$element.trigger("focus").trigger(f) 366 | }).emulateTransitionEnd(c.TRANSITION_DURATION) : d.$element.trigger("focus").trigger(f) 367 | })) 368 | }, c.prototype.hide = function(b) { 369 | b && b.preventDefault(), b = a.Event("hide.bs.modal"), this.$element.trigger(b), this.isShown&&!b.isDefaultPrevented() && (this.isShown=!1, this.escape(), this.resize(), a(document).off("focusin.bs.modal"), this.$element.removeClass("in").off("click.dismiss.bs.modal").off("mouseup.dismiss.bs.modal"), this.$dialog.off("mousedown.dismiss.bs.modal"), a.support.transition && this.$element.hasClass("fade") ? this.$element.one("bsTransitionEnd", a.proxy(this.hideModal, this)).emulateTransitionEnd(c.TRANSITION_DURATION) : this.hideModal()) 370 | }, c.prototype.enforceFocus = function() { 371 | a(document).off("focusin.bs.modal").on("focusin.bs.modal", a.proxy(function(a) { 372 | this.$element[0] === a.target || this.$element.has(a.target).length || this.$element.trigger("focus") 373 | }, this)) 374 | }, c.prototype.escape = function() { 375 | this.isShown && this.options.keyboard ? this.$element.on("keydown.dismiss.bs.modal", a.proxy(function(a) { 376 | 27 == a.which && this.hide() 377 | }, this)) : this.isShown || this.$element.off("keydown.dismiss.bs.modal") 378 | }, c.prototype.resize = function() { 379 | this.isShown ? a(window).on("resize.bs.modal", a.proxy(this.handleUpdate, this)) : a(window).off("resize.bs.modal") 380 | }, c.prototype.hideModal = function() { 381 | var a = this; 382 | this.$element.hide(), this.backdrop(function() { 383 | a.$body.removeClass("modal-open"), a.resetAdjustments(), a.resetScrollbar(), a.$element.trigger("hidden.bs.modal") 384 | }) 385 | }, c.prototype.removeBackdrop = function() { 386 | this.$backdrop && this.$backdrop.remove(), this.$backdrop = null 387 | }, c.prototype.backdrop = function(b) { 388 | var d = this, e = this.$element.hasClass("fade") ? "fade": ""; 389 | if (this.isShown && this.options.backdrop) { 390 | var f = a.support.transition && e; 391 | if (this.$backdrop = a(document.createElement("div")).addClass("modal-backdrop " + e).appendTo(this.$body), this.$element.on("click.dismiss.bs.modal", a.proxy(function(a) { 392 | return this.ignoreBackdropClick ? void(this.ignoreBackdropClick=!1) : void(a.target === a.currentTarget && ("static" == this.options.backdrop ? this.$element[0].focus() : this.hide())) 393 | }, this)), f && this.$backdrop[0].offsetWidth, this.$backdrop.addClass("in"), !b) 394 | return; 395 | f ? this.$backdrop.one("bsTransitionEnd", b).emulateTransitionEnd(c.BACKDROP_TRANSITION_DURATION) : b() 396 | } else if (!this.isShown && this.$backdrop) { 397 | this.$backdrop.removeClass("in"); 398 | var g = function() { 399 | d.removeBackdrop(), b && b() 400 | }; 401 | a.support.transition && this.$element.hasClass("fade") ? this.$backdrop.one("bsTransitionEnd", g).emulateTransitionEnd(c.BACKDROP_TRANSITION_DURATION) : g() 402 | } else 403 | b && b() 404 | }, c.prototype.handleUpdate = function() { 405 | this.adjustDialog() 406 | }, c.prototype.adjustDialog = function() { 407 | var a = this.$element[0].scrollHeight > document.documentElement.clientHeight; 408 | this.$element.css({ 409 | paddingLeft: !this.bodyIsOverflowing && a ? this.scrollbarWidth: "", 410 | paddingRight: this.bodyIsOverflowing&&!a ? this.scrollbarWidth: "" 411 | }) 412 | }, c.prototype.resetAdjustments = function() { 413 | this.$element.css({ 414 | paddingLeft: "", 415 | paddingRight: "" 416 | }) 417 | }, c.prototype.checkScrollbar = function() { 418 | var a = window.innerWidth; 419 | if (!a) { 420 | var b = document.documentElement.getBoundingClientRect(); 421 | a = b.right - Math.abs(b.left) 422 | } 423 | this.bodyIsOverflowing = document.body.clientWidth < a, this.scrollbarWidth = this.measureScrollbar() 424 | }, c.prototype.setScrollbar = function() { 425 | var a = parseInt(this.$body.css("padding-right") || 0, 10); 426 | this.originalBodyPad = document.body.style.paddingRight || "", this.bodyIsOverflowing && this.$body.css("padding-right", a + this.scrollbarWidth) 427 | }, c.prototype.resetScrollbar = function() { 428 | this.$body.css("padding-right", this.originalBodyPad) 429 | }, c.prototype.measureScrollbar = function() { 430 | var a = document.createElement("div"); 431 | a.className = "modal-scrollbar-measure", this.$body.append(a); 432 | var b = a.offsetWidth - a.clientWidth; 433 | return this.$body[0].removeChild(a), b 434 | }; 435 | var d = a.fn.modal; 436 | a.fn.modal = b, a.fn.modal.Constructor = c, a.fn.modal.noConflict = function() { 437 | return a.fn.modal = d, this 438 | }, a(document).on("click.bs.modal.data-api", '[data-toggle="modal"]', function(c) { 439 | var d = a(this), e = d.attr("href"), f = a(d.attr("data-target") || e && e.replace(/.*(?=#[^\s]+$)/, "")), g = f.data("bs.modal") ? "toggle": a.extend({ 440 | remote: !/#/.test(e) && e 441 | }, f.data(), d.data()); 442 | d.is("a") && c.preventDefault(), f.one("show.bs.modal", function(a) { 443 | a.isDefaultPrevented() || f.one("hidden.bs.modal", function() { 444 | d.is(":visible") && d.trigger("focus") 445 | }) 446 | }), b.call(f, g, this) 447 | }) 448 | }(jQuery), + function(a) { 449 | "use strict"; 450 | function b(b) { 451 | return this.each(function() { 452 | var d = a(this), e = d.data("bs.tooltip"), f = "object" == typeof b && b; 453 | (e ||!/destroy|hide/.test(b)) && (e || d.data("bs.tooltip", e = new c(this, f)), "string" == typeof b && e[b]()) 454 | }) 455 | } 456 | var c = function(a, b) { 457 | this.type = null, this.options = null, this.enabled = null, this.timeout = null, this.hoverState = null, this.$element = null, this.inState = null, this.init("tooltip", a, b) 458 | }; 459 | c.VERSION = "3.3.6", c.TRANSITION_DURATION = 150, c.DEFAULTS = { 460 | animation: !0, 461 | placement: "top", 462 | selector: !1, 463 | template: '', 464 | trigger: "hover focus", 465 | title: "", 466 | delay: 0, 467 | html: !1, 468 | container: !1, 469 | viewport: { 470 | selector: "body", 471 | padding: 0 472 | } 473 | }, c.prototype.init = function(b, c, d) { 474 | if (this.enabled=!0, this.type = b, this.$element = a(c), this.options = this.getOptions(d), this.$viewport = this.options.viewport && a(a.isFunction(this.options.viewport) ? this.options.viewport.call(this, this.$element) : this.options.viewport.selector || this.options.viewport), this.inState = { 475 | click: !1, 476 | hover: !1, 477 | focus: !1 478 | }, this.$element[0]instanceof document.constructor&&!this.options.selector) 479 | throw new Error("`selector` option must be specified when initializing " + this.type + " on the window.document object!"); 480 | for (var e = this.options.trigger.split(" "), f = e.length; f--;) { 481 | var g = e[f]; 482 | if ("click" == g) 483 | this.$element.on("click." + this.type, this.options.selector, a.proxy(this.toggle, this)); 484 | else if ("manual" != g) { 485 | var h = "hover" == g ? "mouseenter": "focusin", i = "hover" == g ? "mouseleave": "focusout"; 486 | this.$element.on(h + "." + this.type, this.options.selector, a.proxy(this.enter, this)), this.$element.on(i + "." + this.type, this.options.selector, a.proxy(this.leave, this)) 487 | } 488 | } 489 | this.options.selector ? this._options = a.extend({}, this.options, { 490 | trigger: "manual", 491 | selector: "" 492 | }) : this.fixTitle() 493 | }, c.prototype.getDefaults = function() { 494 | return c.DEFAULTS 495 | }, c.prototype.getOptions = function(b) { 496 | return b = a.extend({}, this.getDefaults(), this.$element.data(), b), b.delay && "number" == typeof b.delay && (b.delay = { 497 | show: b.delay, 498 | hide: b.delay 499 | }), b 500 | }, c.prototype.getDelegateOptions = function() { 501 | var b = {}, c = this.getDefaults(); 502 | return this._options && a.each(this._options, function(a, d) { 503 | c[a] != d && (b[a] = d) 504 | }), b 505 | }, c.prototype.enter = function(b) { 506 | var c = b instanceof this.constructor ? b: a(b.currentTarget).data("bs." + this.type); 507 | return c || (c = new this.constructor(b.currentTarget, this.getDelegateOptions()), a(b.currentTarget).data("bs." + this.type, c)), b instanceof a.Event && (c.inState["focusin" == b.type ? "focus": "hover"]=!0), c.tip().hasClass("in") || "in" == c.hoverState ? void(c.hoverState = "in") : (clearTimeout(c.timeout), c.hoverState = "in", c.options.delay && c.options.delay.show ? void(c.timeout = setTimeout(function() { 508 | "in" == c.hoverState && c.show() 509 | }, c.options.delay.show)) : c.show()) 510 | }, c.prototype.isInStateTrue = function() { 511 | for (var a in this.inState) 512 | if (this.inState[a]) 513 | return !0; 514 | return !1 515 | }, c.prototype.leave = function(b) { 516 | var c = b instanceof this.constructor ? b: a(b.currentTarget).data("bs." + this.type); 517 | return c || (c = new this.constructor(b.currentTarget, this.getDelegateOptions()), a(b.currentTarget).data("bs." + this.type, c)), b instanceof a.Event && (c.inState["focusout" == b.type ? "focus": "hover"]=!1), c.isInStateTrue() ? void 0 : (clearTimeout(c.timeout), c.hoverState = "out", c.options.delay && c.options.delay.hide ? void(c.timeout = setTimeout(function() { 518 | "out" == c.hoverState && c.hide() 519 | }, c.options.delay.hide)) : c.hide()) 520 | }, c.prototype.show = function() { 521 | var b = a.Event("show.bs." + this.type); 522 | if (this.hasContent() && this.enabled) { 523 | this.$element.trigger(b); 524 | var d = a.contains(this.$element[0].ownerDocument.documentElement, this.$element[0]); 525 | if (b.isDefaultPrevented() ||!d) 526 | return; 527 | var e = this, f = this.tip(), g = this.getUID(this.type); 528 | this.setContent(), f.attr("id", g), this.$element.attr("aria-describedby", g), this.options.animation && f.addClass("fade"); 529 | var h = "function" == typeof this.options.placement ? this.options.placement.call(this, f[0], this.$element[0]): this.options.placement, i = /\s?auto?\s?/i, j = i.test(h); 530 | j && (h = h.replace(i, "") || "top"), f.detach().css({ 531 | top: 0, 532 | left: 0, 533 | display: "block" 534 | }).addClass(h).data("bs." + this.type, this), this.options.container ? f.appendTo(this.options.container) : f.insertAfter(this.$element), this.$element.trigger("inserted.bs." + this.type); 535 | var k = this.getPosition(), l = f[0].offsetWidth, m = f[0].offsetHeight; 536 | if (j) { 537 | var n = h, o = this.getPosition(this.$viewport); 538 | h = "bottom" == h && k.bottom + m > o.bottom ? "top" : "top" == h && k.top - m < o.top ? "bottom" : "right" == h && k.right + l > o.width ? "left" : "left" == h && k.left - l < o.left ? "right" : h, f.removeClass(n).addClass(h) 539 | } 540 | var p = this.getCalculatedOffset(h, k, l, m); 541 | this.applyPlacement(p, h); 542 | var q = function() { 543 | var a = e.hoverState; 544 | e.$element.trigger("shown.bs." + e.type), e.hoverState = null, "out" == a && e.leave(e) 545 | }; 546 | a.support.transition && this.$tip.hasClass("fade") ? f.one("bsTransitionEnd", q).emulateTransitionEnd(c.TRANSITION_DURATION) : q() 547 | } 548 | }, c.prototype.applyPlacement = function(b, c) { 549 | var d = this.tip(), e = d[0].offsetWidth, f = d[0].offsetHeight, g = parseInt(d.css("margin-top"), 10), h = parseInt(d.css("margin-left"), 10); 550 | isNaN(g) && (g = 0), isNaN(h) && (h = 0), b.top += g, b.left += h, a.offset.setOffset(d[0], a.extend({ 551 | using: function(a) { 552 | d.css({ 553 | top: Math.round(a.top), 554 | left: Math.round(a.left) 555 | }) 556 | } 557 | }, b), 0), d.addClass("in"); 558 | var i = d[0].offsetWidth, j = d[0].offsetHeight; 559 | "top" == c && j != f && (b.top = b.top + f - j); 560 | var k = this.getViewportAdjustedDelta(c, b, i, j); 561 | k.left ? b.left += k.left : b.top += k.top; 562 | var l = /top|bottom/.test(c), m = l ? 2 * k.left - e + i: 2 * k.top - f + j, n = l ? "offsetWidth": "offsetHeight"; 563 | d.offset(b), this.replaceArrow(m, d[0][n], l) 564 | }, c.prototype.replaceArrow = function(a, b, c) { 565 | this.arrow().css(c ? "left" : "top", 50 * (1 - a / b) + "%").css(c ? "top" : "left", "") 566 | }, c.prototype.setContent = function() { 567 | var a = this.tip(), b = this.getTitle(); 568 | a.find(".tooltip-inner")[this.options.html ? "html": "text"](b), a.removeClass("fade in top bottom left right") 569 | }, c.prototype.hide = function(b) { 570 | function d() { 571 | "in" != e.hoverState && f.detach(), e.$element.removeAttr("aria-describedby").trigger("hidden.bs." + e.type), b && b() 572 | } 573 | var e = this, f = a(this.$tip), g = a.Event("hide.bs." + this.type); 574 | return this.$element.trigger(g), g.isDefaultPrevented() ? void 0 : (f.removeClass("in"), a.support.transition && f.hasClass("fade") ? f.one("bsTransitionEnd", d).emulateTransitionEnd(c.TRANSITION_DURATION) : d(), this.hoverState = null, this) 575 | }, c.prototype.fixTitle = function() { 576 | var a = this.$element; 577 | (a.attr("title") || "string" != typeof a.attr("data-original-title")) && a.attr("data-original-title", a.attr("title") || "").attr("title", "") 578 | }, c.prototype.hasContent = function() { 579 | return this.getTitle() 580 | }, c.prototype.getPosition = function(b) { 581 | b = b || this.$element; 582 | var c = b[0], d = "BODY" == c.tagName, e = c.getBoundingClientRect(); 583 | null == e.width && (e = a.extend({}, e, { 584 | width: e.right - e.left, 585 | height: e.bottom - e.top 586 | })); 587 | var f = d ? { 588 | top: 0, 589 | left: 0 590 | } 591 | : b.offset(), g = { 592 | scroll: d ? document.documentElement.scrollTop || document.body.scrollTop: b.scrollTop() 593 | }, h = d ? { 594 | width: a(window).width(), 595 | height: a(window).height() 596 | } 597 | : null; 598 | return a.extend({}, e, g, h, f) 599 | }, c.prototype.getCalculatedOffset = function(a, b, c, d) { 600 | return "bottom" == a ? { 601 | top: b.top + b.height, 602 | left: b.left + b.width / 2 - c / 2 603 | } : "top" == a ? { 604 | top: b.top - d, 605 | left: b.left + b.width / 2 - c / 2 606 | } : "left" == a ? { 607 | top: b.top + b.height / 2 - d / 2, 608 | left: b.left - c 609 | } : { 610 | top: b.top + b.height / 2 - d / 2, 611 | left: b.left + b.width 612 | } 613 | }, c.prototype.getViewportAdjustedDelta = function(a, b, c, d) { 614 | var e = { 615 | top: 0, 616 | left: 0 617 | }; 618 | if (!this.$viewport) 619 | return e; 620 | var f = this.options.viewport && this.options.viewport.padding || 0, g = this.getPosition(this.$viewport); 621 | if (/right|left/.test(a)) { 622 | var h = b.top - f - g.scroll, i = b.top + f - g.scroll + d; 623 | h < g.top ? e.top = g.top - h : i > g.top + g.height && (e.top = g.top + g.height - i) 624 | } else { 625 | var j = b.left - f, k = b.left + f + c; 626 | j < g.left ? e.left = g.left - j : k > g.right && (e.left = g.left + g.width - k) 627 | } 628 | return e 629 | }, c.prototype.getTitle = function() { 630 | var a, b = this.$element, c = this.options; 631 | return a = b.attr("data-original-title") || ("function" == typeof c.title ? c.title.call(b[0]) : c.title) 632 | }, c.prototype.getUID = function(a) { 633 | do 634 | a+=~~(1e6 * Math.random()); 635 | while (document.getElementById(a)); 636 | return a 637 | }, c.prototype.tip = function() { 638 | if (!this.$tip && (this.$tip = a(this.options.template), 1 != this.$tip.length)) 639 | throw new Error(this.type + " `template` option must consist of exactly 1 top-level element!"); 640 | return this.$tip 641 | }, c.prototype.arrow = function() { 642 | return this.$arrow = this.$arrow || this.tip().find(".tooltip-arrow") 643 | }, c.prototype.enable = function() { 644 | this.enabled=!0 645 | }, c.prototype.disable = function() { 646 | this.enabled=!1 647 | }, c.prototype.toggleEnabled = function() { 648 | this.enabled=!this.enabled 649 | }, c.prototype.toggle = function(b) { 650 | var c = this; 651 | b && (c = a(b.currentTarget).data("bs." + this.type), c || (c = new this.constructor(b.currentTarget, this.getDelegateOptions()), a(b.currentTarget).data("bs." + this.type, c))), b ? (c.inState.click=!c.inState.click, c.isInStateTrue() ? c.enter(c) : c.leave(c)) : c.tip().hasClass("in") ? c.leave(c) : c.enter(c) 652 | }, c.prototype.destroy = function() { 653 | var a = this; 654 | clearTimeout(this.timeout), this.hide(function() { 655 | a.$element.off("." + a.type).removeData("bs." + a.type), a.$tip && a.$tip.detach(), a.$tip = null, a.$arrow = null, a.$viewport = null 656 | }) 657 | }; 658 | var d = a.fn.tooltip; 659 | a.fn.tooltip = b, a.fn.tooltip.Constructor = c, a.fn.tooltip.noConflict = function() { 660 | return a.fn.tooltip = d, this 661 | } 662 | }(jQuery), + function(a) { 663 | "use strict"; 664 | function b(b) { 665 | return this.each(function() { 666 | var d = a(this), e = d.data("bs.popover"), f = "object" == typeof b && b; 667 | (e ||!/destroy|hide/.test(b)) && (e || d.data("bs.popover", e = new c(this, f)), "string" == typeof b && e[b]()) 668 | }) 669 | } 670 | var c = function(a, b) { 671 | this.init("popover", a, b) 672 | }; 673 | if (!a.fn.tooltip) 674 | throw new Error("Popover requires tooltip.js"); 675 | c.VERSION = "3.3.6", c.DEFAULTS = a.extend({}, a.fn.tooltip.Constructor.DEFAULTS, { 676 | placement: "right", 677 | trigger: "click", 678 | content: "", 679 | template: '' 680 | }), c.prototype = a.extend({}, a.fn.tooltip.Constructor.prototype), c.prototype.constructor = c, c.prototype.getDefaults = function() { 681 | return c.DEFAULTS 682 | }, c.prototype.setContent = function() { 683 | var a = this.tip(), b = this.getTitle(), c = this.getContent(); 684 | a.find(".popover-title")[this.options.html ? "html": "text"](b), a.find(".popover-content").children().detach().end()[this.options.html ? "string" == typeof c ? "html": "append": "text"](c), a.removeClass("fade top bottom left right in"), a.find(".popover-title").html() || a.find(".popover-title").hide() 685 | }, c.prototype.hasContent = function() { 686 | return this.getTitle() || this.getContent() 687 | }, c.prototype.getContent = function() { 688 | var a = this.$element, b = this.options; 689 | return a.attr("data-content") || ("function" == typeof b.content ? b.content.call(a[0]) : b.content) 690 | }, c.prototype.arrow = function() { 691 | return this.$arrow = this.$arrow || this.tip().find(".arrow") 692 | }; 693 | var d = a.fn.popover; 694 | a.fn.popover = b, a.fn.popover.Constructor = c, a.fn.popover.noConflict = function() { 695 | return a.fn.popover = d, this 696 | } 697 | }(jQuery), + function(a) { 698 | "use strict"; 699 | function b(c, d) { 700 | this.$body = a(document.body), this.$scrollElement = a(a(c).is(document.body) ? window : c), this.options = a.extend({}, b.DEFAULTS, d), this.selector = (this.options.target || "") + " .nav li > a", this.offsets = [], this.targets = [], this.activeTarget = null, this.scrollHeight = 0, this.$scrollElement.on("scroll.bs.scrollspy", a.proxy(this.process, this)), this.refresh(), this.process() 701 | } 702 | function c(c) { 703 | return this.each(function() { 704 | var d = a(this), e = d.data("bs.scrollspy"), f = "object" == typeof c && c; 705 | e || d.data("bs.scrollspy", e = new b(this, f)), "string" == typeof c && e[c]() 706 | }) 707 | } 708 | b.VERSION = "3.3.6", b.DEFAULTS = { 709 | offset: 10 710 | }, b.prototype.getScrollHeight = function() { 711 | return this.$scrollElement[0].scrollHeight || Math.max(this.$body[0].scrollHeight, document.documentElement.scrollHeight) 712 | }, b.prototype.refresh = function() { 713 | var b = this, c = "offset", d = 0; 714 | this.offsets = [], this.targets = [], this.scrollHeight = this.getScrollHeight(), a.isWindow(this.$scrollElement[0]) || (c = "position", d = this.$scrollElement.scrollTop()), this.$body.find(this.selector).map(function() { 715 | var b = a(this), e = b.data("target") || b.attr("href"), f = /^#./.test(e) && a(e); 716 | return f && f.length && f.is(":visible") && [[f[c]().top + d, e]] || null 717 | }).sort(function(a, b) { 718 | return a[0] - b[0] 719 | }).each(function() { 720 | b.offsets.push(this[0]), b.targets.push(this[1]) 721 | }) 722 | }, b.prototype.process = function() { 723 | var a, b = this.$scrollElement.scrollTop() + this.options.offset, c = this.getScrollHeight(), d = this.options.offset + c - this.$scrollElement.height(), e = this.offsets, f = this.targets, g = this.activeTarget; 724 | if (this.scrollHeight != c && this.refresh(), b >= d) 725 | return g != (a = f[f.length - 1]) && this.activate(a); 726 | if (g && b < e[0]) 727 | return this.activeTarget = null, this.clear(); 728 | for (a = e.length; a--;) 729 | g != f[a] && b >= e[a] && (void 0 === e[a + 1] || b < e[a + 1]) && this.activate(f[a]) 730 | }, b.prototype.activate = function(b) { 731 | this.activeTarget = b, this.clear(); 732 | var c = this.selector + '[data-target="' + b + '"],' + this.selector + '[href="' + b + '"]', d = a(c).parents("li").addClass("active"); 733 | d.parent(".dropdown-menu").length && (d = d.closest("li.dropdown").addClass("active")), d.trigger("activate.bs.scrollspy") 734 | }, b.prototype.clear = function() { 735 | a(this.selector).parentsUntil(this.options.target, ".active").removeClass("active") 736 | }; 737 | var d = a.fn.scrollspy; 738 | a.fn.scrollspy = c, a.fn.scrollspy.Constructor = b, a.fn.scrollspy.noConflict = function() { 739 | return a.fn.scrollspy = d, this 740 | }, a(window).on("load.bs.scrollspy.data-api", function() { 741 | a('[data-spy="scroll"]').each(function() { 742 | var b = a(this); 743 | c.call(b, b.data()) 744 | }) 745 | }) 746 | }(jQuery), + function(a) { 747 | "use strict"; 748 | function b(b) { 749 | return this.each(function() { 750 | var d = a(this), e = d.data("bs.tab"); 751 | e || d.data("bs.tab", e = new c(this)), "string" == typeof b && e[b]() 752 | }) 753 | } 754 | var c = function(b) { 755 | this.element = a(b) 756 | }; 757 | c.VERSION = "3.3.6", c.TRANSITION_DURATION = 150, c.prototype.show = function() { 758 | var b = this.element, c = b.closest("ul:not(.dropdown-menu)"), d = b.data("target"); 759 | if (d || (d = b.attr("href"), d = d && d.replace(/.*(?=#[^\s]*$)/, "")), !b.parent("li").hasClass("active")) { 760 | var e = c.find(".active:last a"), f = a.Event("hide.bs.tab", { 761 | relatedTarget: b[0] 762 | }), g = a.Event("show.bs.tab", { 763 | relatedTarget: e[0] 764 | }); 765 | if (e.trigger(f), b.trigger(g), !g.isDefaultPrevented()&&!f.isDefaultPrevented()) { 766 | var h = a(d); 767 | this.activate(b.closest("li"), c), this.activate(h, h.parent(), function() { 768 | e.trigger({ 769 | type: "hidden.bs.tab", 770 | relatedTarget: b[0] 771 | }), b.trigger({ 772 | type: "shown.bs.tab", 773 | relatedTarget: e[0] 774 | }) 775 | }) 776 | } 777 | } 778 | }, c.prototype.activate = function(b, d, e) { 779 | function f() { 780 | g.removeClass("active").find("> .dropdown-menu > .active").removeClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded", !1), b.addClass("active").find('[data-toggle="tab"]').attr("aria-expanded", !0), h ? (b[0].offsetWidth, b.addClass("in")) : b.removeClass("fade"), b.parent(".dropdown-menu").length && b.closest("li.dropdown").addClass("active").end().find('[data-toggle="tab"]').attr("aria-expanded", !0), e && e() 781 | } 782 | var g = d.find("> .active"), h = e && a.support.transition && (g.length && g.hasClass("fade")||!!d.find("> .fade").length); 783 | g.length && h ? g.one("bsTransitionEnd", f).emulateTransitionEnd(c.TRANSITION_DURATION) : f(), g.removeClass("in") 784 | }; 785 | var d = a.fn.tab; 786 | a.fn.tab = b, a.fn.tab.Constructor = c, a.fn.tab.noConflict = function() { 787 | return a.fn.tab = d, this 788 | }; 789 | var e = function(c) { 790 | c.preventDefault(), b.call(a(this), "show") 791 | }; 792 | a(document).on("click.bs.tab.data-api", '[data-toggle="tab"]', e).on("click.bs.tab.data-api", '[data-toggle="pill"]', e) 793 | }(jQuery), + function(a) { 794 | "use strict"; 795 | function b(b) { 796 | return this.each(function() { 797 | var d = a(this), e = d.data("bs.affix"), f = "object" == typeof b && b; 798 | e || d.data("bs.affix", e = new c(this, f)), "string" == typeof b && e[b]() 799 | }) 800 | } 801 | var c = function(b, d) { 802 | this.options = a.extend({}, c.DEFAULTS, d), this.$target = a(this.options.target).on("scroll.bs.affix.data-api", a.proxy(this.checkPosition, this)).on("click.bs.affix.data-api", a.proxy(this.checkPositionWithEventLoop, this)), this.$element = a(b), this.affixed = null, this.unpin = null, this.pinnedOffset = null, this.checkPosition() 803 | }; 804 | c.VERSION = "3.3.6", c.RESET = "affix affix-top affix-bottom", c.DEFAULTS = { 805 | offset: 0, 806 | target: window 807 | }, c.prototype.getState = function(a, b, c, d) { 808 | var e = this.$target.scrollTop(), f = this.$element.offset(), g = this.$target.height(); 809 | if (null != c && "top" == this.affixed) 810 | return c > e ? "top" : !1; 811 | if ("bottom" == this.affixed) 812 | return null != c ? e + this.unpin <= f.top?!1 : "bottom" : a - d >= e + g?!1 : "bottom"; 813 | var h = null == this.affixed, i = h ? e: f.top, j = h ? g: b; 814 | return null != c && c >= e ? "top" : null != d && i + j >= a - d ? "bottom" : !1 815 | }, c.prototype.getPinnedOffset = function() { 816 | if (this.pinnedOffset) 817 | return this.pinnedOffset; 818 | this.$element.removeClass(c.RESET).addClass("affix"); 819 | var a = this.$target.scrollTop(), b = this.$element.offset(); 820 | return this.pinnedOffset = b.top - a 821 | }, c.prototype.checkPositionWithEventLoop = function() { 822 | setTimeout(a.proxy(this.checkPosition, this), 1) 823 | }, c.prototype.checkPosition = function() { 824 | if (this.$element.is(":visible")) { 825 | var b = this.$element.height(), d = this.options.offset, e = d.top, f = d.bottom, g = Math.max(a(document).height(), a(document.body).height()); 826 | "object" != typeof d && (f = e = d), "function" == typeof e && (e = d.top(this.$element)), "function" == typeof f && (f = d.bottom(this.$element)); 827 | var h = this.getState(g, b, e, f); 828 | if (this.affixed != h) { 829 | null != this.unpin && this.$element.css("top", ""); 830 | var i = "affix" + (h ? "-" + h : ""), j = a.Event(i + ".bs.affix"); 831 | if (this.$element.trigger(j), j.isDefaultPrevented()) 832 | return; 833 | this.affixed = h, this.unpin = "bottom" == h ? this.getPinnedOffset() : null, this.$element.removeClass(c.RESET).addClass(i).trigger(i.replace("affix", "affixed") + ".bs.affix") 834 | } 835 | "bottom" == h && this.$element.offset({ 836 | top: g - b - f 837 | }) 838 | } 839 | }; 840 | var d = a.fn.affix; 841 | a.fn.affix = b, a.fn.affix.Constructor = c, a.fn.affix.noConflict = function() { 842 | return a.fn.affix = d, this 843 | }, a(window).on("load", function() { 844 | a('[data-spy="affix"]').each(function() { 845 | var c = a(this), d = c.data(); 846 | d.offset = d.offset || {}, null != d.offsetBottom && (d.offset.bottom = d.offsetBottom), null != d.offsetTop && (d.offset.top = d.offsetTop), b.call(c, d) 847 | }) 848 | }) 849 | }(jQuery); 850 | -------------------------------------------------------------------------------- /server/public/js/dragdrop.min.js: -------------------------------------------------------------------------------- 1 | !function(e){if("object"==typeof exports&&"undefined"!=typeof module)module.exports=e();else if("function"==typeof define&&define.amd)define([],e);else{var n;n="undefined"!=typeof window?window:"undefined"!=typeof global?global:"undefined"!=typeof self?self:this,n.DragDrop=e()}}(function(){return function e(n,t,r){function o(u,a){if(!t[u]){if(!n[u]){var f="function"==typeof require&&require;if(!a&&f)return f(u,!0);if(i)return i(u,!0);var c=new Error("Cannot find module '"+u+"'");throw c.code="MODULE_NOT_FOUND",c}var l=t[u]={exports:{}};n[u][0].call(l.exports,function(e){var t=n[u][1][e];return o(t?t:e)},l,l.exports,e,n,t,r)}return t[u].exports}for(var i="function"==typeof require&&require,u=0;u1)for(var t=1;t0?(u=u.concat(i(e)),t()):r()})}function r(){a(u.map(function(e){return function(n){o(e,n)}}),n)}var u=[];if(e.isFile)e.file(function(t){t.fullPath=e.fullPath,n(null,t)},function(e){n(e)});else if(e.isDirectory){var f=e.createReader();t()}}function i(e){return Array.prototype.slice.call(e||[],0)}n.exports=r;var u=e("flatten"),a=e("run-parallel")},{flatten:1,"run-parallel":3}]},{},[])("/")}); -------------------------------------------------------------------------------- /server/public/js/html5shiv.min.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @preserve HTML5 Shiv 3.7.2 | @afarkas @jdalton @jon_neal @rem | MIT/GPL2 Licensed 3 | */ 4 | !function(a,b){function c(a,b){var c=a.createElement("p"),d=a.getElementsByTagName("head")[0]||a.documentElement;return c.innerHTML="x",d.insertBefore(c.lastChild,d.firstChild)}function d(){var a=t.elements;return"string"==typeof a?a.split(" "):a}function e(a,b){var c=t.elements;"string"!=typeof c&&(c=c.join(" ")),"string"!=typeof a&&(a=a.join(" ")),t.elements=c+" "+a,j(b)}function f(a){var b=s[a[q]];return b||(b={},r++,a[q]=r,s[r]=b),b}function g(a,c,d){if(c||(c=b),l)return c.createElement(a);d||(d=f(c));var e;return e=d.cache[a]?d.cache[a].cloneNode():p.test(a)?(d.cache[a]=d.createElem(a)).cloneNode():d.createElem(a),!e.canHaveChildren||o.test(a)||e.tagUrn?e:d.frag.appendChild(e)}function h(a,c){if(a||(a=b),l)return a.createDocumentFragment();c=c||f(a);for(var e=c.frag.cloneNode(),g=0,h=d(),i=h.length;i>g;g++)e.createElement(h[g]);return e}function i(a,b){b.cache||(b.cache={},b.createElem=a.createElement,b.createFrag=a.createDocumentFragment,b.frag=b.createFrag()),a.createElement=function(c){return t.shivMethods?g(c,a,b):b.createElem(c)},a.createDocumentFragment=Function("h,f","return function(){var n=f.cloneNode(),c=n.createElement;h.shivMethods&&("+d().join().replace(/[\w\-:]+/g,function(a){return b.createElem(a),b.frag.createElement(a),'c("'+a+'")'})+");return n}")(t,b.frag)}function j(a){a||(a=b);var d=f(a);return!t.shivCSS||k||d.hasCSS||(d.hasCSS=!!c(a,"article,aside,dialog,figcaption,figure,footer,header,hgroup,main,nav,section{display:block}mark{background:#FF0;color:#000}template{display:none}")),l||i(a,d),a}var k,l,m="3.7.2",n=a.html5||{},o=/^<|^(?:button|map|select|textarea|object|iframe|option|optgroup)$/i,p=/^(?:a|b|code|div|fieldset|h1|h2|h3|h4|h5|h6|i|label|li|ol|p|q|span|strong|style|table|tbody|td|th|tr|ul)$/i,q="_html5shiv",r=0,s={};!function(){try{var a=b.createElement("a");a.innerHTML="",k="hidden"in a,l=1==a.childNodes.length||function(){b.createElement("a");var a=b.createDocumentFragment();return"undefined"==typeof a.cloneNode||"undefined"==typeof a.createDocumentFragment||"undefined"==typeof a.createElement}()}catch(c){k=!0,l=!0}}();var t={elements:n.elements||"abbr article aside audio bdi canvas data datalist details dialog figcaption figure footer header hgroup main mark meter nav output picture progress section summary template time video",version:m,shivCSS:n.shivCSS!==!1,supportsUnknownElements:l,shivMethods:n.shivMethods!==!1,type:"default",shivDocument:j,createElement:g,createDocumentFragment:h,addElements:e};a.html5=t,j(b)}(this,document); -------------------------------------------------------------------------------- /server/public/js/ie-emulation-modes-warning.js: -------------------------------------------------------------------------------- 1 | // NOTICE!! DO NOT USE ANY OF THIS JAVASCRIPT 2 | // IT'S JUST JUNK FOR OUR DOCS! 3 | // ++++++++++++++++++++++++++++++++++++++++++ 4 | /*! 5 | * Copyright 2014-2015 Twitter, Inc. 6 | * 7 | * Licensed under the Creative Commons Attribution 3.0 Unported License. For 8 | * details, see https://creativecommons.org/licenses/by/3.0/. 9 | */ 10 | // Intended to prevent false-positive bug reports about Bootstrap not working properly in old versions of IE due to folks testing using IE's unreliable emulation modes. 11 | (function () { 12 | 'use strict'; 13 | 14 | function emulatedIEMajorVersion() { 15 | var groups = /MSIE ([0-9.]+)/.exec(window.navigator.userAgent) 16 | if (groups === null) { 17 | return null 18 | } 19 | var ieVersionNum = parseInt(groups[1], 10) 20 | var ieMajorVersion = Math.floor(ieVersionNum) 21 | return ieMajorVersion 22 | } 23 | 24 | function actualNonEmulatedIEMajorVersion() { 25 | // Detects the actual version of IE in use, even if it's in an older-IE emulation mode. 26 | // IE JavaScript conditional compilation docs: https://msdn.microsoft.com/library/121hztk3%28v=vs.94%29.aspx 27 | // @cc_on docs: https://msdn.microsoft.com/library/8ka90k2e%28v=vs.94%29.aspx 28 | var jscriptVersion = new Function('/*@cc_on return @_jscript_version; @*/')() // jshint ignore:line 29 | if (jscriptVersion === undefined) { 30 | return 11 // IE11+ not in emulation mode 31 | } 32 | if (jscriptVersion < 9) { 33 | return 8 // IE8 (or lower; haven't tested on IE<8) 34 | } 35 | return jscriptVersion // IE9 or IE10 in any mode, or IE11 in non-IE11 mode 36 | } 37 | 38 | var ua = window.navigator.userAgent 39 | if (ua.indexOf('Opera') > -1 || ua.indexOf('Presto') > -1) { 40 | return // Opera, which might pretend to be IE 41 | } 42 | var emulated = emulatedIEMajorVersion() 43 | if (emulated === null) { 44 | return // Not IE 45 | } 46 | var nonEmulated = actualNonEmulatedIEMajorVersion() 47 | 48 | if (emulated !== nonEmulated) { 49 | window.alert('WARNING: You appear to be using IE' + nonEmulated + ' in IE' + emulated + ' emulation mode.\nIE emulation modes can behave significantly differently from ACTUAL older versions of IE.\nPLEASE DON\'T FILE BOOTSTRAP BUGS based on testing in IE emulation modes!') 50 | } 51 | })(); 52 | -------------------------------------------------------------------------------- /server/public/js/ie10-viewport-bug-workaround.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * IE10 viewport hack for Surface/desktop Windows 8 bug 3 | * Copyright 2014-2015 Twitter, Inc. 4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5 | */ 6 | 7 | // See the Getting Started docs for more information: 8 | // http://getbootstrap.com/getting-started/#support-ie10-width 9 | 10 | (function () { 11 | 'use strict'; 12 | 13 | if (navigator.userAgent.match(/IEMobile\/10\.0/)) { 14 | var msViewportStyle = document.createElement('style') 15 | msViewportStyle.appendChild( 16 | document.createTextNode( 17 | '@-ms-viewport{width:auto!important}' 18 | ) 19 | ) 20 | document.querySelector('head').appendChild(msViewportStyle) 21 | } 22 | 23 | })(); 24 | -------------------------------------------------------------------------------- /server/public/js/respond.min.js: -------------------------------------------------------------------------------- 1 | /*! Respond.js v1.4.2: min/max-width media query polyfill * Copyright 2013 Scott Jehl 2 | * Licensed under https://github.com/scottjehl/Respond/blob/master/LICENSE-MIT 3 | * */ 4 | 5 | !function(a){"use strict";a.matchMedia=a.matchMedia||function(a){var b,c=a.documentElement,d=c.firstElementChild||c.firstChild,e=a.createElement("body"),f=a.createElement("div");return f.id="mq-test-1",f.style.cssText="position:absolute;top:-100em",e.style.background="none",e.appendChild(f),function(a){return f.innerHTML='­',c.insertBefore(e,d),b=42===f.offsetWidth,c.removeChild(e),{matches:b,media:a}}}(a.document)}(this),function(a){"use strict";function b(){u(!0)}var c={};a.respond=c,c.update=function(){};var d=[],e=function(){var b=!1;try{b=new a.XMLHttpRequest}catch(c){b=new a.ActiveXObject("Microsoft.XMLHTTP")}return function(){return b}}(),f=function(a,b){var c=e();c&&(c.open("GET",a,!0),c.onreadystatechange=function(){4!==c.readyState||200!==c.status&&304!==c.status||b(c.responseText)},4!==c.readyState&&c.send(null))};if(c.ajax=f,c.queue=d,c.regex={media:/@media[^\{]+\{([^\{\}]*\{[^\}\{]*\})+/gi,keyframes:/@(?:\-(?:o|moz|webkit)\-)?keyframes[^\{]+\{(?:[^\{\}]*\{[^\}\{]*\})+[^\}]*\}/gi,urls:/(url\()['"]?([^\/\)'"][^:\)'"]+)['"]?(\))/g,findStyles:/@media *([^\{]+)\{([\S\s]+?)$/,only:/(only\s+)?([a-zA-Z]+)\s?/,minw:/\([\s]*min\-width\s*:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/,maxw:/\([\s]*max\-width\s*:[\s]*([\s]*[0-9\.]+)(px|em)[\s]*\)/},c.mediaQueriesSupported=a.matchMedia&&null!==a.matchMedia("only all")&&a.matchMedia("only all").matches,!c.mediaQueriesSupported){var g,h,i,j=a.document,k=j.documentElement,l=[],m=[],n=[],o={},p=30,q=j.getElementsByTagName("head")[0]||k,r=j.getElementsByTagName("base")[0],s=q.getElementsByTagName("link"),t=function(){var a,b=j.createElement("div"),c=j.body,d=k.style.fontSize,e=c&&c.style.fontSize,f=!1;return b.style.cssText="position:absolute;font-size:1em;width:1em",c||(c=f=j.createElement("body"),c.style.background="none"),k.style.fontSize="100%",c.style.fontSize="100%",c.appendChild(b),f&&k.insertBefore(c,k.firstChild),a=b.offsetWidth,f?k.removeChild(c):c.removeChild(b),k.style.fontSize=d,e&&(c.style.fontSize=e),a=i=parseFloat(a)},u=function(b){var c="clientWidth",d=k[c],e="CSS1Compat"===j.compatMode&&d||j.body[c]||d,f={},o=s[s.length-1],r=(new Date).getTime();if(b&&g&&p>r-g)return a.clearTimeout(h),h=a.setTimeout(u,p),void 0;g=r;for(var v in l)if(l.hasOwnProperty(v)){var w=l[v],x=w.minw,y=w.maxw,z=null===x,A=null===y,B="em";x&&(x=parseFloat(x)*(x.indexOf(B)>-1?i||t():1)),y&&(y=parseFloat(y)*(y.indexOf(B)>-1?i||t():1)),w.hasquery&&(z&&A||!(z||e>=x)||!(A||y>=e))||(f[w.media]||(f[w.media]=[]),f[w.media].push(m[w.rules]))}for(var C in n)n.hasOwnProperty(C)&&n[C]&&n[C].parentNode===q&&q.removeChild(n[C]);n.length=0;for(var D in f)if(f.hasOwnProperty(D)){var E=j.createElement("style"),F=f[D].join("\n");E.type="text/css",E.media=D,q.insertBefore(E,o.nextSibling),E.styleSheet?E.styleSheet.cssText=F:E.appendChild(j.createTextNode(F)),n.push(E)}},v=function(a,b,d){var e=a.replace(c.regex.keyframes,"").match(c.regex.media),f=e&&e.length||0;b=b.substring(0,b.lastIndexOf("/"));var g=function(a){return a.replace(c.regex.urls,"$1"+b+"$2$3")},h=!f&&d;b.length&&(b+="/"),h&&(f=1);for(var i=0;f>i;i++){var j,k,n,o;h?(j=d,m.push(g(a))):(j=e[i].match(c.regex.findStyles)&&RegExp.$1,m.push(RegExp.$2&&g(RegExp.$2))),n=j.split(","),o=n.length;for(var p=0;o>p;p++)k=n[p],l.push({media:k.split("(")[0].match(c.regex.only)&&RegExp.$2||"all",rules:m.length-1,hasquery:k.indexOf("(")>-1,minw:k.match(c.regex.minw)&&parseFloat(RegExp.$1)+(RegExp.$2||""),maxw:k.match(c.regex.maxw)&&parseFloat(RegExp.$1)+(RegExp.$2||"")})}u()},w=function(){if(d.length){var b=d.shift();f(b.href,function(c){v(c,b.href,b.media),o[b.href]=!0,a.setTimeout(function(){w()},0)})}},x=function(){for(var b=0;b<%= message %> 2 |

<%= error.status %>

3 |
<%= error.stack %>
4 | -------------------------------------------------------------------------------- /server/views/foot.ejs: -------------------------------------------------------------------------------- 1 |
2 | 3 |
4 |

© 2016-2017 Company BtOnline, Inc.

5 |
6 | 7 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /server/views/head.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Node.js 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /server/views/index.ejs: -------------------------------------------------------------------------------- 1 | <% include head.ejs %> 2 | <% include nav.ejs %> 3 |
4 |
5 |
6 |
7 | 8 | 9 |
10 |
11 | 12 | 13 |
14 |
15 |
16 |
17 |

下载速度 :

18 |

下载进度 :

19 |
20 |
0%
21 |
22 |
23 | <% include foot.ejs %> -------------------------------------------------------------------------------- /server/views/nav.ejs: -------------------------------------------------------------------------------- 1 | --------------------------------------------------------------------------------