├── .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 | 
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 |
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 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
24 |
25 |
28 |
--------------------------------------------------------------------------------
/WebUI/src/components/Body.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
21 |
22 |
23 |
Downloading
24 |
Seeding
25 |
26 | {{link}}
27 |
28 |
from
29 |
to
30 |
0 peers
.
31 |
32 |
33 |
of
—
↘
34 | 0 b/s
/ ↗0 b/s
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 | Well Done!
45 | You successfully read this important alert message :)
46 |
47 |
48 |
49 |
50 | Something was wrong!
51 | Try again latter :(
52 |
53 |
54 |
55 |
56 |
57 |
156 |
157 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
221 |
222 |
223 |
Downloading
224 |
Seeding
225 |
226 | {{link}}
227 |
228 |
from
229 |
to
230 |
0 peers
.
231 |
232 |
233 |
of
—
↘
234 | 0 b/s
/ ↗0 b/s
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 | Well Done!
245 | You successfully read this important alert message :)
246 |
247 |
248 |
249 |
250 | Something was wrong!
251 | Try again latter :(
252 |
253 |
254 |
255 |
256 |
257 |
356 |
357 |
401 |
--------------------------------------------------------------------------------
/WebUI/src/components/Footer.vue:
--------------------------------------------------------------------------------
1 |
2 |
11 |
12 |
13 |
18 |
19 |
21 |
--------------------------------------------------------------------------------
/WebUI/src/components/Header.vue:
--------------------------------------------------------------------------------
1 |
2 |
31 |
32 |
33 |
43 |
44 |
47 |
--------------------------------------------------------------------------------
/WebUI/src/components/Hello.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{ msg }}
4 | Essential Links
5 |
6 |
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 |
6 |
7 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |