├── .gitignore ├── LICENSE ├── jsconfig.json ├── modules ├── chaoxing │ ├── api │ │ ├── attachment.js │ │ ├── automatic.js │ │ ├── course.js │ │ ├── courseList.js │ │ ├── login.js │ │ └── saveStatus.js │ ├── chaoxingRequest.js │ ├── chaoxingRoute.js │ └── crypto.js └── lemonSchool │ ├── autoPlay.js │ ├── crypto.js │ ├── lemonRequest.js │ ├── lemonSchool.js │ └── lemonSchoolRoute.js ├── mongo ├── chaoxing.js ├── mongodb.js └── user.js ├── package-lock.json ├── package.json ├── public ├── css │ └── bootstrap-3.3.7-dist │ │ ├── css │ │ ├── bootstrap-theme.css │ │ ├── bootstrap-theme.css.map │ │ ├── bootstrap-theme.min.css │ │ ├── bootstrap-theme.min.css.map │ │ ├── bootstrap.css │ │ ├── bootstrap.css.map │ │ ├── bootstrap.min.css │ │ └── bootstrap.min.css.map │ │ ├── fonts │ │ ├── glyphicons-halflings-regular.eot │ │ ├── glyphicons-halflings-regular.svg │ │ ├── glyphicons-halflings-regular.ttf │ │ ├── glyphicons-halflings-regular.woff │ │ └── glyphicons-halflings-regular.woff2 │ │ └── js │ │ ├── bootstrap.js │ │ ├── bootstrap.min.js │ │ └── npm.js ├── index.html ├── js │ ├── index.js │ └── js-cookie.js └── test.html ├── readme.md ├── server.js ├── tools ├── HttpRequest.js ├── request.js └── tools.js └── upload ├── Rec 0002.gif ├── img.jpg ├── new_01.jpg ├── new_02.jpg └── new_03.jpg /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | 3 | *.zip -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | ISC License 2 | 3 | Copyright (c) 2021, 孤独的小丑 4 | 5 | Permission to use, copy, modify, and/or distribute this software for any 6 | purpose with or without fee is hereby granted, provided that the above 7 | copyright notice and this permission notice appear in all copies. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 | WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 | MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 | ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 | WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 | ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 | OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 | -------------------------------------------------------------------------------- /jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "typeAcquisition": { 3 | "include": [ 4 | "jquery" 5 | ] 6 | } 7 | } -------------------------------------------------------------------------------- /modules/chaoxing/api/attachment.js: -------------------------------------------------------------------------------- 1 | const request = require('../chaoxingRequest'); 2 | 3 | const host = 'http://mooc1.chaoxing.com'; 4 | 5 | const cheerio = require('cheerio'); 6 | 7 | async function attachment(params = {}, options = {}) { 8 | 9 | /* 10 | courseId: 219802873 11 | clazzid: 54961318 12 | chapterId: 470144782 13 | cpi: 170786324 14 | verificationcode: 15 | mooc2: 1 16 | */ 17 | 18 | var { courseId, clazzid, chapterId } = params; 19 | var result = await request('http://mooc1.chaoxing.com/mycourse/studentstudyAjax', 'post', { 20 | courseId: courseId, 21 | clazzid: clazzid, 22 | chapterId: chapterId, 23 | verificationcode: '', 24 | mooc2: 1 25 | }, options); 26 | 27 | var $ = cheerio.load(result.data), 28 | Concurrencys = []; 29 | 30 | var $tabBtns = $('#prev_tab .prev_ul > li'), 31 | iframeSrc = $('#iframe').prop('src'); 32 | 33 | // 并发请求获取iframe资源 34 | $tabBtns.each(function (index) { 35 | var url = new URL(iframeSrc, host); 36 | url.searchParams.set('num', index); 37 | Concurrencys.push(request(url.toString(), 'get', {}, options)); 38 | }); 39 | 40 | return Promise.all(Concurrencys).then(documents => { 41 | var resources = [], 42 | mArgRule = /mArg\s*=\s*{(.+)}/; 43 | documents.forEach(function (doc) { 44 | var mArg = doc.data.match(mArgRule) || ['']; 45 | if (doc.data.length > 0) { 46 | resources.push(JSON.parse(mArg[0].replace(/mArg\s*=\s*/, '') || '{}')); 47 | } 48 | }); 49 | return { 50 | attachments: resources 51 | }; 52 | }); 53 | } 54 | 55 | module.exports = attachment; -------------------------------------------------------------------------------- /modules/chaoxing/api/automatic.js: -------------------------------------------------------------------------------- 1 | const getCourseList = require('./courseList'); 2 | 3 | const getAttachments = require('./attachment'); 4 | 5 | const saveStatus = require('./saveStatus'); 6 | 7 | const { ChaoXing } = require('../../../mongo/chaoxing'); 8 | 9 | var queue = {}; 10 | 11 | module.exports = async (params, options) => { 12 | 13 | var { uname, courseId, clazzid, personid } = params; 14 | console.log(params); 15 | 16 | if (!(courseId && clazzid && personid)) { 17 | return { 18 | code: 400, 19 | msg: '参数不能为空' 20 | }; 21 | } 22 | 23 | var user = await ChaoXing.findOne({ user: uname }); 24 | 25 | if (!user) return { code: 201, msg: '请先进行登陆' } 26 | 27 | if (queue[uname]) { 28 | return { code: 400, msg: '当前账号正在刷取中,请勿多次提交!' } 29 | } else { queue[uname] = uname } 30 | 31 | 32 | var des = new Auto({ user, options, courseInfo: params }, function () { 33 | // 利用闭包操作,成功后删除已经刷取完毕的账号 34 | console.log(`账号:[${uname}]课程刷取完毕!`); 35 | delete queue[uname]; 36 | }); 37 | 38 | des.autoPlay(); 39 | 40 | return { 41 | msg: '提交成功', 42 | queue, 43 | info: randomStr() 44 | } 45 | } 46 | 47 | // 生成随机Str 48 | function randomStr(prefix = 'zzr') { 49 | 50 | var init = [prefix], 51 | I = Math.random() * 13, 52 | Love = Math.random() * 14, 53 | You = Math.random() * 520, 54 | GoodBye = I + Love + You; 55 | 56 | // console.log(I, Love, You, GoodBye); 57 | 58 | init[init.length] = Math.ceil(Date.now() / GoodBye); 59 | 60 | return init.join('_'); 61 | } 62 | 63 | 64 | class Auto { 65 | 66 | constructor(params, callback) { 67 | 68 | this.user = params.user || {}; 69 | 70 | this.options = params.options || {}; 71 | 72 | this.courseInfo = params.courseInfo || {}; 73 | 74 | this.callback = callback; 75 | 76 | // 课程总项 77 | this.subjects = []; 78 | 79 | // 已经完成课程项的总数 80 | this.completeCount = 0; 81 | 82 | } 83 | 84 | // 获取课程下科目项 85 | async getSubjects(params, options) { 86 | var { data: subjects } = await getCourseList(params, options); 87 | if (subjects.length === 0) { 88 | console.log(`获取课程项 [失败] 可能已限制访问 需要手动输入验证码`); 89 | } 90 | // 筛选还没有完成的科目 91 | return subjects.filter(item => !item.isPass); 92 | } 93 | 94 | async getAttachments(params, options) { 95 | var { attachments } = await getAttachments(params, options); 96 | return attachments.filter(item => item.attachments.length > 0); 97 | } 98 | 99 | async autoPlay() { 100 | this.subjects = await this.getSubjects(this.courseInfo, this.options); 101 | if (this.subjects.length === 0) { 102 | console.log(`当前课程中暂时没发现还没有完成的课程项`); 103 | this.callback && this.callback(); 104 | return false; 105 | } 106 | this.subjects.forEach((item, index) => { 107 | this.timer(item, (index + 1) * 5000); 108 | }); 109 | 110 | } 111 | 112 | timer(subjectItem, time) { 113 | setTimeout(this.callStack.bind(this, subjectItem), time || 2000); 114 | } 115 | 116 | async callStack(target = {}) { 117 | 118 | var currentTarget = target, 119 | { chapter_name, section_name, data } = currentTarget || {}; 120 | 121 | console.log(`正在搜查 [${chapter_name}] 中的 [${section_name}] 可执行任务`); 122 | 123 | var params = { 124 | 'courseId': data[0], 125 | 'clazzid': data[1], 126 | 'chapterId': data[2] 127 | } 128 | 129 | // 获取当前章节中的任务附件 130 | try { 131 | currentTarget.taskTotal = await this.getAttachments(params, this.options); 132 | } catch (err) { 133 | console.log(`搜查 [${chapter_name}] 中的 [${section_name}] 可执行任务 [失败]`); 134 | this.total(); 135 | return false; 136 | } 137 | 138 | console.log(`在 [${chapter_name}] 中的 [${section_name}] 发现 [${currentTarget.taskTotal.length}] 个可执行任务`); 139 | 140 | currentTarget.taskCount = 0; 141 | 142 | this.attachmentTask(currentTarget); 143 | 144 | } 145 | 146 | total() { 147 | this.completeCount++; 148 | if (this.completeCount >= this.subjects.length) { 149 | this.callback && this.callback(); 150 | } 151 | } 152 | 153 | attachmentTask(currentTarget) { 154 | // var c = { 155 | // taskTotal: [ 156 | // { 157 | // attachments: [], 158 | // defaults: {} 159 | // }, 160 | // { 161 | // attachments: [], 162 | // defaults: {} 163 | // }, 164 | // { 165 | // attachments: [], 166 | // defaults: {} 167 | // } 168 | // ] 169 | // } 170 | const { chapter_name, section_name, taskTotal } = currentTarget, 171 | currentTask = taskTotal[currentTarget.taskCount]; 172 | 173 | if (currentTarget.taskCount >= taskTotal.length) { 174 | console.log(`${chapter_name}中的${section_name}任务已经全部完成`); 175 | this.total(); 176 | return; 177 | } 178 | 179 | currentTask['currentIndex'] = currentTarget.taskCount; 180 | 181 | currentTarget.taskCount++; 182 | 183 | currentTask['chapter_name'] = chapter_name; 184 | currentTask['section_name'] = section_name; 185 | 186 | this.saveStatus(currentTask, 0); 187 | 188 | setTimeout(this.attachmentTask.bind(this), 2000, currentTarget); 189 | } 190 | 191 | async saveStatus(currentTask, count) { 192 | 193 | var { chapter_name, section_name, attachments, defaults, currentIndex } = currentTask; 194 | 195 | if (count >= attachments.length) { 196 | console.log(`当前 [${chapter_name}] [${section_name}] [${currentIndex}] 项的附件任务已经全部完成`); 197 | return; 198 | } 199 | 200 | var currentAttas = attachments[count], rules = /video|\.mp4/i, 201 | { type, property } = currentAttas || {}, 202 | fileName = property.name || property.title || property.module; 203 | 204 | 205 | if (!(rules.test(type) || rules.test(property['type']))) { 206 | console.log(`当前 [${chapter_name}] [${section_name}] 中的 [${fileName}] 不是视频附件已跳过此附件任务`); 207 | this.saveStatus(currentTask, count + 1); 208 | return; 209 | } 210 | 211 | console.log(`正在开始发送请求完成 [${chapter_name}] [${section_name}] 中的 [${property.name}] 附件任务`); 212 | 213 | var params = { 214 | clazzId: defaults['clazzId'], 215 | objectId: currentAttas['objectId'], 216 | otherInfo: currentAttas['otherInfo'], 217 | jobid: property['_jobid'], 218 | userid: defaults['userid'], 219 | reportUrl: defaults['reportUrl'], 220 | rt: property['rt'] 221 | } 222 | 223 | try { 224 | var { data } = await saveStatus(params, this.options); 225 | } catch (err) { 226 | // console.log(err); 227 | console.log(`当前 [${chapter_name}] [${section_name}] 中的 [${property.name}] 保存状态失败`); 228 | } 229 | 230 | console.log(data); 231 | 232 | if (data.isPassed) { 233 | console.log(`当前 [${chapter_name}] [${section_name}] 中的 [${property.name}] 保存状态成功`); 234 | }else{ 235 | console.log(`当前 [${chapter_name}] [${section_name}] 中的 [${property.name}] 附件状态,没有检测到通过`); 236 | console.log(`正在重新尝试保存 [${chapter_name}] [${section_name}] 中的 [${property.name}] 附件状态任务`); 237 | count--; 238 | } 239 | 240 | count++; 241 | 242 | setTimeout(this.saveStatus.bind(this), 5000, currentTask, count); 243 | } 244 | 245 | } -------------------------------------------------------------------------------- /modules/chaoxing/api/course.js: -------------------------------------------------------------------------------- 1 | const request = require('../chaoxingRequest'); 2 | 3 | const cheerio = require('cheerio'); 4 | 5 | module.exports = async function (params, options) { 6 | 7 | var { data } = await request('https://mooc1-1.chaoxing.com/visit/courselistdata', 'get', { 8 | courseType: 1, 9 | courseFolderId: 0, 10 | baseEducation: 0, 11 | courseFolderSize: 0 12 | }, options); 13 | 14 | var $ = cheerio.load(data), 15 | lists = []; 16 | 17 | $('#courseList').children('li').each(function (index, el) { 18 | var $el = $(el); 19 | lists.push({ 20 | name: $el.find('.course-name').text(), 21 | courseid: $el.attr('courseid'), 22 | personid: $el.attr('personid'), 23 | clazzid: $el.attr('clazzid'), 24 | link: $el.children('.course-cover').find('a').prop('href') 25 | }); 26 | }); 27 | 28 | return { 29 | data: lists 30 | } 31 | } -------------------------------------------------------------------------------- /modules/chaoxing/api/courseList.js: -------------------------------------------------------------------------------- 1 | const request = require('../chaoxingRequest'); 2 | 3 | // 和jQuery一样的选择器 4 | const cheerio = require('cheerio'); 5 | 6 | module.exports = async function (params, options) { 7 | var { courseId, chapterId, clazzid, personid } = params; 8 | 9 | var result = await request('http://mooc1.chaoxing.com/mycourse/studentstudycourselist', 'get', { 10 | courseId: courseId, 11 | chapterId: '', 12 | clazzid: clazzid, 13 | mooc2: 1, 14 | cpi: personid || '' 15 | }, options); 16 | 17 | var $ = cheerio.load(result['data']); 18 | 19 | var course_data = []; 20 | 21 | $('[onclick^=getTeacherAjax]').each((index, element) => { 22 | 23 | var data = $(element).attr('onclick'); 24 | var posCatalog_select = $(element).parents('.posCatalog_level').siblings('.posCatalog_select') 25 | 26 | course_data.push({ 27 | section_name: $(element).attr('title'), 28 | data: data.match(/\((.+)\)/)[1].replace(/'/g, '').split(','), 29 | chapter_name: posCatalog_select.find('span').attr('title'), 30 | id: posCatalog_select.attr('id'), 31 | isPass: $(element).siblings('.prevTips').hasClass('icon_Completed') 32 | }); 33 | 34 | }); 35 | 36 | return result['data'] = course_data, result; 37 | } -------------------------------------------------------------------------------- /modules/chaoxing/api/login.js: -------------------------------------------------------------------------------- 1 | const request = require('../chaoxingRequest'); 2 | 3 | const { cookieParse, cookieStringify } = require('../../../tools/tools'); 4 | 5 | const { createUser } = require('../../../mongo/chaoxing'); 6 | 7 | const { encrypt, decrypt } = require('../crypto'); 8 | 9 | module.exports = async (params, options = {}) => { 10 | 11 | var { cookie: cookies } = options; 12 | 13 | if (cookies['UID'] && cookies['fid']) { 14 | return { 15 | code: 301, 16 | msg: '当前已处于登陆状态' 17 | } 18 | } 19 | 20 | var { uname, password } = params; 21 | if (!uname || !password) { 22 | return { 23 | code: 400, 24 | msg: '请输入完整' 25 | } 26 | } 27 | 28 | var { data, cookie } = await request('http://passport2.chaoxing.com/fanyalogin', 'post', { 29 | fid: options.fid || -1, 30 | uname: uname, 31 | password: encrypt(password, 'u2oh6Vu^HWe40fj'), 32 | refer: encodeURIComponent('http://i.chaoxing.com'), 33 | t: true, 34 | forbidotherlogin: 0, 35 | validate: '' 36 | }, options); 37 | 38 | if (!data.status) { 39 | return { 40 | code: 201, 41 | msg: data.msg2 || '登陆失败,请稍后重试!' 42 | } 43 | } 44 | 45 | var response = await request('http://i.chaoxing.com', 'get', {}, { 46 | cookie: cookieStringify(cookieParse(cookie)) 47 | }); 48 | 49 | var location = response._http['responseHeaders']['location'], 50 | cookies = cookie.concat(response.cookie); 51 | return request(location, 'get', {}, { 52 | cookie: cookieStringify(cookieParse(cookies)) 53 | }).then(({ data, cookie }) => { 54 | 55 | createUser({ 56 | user: uname, 57 | password: password, 58 | cookie: cookieStringify(cookieParse(cookies.concat(cookie))), 59 | userInit: { 60 | login_time: Date.now() 61 | } 62 | }); 63 | 64 | return Promise.resolve({ 65 | msg: '登陆成功', 66 | code: 200, 67 | cookie: cookies.concat(cookie) 68 | }) 69 | }); 70 | 71 | } -------------------------------------------------------------------------------- /modules/chaoxing/api/saveStatus.js: -------------------------------------------------------------------------------- 1 | const request = require('../chaoxingRequest'); 2 | 3 | const md5 = require('md5-node'); 4 | 5 | module.exports = async (params, options) => { 6 | 7 | var { data: info, cookie } = await getAttachmentInfo(params, options); 8 | 9 | params['dtoken'] = info['dtoken']; 10 | params['duration'] = info['duration']; 11 | 12 | var { data: result, cookie: resCookie } = await saveStatus(params, options); 13 | 14 | return { 15 | data: result, 16 | attachmentInfo: info, 17 | cookie: cookie.concat(resCookie) 18 | }; 19 | } 20 | 21 | async function saveStatus(params, options) { 22 | 23 | var duration = params['duration'], 24 | playTime = duration * 1000, 25 | clazzId = params['clazzId'], 26 | clipTime = 0 + '_' + duration, 27 | objectId = params['objectId'], 28 | otherInfo = params['otherInfo'], 29 | jobid = params['jobid'], 30 | userid = params['userid'], 31 | enc = `[${clazzId}][${userid}][${jobid}][${objectId}][${playTime}][d_yHJ!$pdA~5][${duration * 1000}][${clipTime}]`; 32 | 33 | // '[clazzId][userid][jobid][objectId][已播放毫秒]["d_yHJ!$pdA~5"][duration * 1000][0_endTime]' 34 | // "[59093676][57949954][1582641044173926][211ceda28b40271afa2c8121f51d845f][9000][d_yHJ!$pdA~5][1476000][0_1476]" 35 | 36 | return request(`${params['reportUrl']}/${params['dtoken']}`, 'get', { 37 | clazzId: clazzId, 38 | playingTime: playTime / 1000, 39 | duration: duration, 40 | clipTime: clipTime, 41 | objectId: objectId, 42 | otherInfo: otherInfo, 43 | jobid: jobid, 44 | userid: userid, 45 | isdrag: '4', 46 | view: 'pc', 47 | enc: md5(enc), 48 | rt: params['rt'] || '0.9', 49 | dtype: 'Video', 50 | _t: Date.now() 51 | }, options); 52 | } 53 | 54 | // 获取附件信息 55 | function getAttachmentInfo(params, options) { 56 | return request(`https://mooc1.chaoxing.com/ananas/status/${params.objectId}`, 'get', { 57 | k: options.cookie.fid, 58 | flag: 'normal', 59 | _dc: Date.now() 60 | }, { 61 | headers: { 62 | Referer: 'https://mooc1.chaoxing.com/ananas/modules/video/index.html' 63 | }, 64 | ...options 65 | }); 66 | } -------------------------------------------------------------------------------- /modules/chaoxing/chaoxingRequest.js: -------------------------------------------------------------------------------- 1 | const { ajax, asynAjax } = require('../../tools/request'); 2 | 3 | const setCookieParser = require('set-cookie-parser'); 4 | 5 | const { cookieStringify } = require('../../tools/tools'); 6 | 7 | function createRequest(url = '', method = 'get', data = {}, options = {}) { 8 | 9 | var headers = { 10 | 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/102.0.5005.124 Safari/537.36 Edg/102.0.1245.41', 11 | 'accept-language': 'zh-CN' 12 | }; 13 | 14 | if (options.headers instanceof Object) { 15 | Object.assign(headers, options.headers); 16 | } 17 | 18 | if (options.cookie instanceof Object) { 19 | headers.cookie = cookieStringify(options.cookie); 20 | } else if (typeof options.cookie === 'string') headers.cookie = options.cookie; 21 | 22 | if (url.includes('mooc1.chaoxing.com')) { 23 | headers['Host'] = 'mooc1.chaoxing.com'; 24 | headers['Upgrade-Insecure-Requests'] = '1'; 25 | } else if (url.includes('passport2.chaoxing.com')) { 26 | headers['Host'] = 'passport2.chaoxing.com'; 27 | headers['Origin'] = 'https://passport2.chaoxing.com'; 28 | } 29 | 30 | headers['X-Real-IP'] = '223.24.197.23'; 31 | 32 | method = method.toLocaleLowerCase(); 33 | 34 | if (method === 'post') { 35 | headers['content-type'] = 'application/x-www-form-urlencoded'; 36 | headers['X-Requested-With'] = 'XMLHttpRequest'; 37 | } 38 | // console.log(data); 39 | return asynAjax({ 40 | url: url, 41 | method: method, 42 | data: data, 43 | headers: headers 44 | }).then(({ data, xhr }) => { 45 | var set_cookie = xhr.responseHeaders['set-cookie']; 46 | return Promise.resolve({ 47 | data: data, 48 | cookie: set_cookie ? setCookieParser(set_cookie) : [], 49 | _http: xhr 50 | }) 51 | }).catch(err => Promise.reject(err)); 52 | } 53 | 54 | module.exports = createRequest; -------------------------------------------------------------------------------- /modules/chaoxing/chaoxingRoute.js: -------------------------------------------------------------------------------- 1 | const route = { 2 | // 获取课程 3 | course: require('./api/course'), 4 | // 获取课程列表项 5 | subject: require('./api/courseList'), 6 | // 获取附件任务信息 7 | attachment: require('./api/attachment'), 8 | // 保存任务状态 9 | savestatus: require('./api/saveStatus'), 10 | // 登陆 11 | login: require('./api/login'), 12 | // 自动完成 13 | auto: require('./api/automatic') 14 | } 15 | 16 | function setCookie(cookies) { 17 | cookies.forEach((item) => { 18 | var { name, value, ...options } = item; 19 | if (options['expires']) { 20 | options['expires'] = new Date(options['expires']); 21 | } 22 | 23 | if (options['maxAge']) { 24 | options['maxAge'] = options['maxAge'] * 1000; 25 | } 26 | 27 | if (options['domain']) { 28 | delete options['domain']; 29 | } 30 | this.cookie(name, value, options); 31 | }); 32 | } 33 | 34 | module.exports = async (req, res) => { 35 | const program = req.path.replace(/^\//, ''); 36 | 37 | var cx = route[program] 38 | if (!cx) { 39 | return res.json({ 40 | code: 400, 41 | msg: 'error' 42 | }) 43 | } 44 | 45 | var { cookies } = req; 46 | 47 | // 服务端不做任何回话状态保存,只是做了一个简单的cookie判断 48 | if ((!cookies['UID'] || !cookies['fid']) && req.path !== '/login') { 49 | return res.json({ 50 | code: 400, 51 | msg: '请先进行登陆' 52 | }) 53 | } 54 | 55 | try { 56 | var result = await cx(req.query, { cookie: req.cookies }) 57 | } catch (err) { 58 | // console.log(err); 59 | return res.json({ 60 | code: 500, 61 | msg: '服务器内部错误' 62 | }) 63 | } 64 | 65 | if (!result) { 66 | result = {}; 67 | } 68 | 69 | if (result['_http'] && result['_http']['requestURL']) { 70 | delete result._http; 71 | } 72 | 73 | if (result['cookie']) { 74 | setCookie.call(res, result['cookie']); 75 | delete result['cookie']; 76 | } 77 | 78 | if (typeof result === 'string') { 79 | res.send(result); 80 | } else { 81 | res.json(Object.assign(result, { code: result.code || 200 })); 82 | 83 | } 84 | 85 | 86 | } -------------------------------------------------------------------------------- /modules/chaoxing/crypto.js: -------------------------------------------------------------------------------- 1 | const CryptoJS = require('crypto-js'); 2 | 3 | function encrypt(message, key) { 4 | var keyHex = CryptoJS.enc.Utf8.parse(key); 5 | var encrypted = CryptoJS.DES.encrypt(message, keyHex, { 6 | mode: CryptoJS.mode.ECB, 7 | padding: CryptoJS.pad.Pkcs7 8 | }); 9 | return encrypted.ciphertext.toString(); 10 | } 11 | 12 | function decrypt(ciphertext, key) { 13 | 14 | var keyHex = CryptoJS.enc.Utf8.parse(key); 15 | var decrypted = CryptoJS.DES.decrypt({ 16 | ciphertext: CryptoJS.enc.Hex.parse(ciphertext) 17 | }, keyHex, { 18 | mode: CryptoJS.mode.ECB, 19 | padding: CryptoJS.pad.Pkcs7 20 | }); 21 | return decrypted.toString(CryptoJS.enc.Utf8); 22 | } 23 | 24 | module.exports = { 25 | encrypt, 26 | decrypt 27 | } -------------------------------------------------------------------------------- /modules/lemonSchool/autoPlay.js: -------------------------------------------------------------------------------- 1 | const { User } = require('../../mongo/user'); 2 | 3 | const { route, deURI } = require('./lemonSchool'); 4 | 5 | const { semester, subject, subjectitem, play } = route; 6 | 7 | // 从一个数组对象里面提取指定的属性 8 | function filterData(data) { 9 | var arr = []; 10 | 11 | for (let i = 0; i < this.length; i++) { 12 | var obj = {}; 13 | Object.keys(this[i]).forEach(value => { 14 | for (let k in data) { 15 | if (k === value) { 16 | obj[data[k]] = this[i][value]; 17 | break; 18 | } 19 | } 20 | }); 21 | 22 | if (Object.keys(obj).length > 0) { 23 | arr.push(obj); 24 | } 25 | } 26 | 27 | return arr; 28 | } 29 | 30 | Array.prototype.filterData = filterData; 31 | 32 | // 参数别乱传,懒得写判断 33 | async function processing(params = {}, options = {}) { 34 | 35 | var { program, data } = params, msg = params['msg'] || '获取某个信息异常'; 36 | 37 | try { 38 | var result = await program(data || {}, options); 39 | if (result['code'] === 1000) { 40 | return result['data']; 41 | } else { 42 | console.log(msg); 43 | console.log(result); 44 | return []; 45 | } 46 | } catch (err) { 47 | console.log(err); 48 | console.log(msg); 49 | return []; 50 | } 51 | 52 | } 53 | 54 | class Auto { 55 | constructor(params, callback) { 56 | this.user = params.user || {}; 57 | this.options = params.options || {}; 58 | this.cookie = deURI(this.options.cookie); 59 | this.test = {}; 60 | this.callback = callback; 61 | this.subjectItem = 0; 62 | } 63 | 64 | // 获取所有学期 65 | async getAllSemester() { 66 | var result = await processing({ 67 | program: semester, 68 | data: '', 69 | msg: '获取学期失败' 70 | }, this.options); 71 | 72 | return result.filterData({ termCode: 'termId', term: 'term', isCurrentTerm: 'currentTerm' }); 73 | } 74 | 75 | // 获取学期所有课程 76 | async getAllSubject(termId) { 77 | var result = await processing({ 78 | program: subject, 79 | data: { 80 | termId: termId 81 | }, 82 | msg: `获取学期${termId}课程失败` 83 | }, this.options); 84 | 85 | return result['courseInfoList'].filterData({ courseName: 'courseName', courseId: 'course_id' }).filter(value => value['course_id'] > 0); 86 | } 87 | 88 | // 获取课程所有没有观看完成项 89 | async getAllSubjectItem(course_id) { 90 | var result = await processing({ 91 | program: subjectitem, 92 | data: { 93 | course_id: course_id 94 | }, 95 | msg: `获取课程${course_id}项失败` 96 | }, this.options); 97 | return result['listCourseLesson'] && result['listCourseLesson'].filterData({ 98 | courseId: 'courseId', 99 | chapterName: 'chapterName', 100 | lessonId: 'item_id', 101 | timeLen: 'timeLen', 102 | useEnergyNum: 'useEnergyNum', 103 | lessonName: 'item_name', 104 | courseName: 'courseName', 105 | isFinish: 'isFinish', 106 | isChapter: 'isChapter' 107 | }).filter(value => value['timeLen'] > 0 && !value['isFinish'] && value['isChapter'] != true); 108 | } 109 | 110 | async play(query) { 111 | 112 | try { 113 | var result = await play({ 114 | course_id: query['courseId'], 115 | item_id: query['item_id'], 116 | time: query['timeLen'] 117 | }, this.options); 118 | } catch (err) { 119 | console.log(err); 120 | var msg = `刷取视频${query['item_id']}失败,课程ID:${query['courseId']}`; 121 | console.log(msg); 122 | return { code: 500, message: msg }; 123 | } 124 | 125 | return result; 126 | } 127 | 128 | // 刷取课程 129 | async autoPlay(query) { 130 | 131 | var { course_id, time } = query; 132 | 133 | if (!course_id) return; 134 | 135 | var result = await this.getAllSubjectItem(course_id); 136 | 137 | if (!result || result.length === 0) return this.total(); 138 | 139 | var rand = ('timer_' + Math.random() * 30).replace('.', ''); 140 | 141 | this.test[rand] = {}; 142 | // 全部课程项Array 143 | this.test[rand]['subjectItem'] = result; 144 | // 执行的索引 145 | this.test[rand]['index'] = 0; 146 | 147 | // 延时器执行时间 默认5秒 148 | this.test[rand]['time'] = time || 5000; 149 | 150 | // 用来关闭延时器的,(现在好像没有什么用了); 151 | this.test[rand]['timers'] = true; 152 | 153 | this.test[rand]['course_id'] = course_id; 154 | 155 | // 其实也可以传一个对象进去操作的,懒得改了 156 | this.timer(rand); 157 | 158 | return result; 159 | 160 | } 161 | 162 | // 记录课程项播放进度 163 | async timer(name) { 164 | 165 | const { subjectItem, index, time } = this.test[name]; 166 | 167 | const { courseName, item_name, courseId, item_id } = subjectItem[index]; 168 | 169 | const msg = `课程${courseName} => ${item_name}项`; 170 | const item_init = `[课程ID:${courseId} => 项ID:${item_id}]`; 171 | console.log(`正在刷取${msg}`); 172 | 173 | var result = await this.play(subjectItem[index], name); 174 | 175 | if (result['code'] == 1000) { 176 | console.log(`${msg},刷取成功 => [message:${result['message']}]${item_init}`); 177 | } else { 178 | console.log(`${msg},刷取失败 => [message:${result['message']}]${item_init}`); 179 | console.log(`${msg},刷取失败 => 正在尝试重新刷取.....`); 180 | this.test[name].index--; 181 | } 182 | 183 | // console.log(res); 184 | 185 | this.test[name].index++; 186 | 187 | // 记录某一课程刷取完毕 188 | if (this.test[name].index >= subjectItem.length) { 189 | console.log(`课程${courseName}刷取完毕!`); 190 | this.test[name].timers = false; 191 | delete this.test[name]; 192 | this.total(); 193 | return; 194 | } 195 | 196 | this.test[name].timers && setTimeout(this.timer.bind(this, name), time); 197 | } 198 | 199 | // 记录课程是否全部刷取完毕 200 | total() { 201 | this.subjectItem++; 202 | if (this.subjectItem >= this.subjectTotal) { 203 | this.callback && this.callback(); 204 | } 205 | } 206 | 207 | // 快速完成 一个学期的所有课程 208 | async fast(term) { 209 | 210 | // term 刷取的学期 默认刷取当前学期 211 | if (!term) { 212 | term = await this.getAllSemester(), term = Array.isArray(term) && term.find(value => value['currentTerm']), term = term && term['termId']; 213 | if (!term) return; 214 | } 215 | 216 | var result = await this.getAllSubject(term); 217 | 218 | this.subjectTotal = result.length; 219 | 220 | result.forEach((item, index) => { 221 | // { courseName: '中国传统文化', course_id: 102129 } 222 | this.autoPlay({ course_id: item['course_id'], time: 5000 * index }); 223 | }); 224 | 225 | } 226 | 227 | } 228 | 229 | // 刷取的队列,防止多次提交造成服务器压力大。 230 | var queue = {}; 231 | 232 | async function autoPlay(query, options) { 233 | 234 | var { user: zrUser, term } = query || {}; 235 | 236 | var user = await User.findOne({ user: zrUser }); 237 | 238 | if (!user) return { code: 201, msg: '请先进行登陆!' } 239 | 240 | if (queue[zrUser]) { 241 | return { code: 400, msg: '当前账号正在刷取中,请勿多次提交!' } 242 | } else { queue[zrUser] = zrUser } 243 | 244 | var result = new Auto({ 245 | "user": user, 246 | "options": options 247 | }, function () { 248 | // 利用闭包操作,成功后删除已经刷取完毕的账号 249 | console.log(`账号:[${zrUser}]课程刷取完毕!`); 250 | delete queue[zrUser]; 251 | }); 252 | result.fast(term); 253 | 254 | return { 255 | code: 200, 256 | msg: '提交成功', 257 | queue: queue 258 | } 259 | 260 | } 261 | 262 | module.exports = autoPlay; -------------------------------------------------------------------------------- /modules/lemonSchool/crypto.js: -------------------------------------------------------------------------------- 1 | const CryptoJS = require('crypto-js'); 2 | 3 | function k1() { 4 | return "NDY0NQ==" 5 | } 6 | 7 | function Encrypt(r) { 8 | var t = k2() + k4() + k1() + k3(), 9 | e = i2() + i1(), 10 | n = Base64.decode(t), 11 | o = Base64.decode(e), 12 | a = CryptoJS.enc.Latin1.parse(n), 13 | o = CryptoJS.enc.Latin1.parse(o); 14 | "string" != typeof r && (r = JSON.stringify(r)); 15 | var c = CryptoJS.enc.Utf8.parse(r); 16 | return CryptoJS.AES.encrypt(c, a, { 17 | iv: o, 18 | mode: CryptoJS.mode.CBC, 19 | padding: CryptoJS.pad.Pkcs7 20 | }).toString() 21 | } 22 | 23 | function k2() { 24 | return "NTE2" 25 | } 26 | 27 | function k3() { 28 | return "OTYzMg==" 29 | } 30 | 31 | function i2() { 32 | return "ODY1NTYyNDU0Mw==" 33 | } 34 | 35 | function Decrypt(r) { 36 | var t = k2() + k4() + k1() + k3(), 37 | e = i2() + i1(), 38 | n = Base64.decode(t), 39 | o = Base64.decode(e), 40 | a = CryptoJS.enc.Latin1.parse(n), 41 | o = CryptoJS.enc.Latin1.parse(o), 42 | c = r.replace("\n", "").replace("\r", "").replace(" ", ""), 43 | i = CryptoJS.AES.decrypt(c, a, { 44 | iv: o, 45 | padding: CryptoJS.pad.Pkcs7 46 | }); 47 | return CryptoJS.enc.Utf8.stringify(i).toString() 48 | } 49 | 50 | function k4() { 51 | return "NTMyNTk=" 52 | } 53 | 54 | function i1() { 55 | return "OTU5MjMz" 56 | } 57 | var Base64 = { 58 | _keyStr: "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=", 59 | encode: function(r) { 60 | var t, e, n, o, a, c, i, d = "", 61 | C = 0; 62 | for (r = Base64._utf8_encode(r); C < r.length;) 63 | o = (t = r.charCodeAt(C++)) >> 2, 64 | a = (3 & t) << 4 | (e = r.charCodeAt(C++)) >> 4, 65 | c = (15 & e) << 2 | (n = r.charCodeAt(C++)) >> 6, 66 | i = 63 & n, 67 | isNaN(e) ? c = i = 64 : isNaN(n) && (i = 64), 68 | d = d + this._keyStr.charAt(o) + this._keyStr.charAt(a) + this._keyStr.charAt(c) + this._keyStr.charAt(i); 69 | return d 70 | }, 71 | decode: function(r) { 72 | var t, e, n, o, a, c, i = "", 73 | d = 0; 74 | for (r = r.replace(/[^A-Za-z0-9\+\/\=]/g, ""); d < r.length;) 75 | t = this._keyStr.indexOf(r.charAt(d++)) << 2 | (o = this._keyStr.indexOf(r.charAt(d++))) >> 4, 76 | e = (15 & o) << 4 | (a = this._keyStr.indexOf(r.charAt(d++))) >> 2, 77 | n = (3 & a) << 6 | (c = this._keyStr.indexOf(r.charAt(d++))), 78 | i += String.fromCharCode(t), 79 | 64 != a && (i += String.fromCharCode(e)), 80 | 64 != c && (i += String.fromCharCode(n)); 81 | return i = Base64._utf8_decode(i) 82 | }, 83 | _utf8_encode: function(r) { 84 | r = r.replace(/\r\n/g, "\n"); 85 | for (var t = "", e = 0; e < r.length; e++) { 86 | var n = r.charCodeAt(e); 87 | n < 128 ? t += String.fromCharCode(n) : n > 127 && n < 2048 ? (t += String.fromCharCode(n >> 6 | 192), 88 | t += String.fromCharCode(63 & n | 128)) : (t += String.fromCharCode(n >> 12 | 224), 89 | t += String.fromCharCode(n >> 6 & 63 | 128), 90 | t += String.fromCharCode(63 & n | 128)) 91 | } 92 | return t 93 | }, 94 | _utf8_decode: function(r) { 95 | for (var t = "", e = 0, n = c1 = c2 = 0; e < r.length;) 96 | (n = r.charCodeAt(e)) < 128 ? (t += String.fromCharCode(n), 97 | e++) : n > 191 && n < 224 ? (c2 = r.charCodeAt(e + 1), 98 | t += String.fromCharCode((31 & n) << 6 | 63 & c2), 99 | e += 2) : (c2 = r.charCodeAt(e + 1), 100 | c3 = r.charCodeAt(e + 2), 101 | t += String.fromCharCode((15 & n) << 12 | (63 & c2) << 6 | 63 & c3), 102 | e += 3); 103 | return t 104 | } 105 | }; 106 | 107 | 108 | function encrypt(obj) { 109 | var cryptos = {} 110 | 111 | if (!obj || !(obj instanceof Object)) return cryptos; 112 | 113 | for (var k in obj) { 114 | cryptos[k] = encodeURIComponent(Encrypt(obj[k])); 115 | } 116 | 117 | return cryptos; 118 | } 119 | 120 | function decrypt(str) { 121 | try { 122 | return JSON.parse(Decrypt(str)); 123 | } catch (err) {} 124 | } 125 | 126 | module.exports = { 127 | encrypt, 128 | decrypt, 129 | Encrypt 130 | } -------------------------------------------------------------------------------- /modules/lemonSchool/lemonRequest.js: -------------------------------------------------------------------------------- 1 | const { ajax } = require('../../tools/request'); 2 | 3 | const setCookie = require('set-cookie-parser'); 4 | 5 | // 加解密 6 | const { encrypt, decrypt, Encrypt } = require('./crypto'); 7 | 8 | function createRequest(url = '', method = 'get', data = {}, options) { 9 | var options = options || {}, 10 | cookie = options['cookie'], 11 | headers = { 12 | 'Proxy-Connection': 'keep-alive', 13 | 'User-Agent': 'Mozilla/5.0 (Windows NT 6.1; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36' 14 | }; 15 | 16 | // 附加请求头 17 | if (options['headers'] && options['headers'] instanceof Object) { 18 | for (var k in options['headers']) { 19 | headers[k] = options['headers'][k]; 20 | } 21 | } 22 | 23 | // console.log(data); 24 | 25 | // 参数是否需要加密 默认:true 26 | if (!options['noCrypto']) { 27 | data = encrypt(data); 28 | } 29 | 30 | 31 | 32 | // Cookie 33 | if (cookie instanceof Object) { 34 | headers['cookie'] = Object.keys(cookie).map((value) => 35 | cookie[value] && encodeURIComponent(value) + '=' + encodeURIComponent(cookie[value]) 36 | ).join(';'); 37 | 38 | } else if (cookie) headers['cookie'] = cookie; 39 | 40 | 41 | method = method.toLowerCase(); 42 | 43 | const urlInfo = new URL(url); 44 | 45 | headers['Host'] = urlInfo.host; 46 | headers['Origin'] = urlInfo.origin; 47 | 48 | if (method === 'post') { 49 | headers['Content-Type'] = 'application/x-www-form-urlencoded; charset=UTF-8'; 50 | headers['X-Requested-With'] = 'XMLHttpRequest' 51 | } 52 | if (method === 'get') { 53 | headers['Upgrade-Insecure-Requests'] = '1' 54 | } 55 | 56 | // console.log(headers); 57 | // console.log(url); 58 | 59 | return new Promise(function (resolve, reject) { 60 | ajax({ 61 | url: url, 62 | method: method, 63 | data: data, 64 | headers: headers, 65 | success: function (response, xhr) { 66 | 67 | var container = {}; 68 | if (response['data']) { 69 | response['data'] = decrypt(response['data']); 70 | } 71 | 72 | response instanceof Object ? container = { ...response } : container['data'] = response; 73 | 74 | // set cookie parse 75 | container['cookie'] = xhr.responseHeaders['set-cookie'] ? setCookie.parse(xhr.responseHeaders['set-cookie'], { 76 | decodeValues: true, // Calls dcodeURIComponent on each value - default: true 77 | map: true, // Return an object instead of an array - default: false 78 | silent: false, // Suppress the warning that is loged when called on a request instead of a response - default: false 79 | }) : {}; 80 | resolve(container); 81 | }, 82 | // http状态码错误 83 | error: function (err, xhr) { 84 | // console.log(xhr); 85 | reject(xhr); 86 | }, 87 | // http解析错误 88 | onerror: function (err) { 89 | reject(err); 90 | } 91 | }); 92 | }); 93 | } 94 | 95 | module.exports = createRequest; -------------------------------------------------------------------------------- /modules/lemonSchool/lemonSchool.js: -------------------------------------------------------------------------------- 1 | const request = require('./lemonRequest'); 2 | 3 | // request (url,method,data,options) 4 | 5 | const queryString = require('querystring'); 6 | 7 | const { deURI, cookieParse, findKey } = require('../../tools/tools'); 8 | 9 | const { createUser } = require('../../mongo/user'); 10 | 11 | // 学习平台登陆 12 | function learningLogin(params, options) { 13 | return request(`${options.urlHost}/login.jsp`, 'post', { 14 | txtLoginName: params['learning_login_name'], 15 | txtPassword: params['password'], 16 | txtSchoolCode: params['school_code'], 17 | txtGradeCode: params['grade_code'] 18 | }, { 19 | headers: { 20 | 'Cache-Control': 'max-age=0' 21 | }, 22 | noCrypto: true 23 | }); 24 | } 25 | 26 | // 使用能量获得课程 (不用使用能量也能完成视频播放,...好像没有什么用) 27 | function useEnerg(query, options) { 28 | 29 | var params = { 30 | 'learning_user_id': query['userId'], // 学习平台id 31 | 'course_id': query['course_id'], // 课程id 32 | 'type_code': 'progress', 33 | 'item_id': query['item_id'] //课程项id 34 | } 35 | 36 | return request(`${options.urlHost}/newApp_use_energy.action?req=saveUseEnergyInfo`, 'post', params, options); 37 | 38 | } 39 | 40 | function checkPath(path, options) { 41 | const prefix = 'full_time_', 42 | userInfo = options.userInfo; 43 | 44 | // 是否全日制 45 | if (userInfo.isQRZ && userInfo.isQRZ != 'false') { 46 | path = '/' + prefix + path.substr(path.indexOf('/') + 1); 47 | } 48 | 49 | return path; 50 | } 51 | 52 | const route = { 53 | // 登陆 54 | login: async function (params, options) { 55 | 56 | var { user, pwd, code } = params || {}; 57 | 58 | if (!params['user'] || !params['pwd']) { 59 | throw { code: 400, msg: '请输入完整' }; 60 | } 61 | 62 | if (options['cookie']['gzcjzyxy_student_COOKIE']) throw { code: 400, msg: '已处于登陆状态!' } 63 | 64 | try { 65 | var url = new URL(options.baseURL), 66 | data = { 67 | login_name: user, 68 | password: pwd, 69 | user_verification_code:'', 70 | snowFlake:Date.now() 71 | }; 72 | 73 | url.searchParams.set('req', 'login'); 74 | 75 | url.pathname = url.pathname + '/login.action'; 76 | 77 | var result = await request(url.toString(), 'post', data); 78 | 79 | // 登陆成功后需要获取cookie 80 | if (result['code'] === 1000 && result['data'].userType === 'student') { 81 | 82 | const query = queryString.stringify({ 83 | req: result.data.isQRZ ? 'doStudentLoginQRZ' : 'doStudentLogin', 84 | debug: true, 85 | login_name: user, 86 | password: pwd 87 | }); 88 | 89 | // nysy_student_COOKIE 90 | var response = await request(`${options.baseURL}_student/login.action?${query}`, 'get', ''); 91 | // 合并 Cookie 92 | result['cookie'] = Object.assign(result.cookie, response.cookie); 93 | 94 | const schollName = url.pathname.split('/')[1], 95 | cookies = result['cookie'], 96 | keyName = schollName + '_student_COOKIE'; 97 | 98 | // 登陆学习平台 99 | var info = cookies[keyName] || findKey(cookies, 'COOKIE'); 100 | 101 | if (info) { 102 | info = deURI(queryString.parse(info.value)); 103 | response = await learningLogin(info, options); 104 | // console.log(response); 105 | } 106 | 107 | // isQRZ 是否全日制 108 | result['cookie'] = Object.assign(result.cookie, response.cookie, { 109 | userInfo: { 110 | name: 'userInfo', 111 | value: queryString.stringify(Object.assign(info, { isQRZ: Boolean(result.data.isQRZ) })), 112 | maxAge: 2592000, 113 | path: '/' 114 | } 115 | }); 116 | 117 | // 保存到数据库 118 | createUser({ 119 | user: user, 120 | password: pwd, 121 | cookie: result['cookie'], 122 | userInit: info, 123 | baseURL: options.baseURL, 124 | urlHost: options.urlHost, 125 | isQRZ: Boolean(result.data.isQRZ) 126 | }); 127 | } 128 | 129 | } catch (err) { 130 | if(err.status===404){ 131 | return { 132 | code:404, 133 | msg:'请求出错误,您选择的学校已经不在柠檬平台服务范围内!' 134 | } 135 | } 136 | throw new Error(err); 137 | } 138 | 139 | return result; 140 | }, 141 | // 102174,102140 142 | // 获取 semester 143 | semester: async function (params, options) { 144 | return request(`${options.baseURL}_student${checkPath('/student_learn.action', options)}?req=getTerm`, 'get', '', options); 145 | }, 146 | 147 | // semester subject 学期科目 148 | subject: function (params, options) { 149 | return request(`${options.baseURL}_student${checkPath('/student_learn.action', options)}?req=getStudentLearnInfo`, 'post', { 150 | term_code: params['termId'] 151 | }, options); 152 | }, 153 | 154 | // subjectitem 科目项 155 | subjectitem: function (param, options) { 156 | return request(`${options.urlHost}/newApp_learn_course.action?req=getCourseScormItemList`, 'post', { 157 | course_id: param['course_id'] 158 | }, options); 159 | }, 160 | 161 | // 获取省份 162 | portal: async function (p) { 163 | return request('http://www.wencaischool.net/openlearning/portal/json/province.json', 'get'); 164 | }, 165 | 166 | // 学校列表 167 | schoollist: function (params) { 168 | const urlHost = params.urlHost || 'http://learning.wencaischool.net/openlearning'; 169 | delete params.urlHost; 170 | return request(`${urlHost}/school_info.action`, 'post', params); 171 | }, 172 | 173 | // 完成视频播放 174 | play: async function (params, options) { 175 | 176 | var { time } = params || {}, time = time || 999; 177 | 178 | var info = options.userInfo; 179 | 180 | var data = { 181 | user_id: info['learning_user_id'], //学习平台账号id 182 | course_id: params['course_id'], //课程id 183 | time: time, //离开时间 184 | item_id: params['item_id'], //课程项id 185 | view_time: time, 186 | last_view_time: time, 187 | video_length: time, //视频总时间 188 | learning_user_id: info['user_id'] 189 | } 190 | 191 | // 使用能量 192 | var result = await useEnerg({ 193 | 'userId': info['learning_user_id'], // 学习平台id 194 | 'course_id': params['course_id'], // 科目id 195 | 'type_code': 'progress', 196 | 'item_id': params['item_id'] //科目项id 197 | }, options); 198 | // console.log(result); 199 | return request(`${options.urlHost}/learning.action?req=submitScormAndHistorySave`, 'post', data, options); 200 | 201 | } 202 | } 203 | 204 | module.exports = { 205 | route: route, 206 | learningLogin: learningLogin, 207 | useEnerg: useEnerg, 208 | cookieParse, 209 | deURI 210 | }; -------------------------------------------------------------------------------- /modules/lemonSchool/lemonSchoolRoute.js: -------------------------------------------------------------------------------- 1 | // 路由 2 | const lemonSchool = require('./lemonSchool'); 3 | 4 | const autoplay = require('./autoPlay'); 5 | 6 | const cookie = require('cookie'); 7 | 8 | const queryString = require('querystring'); 9 | 10 | module.exports = async (req, res) => { 11 | const program = req.path.replace(/^\//, ''); 12 | // console.log(program); 13 | 14 | var route = program === 'autoplay' ? autoplay : lemonSchool['route'][program]; 15 | 16 | if (!route) { 17 | return res.json({ 18 | code: 401, 19 | msg: 'err' 20 | }); 21 | } 22 | 23 | if (req.headers.baseurl) { 24 | req.cookies.baseURL = req.headers.baseurl; 25 | } 26 | 27 | if (req.headers.urlhost) { 28 | req.cookies.urlHost = req.headers.urlhost; 29 | } 30 | 31 | try { 32 | const baseURL = (req.cookies.baseURL && req.cookies.baseURL.replace(/\/console\/*/i, '')) || 'http://site.wencaischool.net/gzcjzyxy', 33 | urlHost = req.cookies.urlHost || 'http://learning.wencaischool.net', 34 | userInfo = req.cookies.userInfo; 35 | 36 | delete req.cookies.baseURL; 37 | delete req.cookies.urlHost; 38 | delete req.cookies.userInfo; 39 | 40 | var result = route && await route({ 41 | ...req.query 42 | }, { 43 | "cookie": Object.keys(req.cookies).length === 0 ? '' : req.cookies, 44 | "baseURL": baseURL, 45 | "urlHost": urlHost, 46 | "userInfo": queryString.parse(userInfo) 47 | }); 48 | } catch (err) { 49 | console.log(err); 50 | return res.send(err); 51 | } 52 | 53 | // console.log(result); 54 | if (result['cookie']) { 55 | res.setHeader('Set-Cookie', setCookie(result['cookie'])); 56 | delete result['cookie']; 57 | } 58 | 59 | if (typeof result.data === 'string') { 60 | res.send(result.data); 61 | } else { 62 | res.json(result); 63 | } 64 | } 65 | 66 | function setCookie(objs) { 67 | 68 | var str = []; 69 | 70 | for (var k in objs) { 71 | var { name, value, ...options } = objs[k]; 72 | if (options['expires']) { 73 | options['expires'] = new Date(options['expires']); 74 | } 75 | 76 | if (options['path'] && options['path'] !== '/') { 77 | options['path'] = '/'; 78 | } 79 | 80 | if (options['domain']) { 81 | delete options['domain']; 82 | } 83 | str.push(cookie.serialize(name, value, options)); 84 | } 85 | 86 | return str; 87 | } -------------------------------------------------------------------------------- /mongo/chaoxing.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | 3 | const ChaoXingSchema = new mongoose.Schema({ 4 | user: String, 5 | password: String, 6 | cookie: String, 7 | userInit: Object 8 | }); 9 | 10 | const ChaoXing = mongoose.model('ChaoXing', ChaoXingSchema, 'chaoxing'); 11 | 12 | async function createUser(docs) { 13 | 14 | const query = { user: docs.user }; 15 | 16 | try { 17 | const isExist = await ChaoXing.findOne(query); 18 | 19 | if (isExist) { 20 | return await ChaoXing.updateOne(query, docs); 21 | } else { 22 | return await ChaoXing.create(docs); 23 | } 24 | } catch (err) { 25 | throw new Error(err); 26 | } 27 | } 28 | 29 | module.exports = { 30 | createUser, 31 | ChaoXing 32 | } -------------------------------------------------------------------------------- /mongo/mongodb.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | 3 | mongoose.connect('mongodb://localhost/AutoStudy', { useNewUrlParser: true, useUnifiedTopology: true }) 4 | .then(() => { 5 | console.log('数据库链接成功 连接地址:mongodb://localhost/AutoStudy'); 6 | }).catch(err => { 7 | console.log(err); 8 | console.log('数据库链接失败'); 9 | }); -------------------------------------------------------------------------------- /mongo/user.js: -------------------------------------------------------------------------------- 1 | const mongoose = require('mongoose'); 2 | 3 | const userMod = new mongoose.Schema({ 4 | user: String, 5 | password: String, 6 | cookie: Object, 7 | userInit: Object, 8 | urlHost: String, 9 | baseURL: String, 10 | isQRZ: Boolean 11 | }); 12 | 13 | const User = mongoose.model('User', userMod, 'user'); 14 | 15 | async function createUser(createParam) { 16 | 17 | var model = User; 18 | 19 | try { 20 | var result = await model.findOne({ user: createParam['user'] }); 21 | 22 | if (result) { 23 | return await model.updateOne({ 24 | user: createParam['user'] 25 | }, createParam); 26 | } else { 27 | return await model.create(createParam); 28 | } 29 | } catch (err) { 30 | console.log(err); 31 | console.log('保存用户失败' + createParam['user']); 32 | throw new Error(err); 33 | } 34 | 35 | } 36 | 37 | module.exports = { createUser, User }; -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "AutoStudy", 3 | "version": "1.1.0", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "@types/bson": { 8 | "version": "4.0.3", 9 | "resolved": "https://registry.npm.taobao.org/@types/bson/download/@types/bson-4.0.3.tgz?cache=0&sync_timestamp=1613378287809&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fbson%2Fdownload%2F%40types%2Fbson-4.0.3.tgz", 10 | "integrity": "sha1-MIidL/3mJiq744ZZNkxjFFSZn78=", 11 | "requires": { 12 | "@types/node": "*" 13 | } 14 | }, 15 | "@types/mongodb": { 16 | "version": "3.6.12", 17 | "resolved": "https://registry.npm.taobao.org/@types/mongodb/download/@types/mongodb-3.6.12.tgz?cache=0&sync_timestamp=1617618714144&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fmongodb%2Fdownload%2F%40types%2Fmongodb-3.6.12.tgz", 18 | "integrity": "sha1-cnlg0081BU0vLOaJCeFglPdC2TU=", 19 | "requires": { 20 | "@types/bson": "*", 21 | "@types/node": "*" 22 | } 23 | }, 24 | "@types/node": { 25 | "version": "14.14.37", 26 | "resolved": "https://registry.npm.taobao.org/@types/node/download/@types/node-14.14.37.tgz?cache=0&sync_timestamp=1616803582959&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2F%40types%2Fnode%2Fdownload%2F%40types%2Fnode-14.14.37.tgz", 27 | "integrity": "sha1-o92NpOuEqZbDbjMd+Y2Cq9drUW4=" 28 | }, 29 | "accepts": { 30 | "version": "1.3.7", 31 | "resolved": "https://registry.npm.taobao.org/accepts/download/accepts-1.3.7.tgz", 32 | "integrity": "sha1-UxvHJlF6OytB+FACHGzBXqq1B80=", 33 | "requires": { 34 | "mime-types": "~2.1.24", 35 | "negotiator": "0.6.2" 36 | } 37 | }, 38 | "array-flatten": { 39 | "version": "1.1.1", 40 | "resolved": "https://registry.npm.taobao.org/array-flatten/download/array-flatten-1.1.1.tgz", 41 | "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" 42 | }, 43 | "bl": { 44 | "version": "2.2.1", 45 | "resolved": "https://registry.npm.taobao.org/bl/download/bl-2.2.1.tgz?cache=0&sync_timestamp=1617381897308&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbl%2Fdownload%2Fbl-2.2.1.tgz", 46 | "integrity": "sha1-jBGntzBlXF1WiYzchxIk9A/ZAdU=", 47 | "requires": { 48 | "readable-stream": "^2.3.5", 49 | "safe-buffer": "^5.1.1" 50 | } 51 | }, 52 | "bluebird": { 53 | "version": "3.5.1", 54 | "resolved": "https://registry.npm.taobao.org/bluebird/download/bluebird-3.5.1.tgz", 55 | "integrity": "sha1-2VUfnemPH82h5oPRfukaBgLuLrk=" 56 | }, 57 | "body-parser": { 58 | "version": "1.19.0", 59 | "resolved": "https://registry.npm.taobao.org/body-parser/download/body-parser-1.19.0.tgz", 60 | "integrity": "sha1-lrJwnlfJxOCab9Zqj9l5hE9p8Io=", 61 | "requires": { 62 | "bytes": "3.1.0", 63 | "content-type": "~1.0.4", 64 | "debug": "2.6.9", 65 | "depd": "~1.1.2", 66 | "http-errors": "1.7.2", 67 | "iconv-lite": "0.4.24", 68 | "on-finished": "~2.3.0", 69 | "qs": "6.7.0", 70 | "raw-body": "2.4.0", 71 | "type-is": "~1.6.17" 72 | } 73 | }, 74 | "boolbase": { 75 | "version": "1.0.0", 76 | "resolved": "https://registry.npm.taobao.org/boolbase/download/boolbase-1.0.0.tgz", 77 | "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24=" 78 | }, 79 | "bson": { 80 | "version": "1.1.6", 81 | "resolved": "https://registry.npm.taobao.org/bson/download/bson-1.1.6.tgz?cache=0&sync_timestamp=1617726652820&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbson%2Fdownload%2Fbson-1.1.6.tgz", 82 | "integrity": "sha1-+4Gb6aYM1nfghTruTKcSp4XWYYo=" 83 | }, 84 | "bytes": { 85 | "version": "3.1.0", 86 | "resolved": "https://registry.npm.taobao.org/bytes/download/bytes-3.1.0.tgz?cache=0&sync_timestamp=1589682741197&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fbytes%2Fdownload%2Fbytes-3.1.0.tgz", 87 | "integrity": "sha1-9s95M6Ng4FiPqf3oVlHNx/gF0fY=" 88 | }, 89 | "cheerio": { 90 | "version": "1.0.0-rc.9", 91 | "resolved": "https://registry.nlark.com/cheerio/download/cheerio-1.0.0-rc.9.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fcheerio%2Fdownload%2Fcheerio-1.0.0-rc.9.tgz", 92 | "integrity": "sha1-o65rfOevgGdTAv+Db2KOfLeGpn8=", 93 | "requires": { 94 | "cheerio-select": "^1.4.0", 95 | "dom-serializer": "^1.3.1", 96 | "domhandler": "^4.2.0", 97 | "htmlparser2": "^6.1.0", 98 | "parse5": "^6.0.1", 99 | "parse5-htmlparser2-tree-adapter": "^6.0.1", 100 | "tslib": "^2.2.0" 101 | } 102 | }, 103 | "cheerio-select": { 104 | "version": "1.4.0", 105 | "resolved": "https://registry.npm.taobao.org/cheerio-select/download/cheerio-select-1.4.0.tgz?cache=0&sync_timestamp=1618573118408&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcheerio-select%2Fdownload%2Fcheerio-select-1.4.0.tgz", 106 | "integrity": "sha1-OhbyHjei7w8hHW0apO/wVLsizck=", 107 | "requires": { 108 | "css-select": "^4.1.2", 109 | "css-what": "^5.0.0", 110 | "domelementtype": "^2.2.0", 111 | "domhandler": "^4.2.0", 112 | "domutils": "^2.6.0" 113 | } 114 | }, 115 | "content-disposition": { 116 | "version": "0.5.3", 117 | "resolved": "https://registry.npm.taobao.org/content-disposition/download/content-disposition-0.5.3.tgz", 118 | "integrity": "sha1-4TDK9+cnkIfFYWwgB9BIVpiYT70=", 119 | "requires": { 120 | "safe-buffer": "5.1.2" 121 | } 122 | }, 123 | "content-type": { 124 | "version": "1.0.4", 125 | "resolved": "https://registry.npm.taobao.org/content-type/download/content-type-1.0.4.tgz", 126 | "integrity": "sha1-4TjMdeBAxyexlm/l5fjJruJW/js=" 127 | }, 128 | "cookie": { 129 | "version": "0.5.0", 130 | "resolved": "https://registry.npmmirror.com/cookie/-/cookie-0.5.0.tgz", 131 | "integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==" 132 | }, 133 | "cookie-parser": { 134 | "version": "1.4.5", 135 | "resolved": "https://registry.npm.taobao.org/cookie-parser/download/cookie-parser-1.4.5.tgz", 136 | "integrity": "sha1-PlctS3wMgPnGHa9gTkM2gxtdHUk=", 137 | "requires": { 138 | "cookie": "0.4.0", 139 | "cookie-signature": "1.0.6" 140 | }, 141 | "dependencies": { 142 | "cookie": { 143 | "version": "0.4.0", 144 | "resolved": "https://registry.npmmirror.com/cookie/-/cookie-0.4.0.tgz", 145 | "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" 146 | } 147 | } 148 | }, 149 | "cookie-signature": { 150 | "version": "1.0.6", 151 | "resolved": "https://registry.npm.taobao.org/cookie-signature/download/cookie-signature-1.0.6.tgz", 152 | "integrity": "sha1-4wOogrNCzD7oylE6eZmXNNqzriw=" 153 | }, 154 | "core-util-is": { 155 | "version": "1.0.2", 156 | "resolved": "https://registry.npm.taobao.org/core-util-is/download/core-util-is-1.0.2.tgz", 157 | "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" 158 | }, 159 | "crypto-js": { 160 | "version": "4.0.0", 161 | "resolved": "https://registry.npm.taobao.org/crypto-js/download/crypto-js-4.0.0.tgz", 162 | "integrity": "sha1-KQSrJnep0EKFai6i74DekuSjbcw=" 163 | }, 164 | "css-select": { 165 | "version": "4.1.2", 166 | "resolved": "https://registry.npm.taobao.org/css-select/download/css-select-4.1.2.tgz?cache=0&sync_timestamp=1618566178339&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcss-select%2Fdownload%2Fcss-select-4.1.2.tgz", 167 | "integrity": "sha1-i1K2cU7TqA2CIeyXHFQ/OxJlMoY=", 168 | "requires": { 169 | "boolbase": "^1.0.0", 170 | "css-what": "^5.0.0", 171 | "domhandler": "^4.2.0", 172 | "domutils": "^2.6.0", 173 | "nth-check": "^2.0.0" 174 | } 175 | }, 176 | "css-what": { 177 | "version": "5.0.0", 178 | "resolved": "https://registry.npm.taobao.org/css-what/download/css-what-5.0.0.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fcss-what%2Fdownload%2Fcss-what-5.0.0.tgz", 179 | "integrity": "sha1-8L9Pi6wHWCciNGqyQ/ajW1Es/Ec=" 180 | }, 181 | "debug": { 182 | "version": "2.6.9", 183 | "resolved": "https://registry.npm.taobao.org/debug/download/debug-2.6.9.tgz?cache=0&sync_timestamp=1607566533140&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdebug%2Fdownload%2Fdebug-2.6.9.tgz", 184 | "integrity": "sha1-XRKFFd8TT/Mn6QpMk/Tgd6U2NB8=", 185 | "requires": { 186 | "ms": "2.0.0" 187 | } 188 | }, 189 | "denque": { 190 | "version": "1.5.0", 191 | "resolved": "https://registry.npm.taobao.org/denque/download/denque-1.5.0.tgz?cache=0&sync_timestamp=1609780136269&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdenque%2Fdownload%2Fdenque-1.5.0.tgz", 192 | "integrity": "sha1-dz3gaG/y2Owv+SkUMWpHtzscc94=" 193 | }, 194 | "depd": { 195 | "version": "1.1.2", 196 | "resolved": "https://registry.npm.taobao.org/depd/download/depd-1.1.2.tgz", 197 | "integrity": "sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=" 198 | }, 199 | "destroy": { 200 | "version": "1.0.4", 201 | "resolved": "https://registry.npm.taobao.org/destroy/download/destroy-1.0.4.tgz", 202 | "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" 203 | }, 204 | "dom-serializer": { 205 | "version": "1.3.2", 206 | "resolved": "https://registry.nlark.com/dom-serializer/download/dom-serializer-1.3.2.tgz?cache=0&sync_timestamp=1621256830355&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fdom-serializer%2Fdownload%2Fdom-serializer-1.3.2.tgz", 207 | "integrity": "sha1-YgZDfTLO767HFhgDIwx6ILwbTZE=", 208 | "requires": { 209 | "domelementtype": "^2.0.1", 210 | "domhandler": "^4.2.0", 211 | "entities": "^2.0.0" 212 | } 213 | }, 214 | "domelementtype": { 215 | "version": "2.2.0", 216 | "resolved": "https://registry.npm.taobao.org/domelementtype/download/domelementtype-2.2.0.tgz?cache=0&sync_timestamp=1617298554829&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdomelementtype%2Fdownload%2Fdomelementtype-2.2.0.tgz", 217 | "integrity": "sha1-mgtsJ4LtahxzI9QiZxg9+b2LHVc=" 218 | }, 219 | "domhandler": { 220 | "version": "4.2.0", 221 | "resolved": "https://registry.npm.taobao.org/domhandler/download/domhandler-4.2.0.tgz?cache=0&sync_timestamp=1618563954924&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdomhandler%2Fdownload%2Fdomhandler-4.2.0.tgz", 222 | "integrity": "sha1-+XaKXwNL5gqJonwuTQ9066DYsFk=", 223 | "requires": { 224 | "domelementtype": "^2.2.0" 225 | } 226 | }, 227 | "domutils": { 228 | "version": "2.6.0", 229 | "resolved": "https://registry.npm.taobao.org/domutils/download/domutils-2.6.0.tgz", 230 | "integrity": "sha1-LhXAQYXUP7Fq5wV8t2Qzxu25OLc=", 231 | "requires": { 232 | "dom-serializer": "^1.0.1", 233 | "domelementtype": "^2.2.0", 234 | "domhandler": "^4.2.0" 235 | } 236 | }, 237 | "ee-first": { 238 | "version": "1.1.1", 239 | "resolved": "https://registry.npm.taobao.org/ee-first/download/ee-first-1.1.1.tgz", 240 | "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" 241 | }, 242 | "encodeurl": { 243 | "version": "1.0.2", 244 | "resolved": "https://registry.npm.taobao.org/encodeurl/download/encodeurl-1.0.2.tgz", 245 | "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" 246 | }, 247 | "entities": { 248 | "version": "2.2.0", 249 | "resolved": "https://registry.npm.taobao.org/entities/download/entities-2.2.0.tgz", 250 | "integrity": "sha1-CY3JDruD2N/6CJ1VJWs1HTTE2lU=" 251 | }, 252 | "escape-html": { 253 | "version": "1.0.3", 254 | "resolved": "https://registry.npm.taobao.org/escape-html/download/escape-html-1.0.3.tgz", 255 | "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" 256 | }, 257 | "etag": { 258 | "version": "1.8.1", 259 | "resolved": "https://registry.npm.taobao.org/etag/download/etag-1.8.1.tgz", 260 | "integrity": "sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=" 261 | }, 262 | "express": { 263 | "version": "4.17.1", 264 | "resolved": "https://registry.npm.taobao.org/express/download/express-4.17.1.tgz?cache=0&sync_timestamp=1596722127254&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fexpress%2Fdownload%2Fexpress-4.17.1.tgz", 265 | "integrity": "sha1-RJH8OGBc9R+GKdOcK10Cb5ikwTQ=", 266 | "requires": { 267 | "accepts": "~1.3.7", 268 | "array-flatten": "1.1.1", 269 | "body-parser": "1.19.0", 270 | "content-disposition": "0.5.3", 271 | "content-type": "~1.0.4", 272 | "cookie": "0.4.0", 273 | "cookie-signature": "1.0.6", 274 | "debug": "2.6.9", 275 | "depd": "~1.1.2", 276 | "encodeurl": "~1.0.2", 277 | "escape-html": "~1.0.3", 278 | "etag": "~1.8.1", 279 | "finalhandler": "~1.1.2", 280 | "fresh": "0.5.2", 281 | "merge-descriptors": "1.0.1", 282 | "methods": "~1.1.2", 283 | "on-finished": "~2.3.0", 284 | "parseurl": "~1.3.3", 285 | "path-to-regexp": "0.1.7", 286 | "proxy-addr": "~2.0.5", 287 | "qs": "6.7.0", 288 | "range-parser": "~1.2.1", 289 | "safe-buffer": "5.1.2", 290 | "send": "0.17.1", 291 | "serve-static": "1.14.1", 292 | "setprototypeof": "1.1.1", 293 | "statuses": "~1.5.0", 294 | "type-is": "~1.6.18", 295 | "utils-merge": "1.0.1", 296 | "vary": "~1.1.2" 297 | }, 298 | "dependencies": { 299 | "cookie": { 300 | "version": "0.4.0", 301 | "resolved": "https://registry.npmmirror.com/cookie/-/cookie-0.4.0.tgz", 302 | "integrity": "sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg==" 303 | } 304 | } 305 | }, 306 | "finalhandler": { 307 | "version": "1.1.2", 308 | "resolved": "https://registry.npm.taobao.org/finalhandler/download/finalhandler-1.1.2.tgz", 309 | "integrity": "sha1-t+fQAP/RGTjQ/bBTUG9uur6fWH0=", 310 | "requires": { 311 | "debug": "2.6.9", 312 | "encodeurl": "~1.0.2", 313 | "escape-html": "~1.0.3", 314 | "on-finished": "~2.3.0", 315 | "parseurl": "~1.3.3", 316 | "statuses": "~1.5.0", 317 | "unpipe": "~1.0.0" 318 | } 319 | }, 320 | "forwarded": { 321 | "version": "0.1.2", 322 | "resolved": "https://registry.npm.taobao.org/forwarded/download/forwarded-0.1.2.tgz", 323 | "integrity": "sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ=" 324 | }, 325 | "fresh": { 326 | "version": "0.5.2", 327 | "resolved": "https://registry.npm.taobao.org/fresh/download/fresh-0.5.2.tgz?cache=0&sync_timestamp=1589682752100&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ffresh%2Fdownload%2Ffresh-0.5.2.tgz", 328 | "integrity": "sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=" 329 | }, 330 | "htmlparser2": { 331 | "version": "6.1.0", 332 | "resolved": "https://registry.nlark.com/htmlparser2/download/htmlparser2-6.1.0.tgz?cache=0&sync_timestamp=1618846794076&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fhtmlparser2%2Fdownload%2Fhtmlparser2-6.1.0.tgz", 333 | "integrity": "sha1-xNditsM3GgXb5l6UrkOp+EX7j7c=", 334 | "requires": { 335 | "domelementtype": "^2.0.1", 336 | "domhandler": "^4.0.0", 337 | "domutils": "^2.5.2", 338 | "entities": "^2.0.0" 339 | } 340 | }, 341 | "http-errors": { 342 | "version": "1.7.2", 343 | "resolved": "https://registry.npm.taobao.org/http-errors/download/http-errors-1.7.2.tgz?cache=0&sync_timestamp=1593407858306&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fhttp-errors%2Fdownload%2Fhttp-errors-1.7.2.tgz", 344 | "integrity": "sha1-T1ApzxMjnzEDblsuVSkrz7zIXI8=", 345 | "requires": { 346 | "depd": "~1.1.2", 347 | "inherits": "2.0.3", 348 | "setprototypeof": "1.1.1", 349 | "statuses": ">= 1.5.0 < 2", 350 | "toidentifier": "1.0.0" 351 | } 352 | }, 353 | "iconv-lite": { 354 | "version": "0.4.24", 355 | "resolved": "https://registry.npm.taobao.org/iconv-lite/download/iconv-lite-0.4.24.tgz?cache=0&sync_timestamp=1594184250387&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ficonv-lite%2Fdownload%2Ficonv-lite-0.4.24.tgz", 356 | "integrity": "sha1-ICK0sl+93CHS9SSXSkdKr+czkIs=", 357 | "requires": { 358 | "safer-buffer": ">= 2.1.2 < 3" 359 | } 360 | }, 361 | "inherits": { 362 | "version": "2.0.3", 363 | "resolved": "https://registry.npm.taobao.org/inherits/download/inherits-2.0.3.tgz", 364 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=" 365 | }, 366 | "ipaddr.js": { 367 | "version": "1.9.1", 368 | "resolved": "https://registry.npm.taobao.org/ipaddr.js/download/ipaddr.js-1.9.1.tgz", 369 | "integrity": "sha1-v/OFQ+64mEglB5/zoqjmy9RngbM=" 370 | }, 371 | "isarray": { 372 | "version": "1.0.0", 373 | "resolved": "https://registry.npm.taobao.org/isarray/download/isarray-1.0.0.tgz", 374 | "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" 375 | }, 376 | "kareem": { 377 | "version": "2.3.2", 378 | "resolved": "https://registry.npm.taobao.org/kareem/download/kareem-2.3.2.tgz?cache=0&sync_timestamp=1607443230264&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fkareem%2Fdownload%2Fkareem-2.3.2.tgz", 379 | "integrity": "sha1-eMRQiJSYW404oNwV4ajhEHjyypM=" 380 | }, 381 | "md5-node": { 382 | "version": "1.0.1", 383 | "resolved": "https://registry.npm.taobao.org/md5-node/download/md5-node-1.0.1.tgz", 384 | "integrity": "sha1-DiLQCdRr3JWx08XoyP7dwaXDqog=" 385 | }, 386 | "media-typer": { 387 | "version": "0.3.0", 388 | "resolved": "https://registry.npm.taobao.org/media-typer/download/media-typer-0.3.0.tgz", 389 | "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" 390 | }, 391 | "memory-pager": { 392 | "version": "1.5.0", 393 | "resolved": "https://registry.npm.taobao.org/memory-pager/download/memory-pager-1.5.0.tgz", 394 | "integrity": "sha1-2HUWVdItOEaCdByXLyw9bfo+ZrU=", 395 | "optional": true 396 | }, 397 | "merge-descriptors": { 398 | "version": "1.0.1", 399 | "resolved": "https://registry.npm.taobao.org/merge-descriptors/download/merge-descriptors-1.0.1.tgz", 400 | "integrity": "sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E=" 401 | }, 402 | "methods": { 403 | "version": "1.1.2", 404 | "resolved": "https://registry.npm.taobao.org/methods/download/methods-1.1.2.tgz", 405 | "integrity": "sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=" 406 | }, 407 | "mime": { 408 | "version": "1.6.0", 409 | "resolved": "https://registry.npm.taobao.org/mime/download/mime-1.6.0.tgz", 410 | "integrity": "sha1-Ms2eXGRVO9WNGaVor0Uqz/BJgbE=" 411 | }, 412 | "mime-db": { 413 | "version": "1.47.0", 414 | "resolved": "https://registry.npm.taobao.org/mime-db/download/mime-db-1.47.0.tgz?cache=0&sync_timestamp=1617306166016&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmime-db%2Fdownload%2Fmime-db-1.47.0.tgz", 415 | "integrity": "sha1-jLMT5Zll08Bc+/iYkVomevRqM1w=" 416 | }, 417 | "mime-types": { 418 | "version": "2.1.30", 419 | "resolved": "https://registry.npm.taobao.org/mime-types/download/mime-types-2.1.30.tgz?cache=0&sync_timestamp=1617340124913&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmime-types%2Fdownload%2Fmime-types-2.1.30.tgz", 420 | "integrity": "sha1-bnvotMR5gl+F7WMmaV23P5MF1i0=", 421 | "requires": { 422 | "mime-db": "1.47.0" 423 | } 424 | }, 425 | "mongodb": { 426 | "version": "3.6.5", 427 | "resolved": "https://registry.npm.taobao.org/mongodb/download/mongodb-3.6.5.tgz", 428 | "integrity": "sha1-wn14b9TTyD3BkwJINwfRKp0q7l8=", 429 | "requires": { 430 | "bl": "^2.2.1", 431 | "bson": "^1.1.4", 432 | "denque": "^1.4.1", 433 | "require_optional": "^1.0.1", 434 | "safe-buffer": "^5.1.2", 435 | "saslprep": "^1.0.0" 436 | } 437 | }, 438 | "mongoose": { 439 | "version": "5.12.3", 440 | "resolved": "https://registry.npm.taobao.org/mongoose/download/mongoose-5.12.3.tgz?cache=0&sync_timestamp=1617218246113&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmongoose%2Fdownload%2Fmongoose-5.12.3.tgz", 441 | "integrity": "sha1-5ItM/YmL13n2p3b8DiMr95CsTBo=", 442 | "requires": { 443 | "@types/mongodb": "^3.5.27", 444 | "bson": "^1.1.4", 445 | "kareem": "2.3.2", 446 | "mongodb": "3.6.5", 447 | "mongoose-legacy-pluralize": "1.0.2", 448 | "mpath": "0.8.3", 449 | "mquery": "3.2.5", 450 | "ms": "2.1.2", 451 | "regexp-clone": "1.0.0", 452 | "safe-buffer": "5.2.1", 453 | "sift": "7.0.1", 454 | "sliced": "1.0.1" 455 | }, 456 | "dependencies": { 457 | "ms": { 458 | "version": "2.1.2", 459 | "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.1.2.tgz?cache=0&sync_timestamp=1607433842694&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fms%2Fdownload%2Fms-2.1.2.tgz", 460 | "integrity": "sha1-0J0fNXtEP0kzgqjrPM0YOHKuYAk=" 461 | }, 462 | "safe-buffer": { 463 | "version": "5.2.1", 464 | "resolved": "https://registry.npm.taobao.org/safe-buffer/download/safe-buffer-5.2.1.tgz?cache=0&sync_timestamp=1589682795646&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsafe-buffer%2Fdownload%2Fsafe-buffer-5.2.1.tgz", 465 | "integrity": "sha1-Hq+fqb2x/dTsdfWPnNtOa3gn7sY=" 466 | } 467 | } 468 | }, 469 | "mongoose-legacy-pluralize": { 470 | "version": "1.0.2", 471 | "resolved": "https://registry.npm.taobao.org/mongoose-legacy-pluralize/download/mongoose-legacy-pluralize-1.0.2.tgz", 472 | "integrity": "sha1-O6n5H6UHtRhtOZ+0CFS/8Y+1Y+Q=" 473 | }, 474 | "mpath": { 475 | "version": "0.8.3", 476 | "resolved": "https://registry.npm.taobao.org/mpath/download/mpath-0.8.3.tgz?cache=0&sync_timestamp=1609342111213&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmpath%2Fdownload%2Fmpath-0.8.3.tgz", 477 | "integrity": "sha1-gorA0Yf39CZ0g510khlwl5q73Y8=" 478 | }, 479 | "mquery": { 480 | "version": "3.2.5", 481 | "resolved": "https://registry.npm.taobao.org/mquery/download/mquery-3.2.5.tgz?cache=0&sync_timestamp=1617029851335&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fmquery%2Fdownload%2Fmquery-3.2.5.tgz", 482 | "integrity": "sha1-jyMFYy5LsZf2j2DAz/ohqvQGDFE=", 483 | "requires": { 484 | "bluebird": "3.5.1", 485 | "debug": "3.1.0", 486 | "regexp-clone": "^1.0.0", 487 | "safe-buffer": "5.1.2", 488 | "sliced": "1.0.1" 489 | }, 490 | "dependencies": { 491 | "debug": { 492 | "version": "3.1.0", 493 | "resolved": "https://registry.npm.taobao.org/debug/download/debug-3.1.0.tgz?cache=0&sync_timestamp=1607566533140&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fdebug%2Fdownload%2Fdebug-3.1.0.tgz", 494 | "integrity": "sha1-W7WgZyYotkFJVmuhaBnmFRjGcmE=", 495 | "requires": { 496 | "ms": "2.0.0" 497 | } 498 | } 499 | } 500 | }, 501 | "ms": { 502 | "version": "2.0.0", 503 | "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.0.0.tgz?cache=0&sync_timestamp=1607433842694&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fms%2Fdownload%2Fms-2.0.0.tgz", 504 | "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" 505 | }, 506 | "negotiator": { 507 | "version": "0.6.2", 508 | "resolved": "https://registry.npm.taobao.org/negotiator/download/negotiator-0.6.2.tgz?cache=0&sync_timestamp=1589682752355&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fnegotiator%2Fdownload%2Fnegotiator-0.6.2.tgz", 509 | "integrity": "sha1-/qz3zPUlp3rpY0Q2pkiD/+yjRvs=" 510 | }, 511 | "nth-check": { 512 | "version": "2.0.0", 513 | "resolved": "https://registry.npm.taobao.org/nth-check/download/nth-check-2.0.0.tgz", 514 | "integrity": "sha1-G7T22scAcvwxPoyc0UF7UHTAoSU=", 515 | "requires": { 516 | "boolbase": "^1.0.0" 517 | } 518 | }, 519 | "on-finished": { 520 | "version": "2.3.0", 521 | "resolved": "https://registry.npm.taobao.org/on-finished/download/on-finished-2.3.0.tgz", 522 | "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", 523 | "requires": { 524 | "ee-first": "1.1.1" 525 | } 526 | }, 527 | "parse5": { 528 | "version": "6.0.1", 529 | "resolved": "https://registry.npm.taobao.org/parse5/download/parse5-6.0.1.tgz?cache=0&sync_timestamp=1595849263958&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fparse5%2Fdownload%2Fparse5-6.0.1.tgz", 530 | "integrity": "sha1-4aHAhcVps9wIMhGE8Zo5zCf3wws=" 531 | }, 532 | "parse5-htmlparser2-tree-adapter": { 533 | "version": "6.0.1", 534 | "resolved": "https://registry.npm.taobao.org/parse5-htmlparser2-tree-adapter/download/parse5-htmlparser2-tree-adapter-6.0.1.tgz", 535 | "integrity": "sha1-LN+a2CMyEUA3DU2/XT6Sx8jdxuY=", 536 | "requires": { 537 | "parse5": "^6.0.1" 538 | } 539 | }, 540 | "parseurl": { 541 | "version": "1.3.3", 542 | "resolved": "https://registry.npm.taobao.org/parseurl/download/parseurl-1.3.3.tgz", 543 | "integrity": "sha1-naGee+6NEt/wUT7Vt2lXeTvC6NQ=" 544 | }, 545 | "path-to-regexp": { 546 | "version": "0.1.7", 547 | "resolved": "https://registry.npm.taobao.org/path-to-regexp/download/path-to-regexp-0.1.7.tgz", 548 | "integrity": "sha1-32BBeABfUi8V60SQ5yR6G/qmf4w=" 549 | }, 550 | "process-nextick-args": { 551 | "version": "2.0.1", 552 | "resolved": "https://registry.npm.taobao.org/process-nextick-args/download/process-nextick-args-2.0.1.tgz", 553 | "integrity": "sha1-eCDZsWEgzFXKmud5JoCufbptf+I=" 554 | }, 555 | "proxy-addr": { 556 | "version": "2.0.6", 557 | "resolved": "https://registry.npm.taobao.org/proxy-addr/download/proxy-addr-2.0.6.tgz", 558 | "integrity": "sha1-/cIzZQVEfT8vLGOO0nLK9hS7sr8=", 559 | "requires": { 560 | "forwarded": "~0.1.2", 561 | "ipaddr.js": "1.9.1" 562 | } 563 | }, 564 | "qs": { 565 | "version": "6.7.0", 566 | "resolved": "https://registry.npm.taobao.org/qs/download/qs-6.7.0.tgz?cache=0&sync_timestamp=1616385281714&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fqs%2Fdownload%2Fqs-6.7.0.tgz", 567 | "integrity": "sha1-QdwaAV49WB8WIXdr4xr7KHapsbw=" 568 | }, 569 | "range-parser": { 570 | "version": "1.2.1", 571 | "resolved": "https://registry.npm.taobao.org/range-parser/download/range-parser-1.2.1.tgz", 572 | "integrity": "sha1-PPNwI9GZ4cJNGlW4SADC8+ZGgDE=" 573 | }, 574 | "raw-body": { 575 | "version": "2.4.0", 576 | "resolved": "https://registry.npm.taobao.org/raw-body/download/raw-body-2.4.0.tgz", 577 | "integrity": "sha1-oc5vucm8NWylLoklarWQWeE9AzI=", 578 | "requires": { 579 | "bytes": "3.1.0", 580 | "http-errors": "1.7.2", 581 | "iconv-lite": "0.4.24", 582 | "unpipe": "1.0.0" 583 | } 584 | }, 585 | "readable-stream": { 586 | "version": "2.3.7", 587 | "resolved": "https://registry.npm.taobao.org/readable-stream/download/readable-stream-2.3.7.tgz?cache=0&sync_timestamp=1589682741447&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Freadable-stream%2Fdownload%2Freadable-stream-2.3.7.tgz", 588 | "integrity": "sha1-Hsoc9xGu+BTAT2IlKjamL2yyO1c=", 589 | "requires": { 590 | "core-util-is": "~1.0.0", 591 | "inherits": "~2.0.3", 592 | "isarray": "~1.0.0", 593 | "process-nextick-args": "~2.0.0", 594 | "safe-buffer": "~5.1.1", 595 | "string_decoder": "~1.1.1", 596 | "util-deprecate": "~1.0.1" 597 | } 598 | }, 599 | "regexp-clone": { 600 | "version": "1.0.0", 601 | "resolved": "https://registry.npm.taobao.org/regexp-clone/download/regexp-clone-1.0.0.tgz", 602 | "integrity": "sha1-Ii25Z2IydwViYLmSYmNUoEzpv2M=" 603 | }, 604 | "require_optional": { 605 | "version": "1.0.1", 606 | "resolved": "https://registry.npm.taobao.org/require_optional/download/require_optional-1.0.1.tgz", 607 | "integrity": "sha1-TPNaQkf2TKPfjC7yCMxJSxyo/C4=", 608 | "requires": { 609 | "resolve-from": "^2.0.0", 610 | "semver": "^5.1.0" 611 | } 612 | }, 613 | "resolve-from": { 614 | "version": "2.0.0", 615 | "resolved": "https://registry.npm.taobao.org/resolve-from/download/resolve-from-2.0.0.tgz", 616 | "integrity": "sha1-lICrIOlP+h2egKgEx+oUdhGWa1c=" 617 | }, 618 | "safe-buffer": { 619 | "version": "5.1.2", 620 | "resolved": "https://registry.npm.taobao.org/safe-buffer/download/safe-buffer-5.1.2.tgz?cache=0&sync_timestamp=1589682795646&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fsafe-buffer%2Fdownload%2Fsafe-buffer-5.1.2.tgz", 621 | "integrity": "sha1-mR7GnSluAxN0fVm9/St0XDX4go0=" 622 | }, 623 | "safer-buffer": { 624 | "version": "2.1.2", 625 | "resolved": "https://registry.npm.taobao.org/safer-buffer/download/safer-buffer-2.1.2.tgz", 626 | "integrity": "sha1-RPoWGwGHuVSd2Eu5GAL5vYOFzWo=" 627 | }, 628 | "saslprep": { 629 | "version": "1.0.3", 630 | "resolved": "https://registry.npm.taobao.org/saslprep/download/saslprep-1.0.3.tgz", 631 | "integrity": "sha1-TAL5RrVs9UKX40e6EJPnrKxM8iY=", 632 | "optional": true, 633 | "requires": { 634 | "sparse-bitfield": "^3.0.3" 635 | } 636 | }, 637 | "semver": { 638 | "version": "5.7.1", 639 | "resolved": "https://registry.npm.taobao.org/semver/download/semver-5.7.1.tgz", 640 | "integrity": "sha1-qVT5Ma66UI0we78Gnv8MAclhFvc=" 641 | }, 642 | "send": { 643 | "version": "0.17.1", 644 | "resolved": "https://registry.npm.taobao.org/send/download/send-0.17.1.tgz", 645 | "integrity": "sha1-wdiwWfeQD3Rm3Uk4vcROEd2zdsg=", 646 | "requires": { 647 | "debug": "2.6.9", 648 | "depd": "~1.1.2", 649 | "destroy": "~1.0.4", 650 | "encodeurl": "~1.0.2", 651 | "escape-html": "~1.0.3", 652 | "etag": "~1.8.1", 653 | "fresh": "0.5.2", 654 | "http-errors": "~1.7.2", 655 | "mime": "1.6.0", 656 | "ms": "2.1.1", 657 | "on-finished": "~2.3.0", 658 | "range-parser": "~1.2.1", 659 | "statuses": "~1.5.0" 660 | }, 661 | "dependencies": { 662 | "ms": { 663 | "version": "2.1.1", 664 | "resolved": "https://registry.npm.taobao.org/ms/download/ms-2.1.1.tgz?cache=0&sync_timestamp=1607433842694&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fms%2Fdownload%2Fms-2.1.1.tgz", 665 | "integrity": "sha1-MKWGTrPrsKZvLr5tcnrwagnYbgo=" 666 | } 667 | } 668 | }, 669 | "serve-static": { 670 | "version": "1.14.1", 671 | "resolved": "https://registry.npm.taobao.org/serve-static/download/serve-static-1.14.1.tgz?cache=0&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fserve-static%2Fdownload%2Fserve-static-1.14.1.tgz", 672 | "integrity": "sha1-Zm5jbcTwEPfvKZcKiKZ0MgiYsvk=", 673 | "requires": { 674 | "encodeurl": "~1.0.2", 675 | "escape-html": "~1.0.3", 676 | "parseurl": "~1.3.3", 677 | "send": "0.17.1" 678 | } 679 | }, 680 | "set-cookie-parser": { 681 | "version": "2.4.8", 682 | "resolved": "https://registry.npm.taobao.org/set-cookie-parser/download/set-cookie-parser-2.4.8.tgz", 683 | "integrity": "sha1-0NoO04i8jyTnBqOR+cniUqE8WLI=" 684 | }, 685 | "setprototypeof": { 686 | "version": "1.1.1", 687 | "resolved": "https://registry.npm.taobao.org/setprototypeof/download/setprototypeof-1.1.1.tgz", 688 | "integrity": "sha1-fpWsskqpL1iF4KvvW6ExMw1K5oM=" 689 | }, 690 | "sift": { 691 | "version": "7.0.1", 692 | "resolved": "https://registry.npm.taobao.org/sift/download/sift-7.0.1.tgz", 693 | "integrity": "sha1-R9YsULFZ0xbxNy+LU/nBDNIaSwg=" 694 | }, 695 | "sliced": { 696 | "version": "1.0.1", 697 | "resolved": "https://registry.npm.taobao.org/sliced/download/sliced-1.0.1.tgz", 698 | "integrity": "sha1-CzpmK10Ewxd7GSa+qCsD+Dei70E=" 699 | }, 700 | "sparse-bitfield": { 701 | "version": "3.0.3", 702 | "resolved": "https://registry.npm.taobao.org/sparse-bitfield/download/sparse-bitfield-3.0.3.tgz", 703 | "integrity": "sha1-/0rm5oZWBWuks+eSqzM004JzyhE=", 704 | "optional": true, 705 | "requires": { 706 | "memory-pager": "^1.0.2" 707 | } 708 | }, 709 | "statuses": { 710 | "version": "1.5.0", 711 | "resolved": "https://registry.npm.taobao.org/statuses/download/statuses-1.5.0.tgz?cache=0&sync_timestamp=1609654014762&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstatuses%2Fdownload%2Fstatuses-1.5.0.tgz", 712 | "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" 713 | }, 714 | "string_decoder": { 715 | "version": "1.1.1", 716 | "resolved": "https://registry.npm.taobao.org/string_decoder/download/string_decoder-1.1.1.tgz?cache=0&sync_timestamp=1589682743884&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fstring_decoder%2Fdownload%2Fstring_decoder-1.1.1.tgz", 717 | "integrity": "sha1-nPFhG6YmhdcDCunkujQUnDrwP8g=", 718 | "requires": { 719 | "safe-buffer": "~5.1.0" 720 | } 721 | }, 722 | "toidentifier": { 723 | "version": "1.0.0", 724 | "resolved": "https://registry.npm.taobao.org/toidentifier/download/toidentifier-1.0.0.tgz", 725 | "integrity": "sha1-fhvjRw8ed5SLxD2Uo8j013UrpVM=" 726 | }, 727 | "tslib": { 728 | "version": "2.2.0", 729 | "resolved": "https://registry.npm.taobao.org/tslib/download/tslib-2.2.0.tgz?cache=0&sync_timestamp=1617647074515&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Ftslib%2Fdownload%2Ftslib-2.2.0.tgz", 730 | "integrity": "sha1-+yxHWXfjXiQTEe3iaTzuHsZpj1w=" 731 | }, 732 | "type-is": { 733 | "version": "1.6.18", 734 | "resolved": "https://registry.npm.taobao.org/type-is/download/type-is-1.6.18.tgz", 735 | "integrity": "sha1-TlUs0F3wlGfcvE73Od6J8s83wTE=", 736 | "requires": { 737 | "media-typer": "0.3.0", 738 | "mime-types": "~2.1.24" 739 | } 740 | }, 741 | "unpipe": { 742 | "version": "1.0.0", 743 | "resolved": "https://registry.npm.taobao.org/unpipe/download/unpipe-1.0.0.tgz?cache=0&sync_timestamp=1589682745059&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Funpipe%2Fdownload%2Funpipe-1.0.0.tgz", 744 | "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" 745 | }, 746 | "util-deprecate": { 747 | "version": "1.0.2", 748 | "resolved": "https://registry.npm.taobao.org/util-deprecate/download/util-deprecate-1.0.2.tgz", 749 | "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" 750 | }, 751 | "utils-merge": { 752 | "version": "1.0.1", 753 | "resolved": "https://registry.npm.taobao.org/utils-merge/download/utils-merge-1.0.1.tgz", 754 | "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" 755 | }, 756 | "vary": { 757 | "version": "1.1.2", 758 | "resolved": "https://registry.npm.taobao.org/vary/download/vary-1.1.2.tgz", 759 | "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" 760 | } 761 | } 762 | } 763 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "AutoStudy", 3 | "version": "1.2.5", 4 | "description": "这是一个能够快速完成你的大学课程的项目,目前实现了两个课程平台(超星学习通和柠檬学堂)", 5 | "main": "index.js", 6 | "scripts": { 7 | "serve": "node ./server.js" 8 | }, 9 | "keywords": [ 10 | "柠檬学堂", 11 | "柠檬文才", 12 | "超星学习通", 13 | "学习通", 14 | "大专刷课程", 15 | "大学刷课程", 16 | "大学课程脚本", 17 | "刷课程", 18 | "刷网课脚本", 19 | "网课脚本" 20 | ], 21 | "author": "孤独的小丑", 22 | "license": "ISC", 23 | "dependencies": { 24 | "cheerio": "^1.0.0-rc.9", 25 | "cookie": "^0.5.0", 26 | "cookie-parser": "^1.4.5", 27 | "crypto-js": "^4.0.0", 28 | "express": "^4.17.1", 29 | "md5-node": "^1.0.1", 30 | "mongoose": "^5.12.3", 31 | "set-cookie-parser": "^2.4.8" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /public/css/bootstrap-3.3.7-dist/css/bootstrap-theme.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.3.7 (http://getbootstrap.com) 3 | * Copyright 2011-2016 Twitter, Inc. 4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5 | */ 6 | .btn-default, 7 | .btn-primary, 8 | .btn-success, 9 | .btn-info, 10 | .btn-warning, 11 | .btn-danger { 12 | text-shadow: 0 -1px 0 rgba(0, 0, 0, .2); 13 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075); 14 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 1px rgba(0, 0, 0, .075); 15 | } 16 | .btn-default:active, 17 | .btn-primary:active, 18 | .btn-success:active, 19 | .btn-info:active, 20 | .btn-warning:active, 21 | .btn-danger:active, 22 | .btn-default.active, 23 | .btn-primary.active, 24 | .btn-success.active, 25 | .btn-info.active, 26 | .btn-warning.active, 27 | .btn-danger.active { 28 | -webkit-box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); 29 | box-shadow: inset 0 3px 5px rgba(0, 0, 0, .125); 30 | } 31 | .btn-default.disabled, 32 | .btn-primary.disabled, 33 | .btn-success.disabled, 34 | .btn-info.disabled, 35 | .btn-warning.disabled, 36 | .btn-danger.disabled, 37 | .btn-default[disabled], 38 | .btn-primary[disabled], 39 | .btn-success[disabled], 40 | .btn-info[disabled], 41 | .btn-warning[disabled], 42 | .btn-danger[disabled], 43 | fieldset[disabled] .btn-default, 44 | fieldset[disabled] .btn-primary, 45 | fieldset[disabled] .btn-success, 46 | fieldset[disabled] .btn-info, 47 | fieldset[disabled] .btn-warning, 48 | fieldset[disabled] .btn-danger { 49 | -webkit-box-shadow: none; 50 | box-shadow: none; 51 | } 52 | .btn-default .badge, 53 | .btn-primary .badge, 54 | .btn-success .badge, 55 | .btn-info .badge, 56 | .btn-warning .badge, 57 | .btn-danger .badge { 58 | text-shadow: none; 59 | } 60 | .btn:active, 61 | .btn.active { 62 | background-image: none; 63 | } 64 | .btn-default { 65 | text-shadow: 0 1px 0 #fff; 66 | background-image: -webkit-linear-gradient(top, #fff 0%, #e0e0e0 100%); 67 | background-image: -o-linear-gradient(top, #fff 0%, #e0e0e0 100%); 68 | background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#e0e0e0)); 69 | background-image: linear-gradient(to bottom, #fff 0%, #e0e0e0 100%); 70 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0); 71 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 72 | background-repeat: repeat-x; 73 | border-color: #dbdbdb; 74 | border-color: #ccc; 75 | } 76 | .btn-default:hover, 77 | .btn-default:focus { 78 | background-color: #e0e0e0; 79 | background-position: 0 -15px; 80 | } 81 | .btn-default:active, 82 | .btn-default.active { 83 | background-color: #e0e0e0; 84 | border-color: #dbdbdb; 85 | } 86 | .btn-default.disabled, 87 | .btn-default[disabled], 88 | fieldset[disabled] .btn-default, 89 | .btn-default.disabled:hover, 90 | .btn-default[disabled]:hover, 91 | fieldset[disabled] .btn-default:hover, 92 | .btn-default.disabled:focus, 93 | .btn-default[disabled]:focus, 94 | fieldset[disabled] .btn-default:focus, 95 | .btn-default.disabled.focus, 96 | .btn-default[disabled].focus, 97 | fieldset[disabled] .btn-default.focus, 98 | .btn-default.disabled:active, 99 | .btn-default[disabled]:active, 100 | fieldset[disabled] .btn-default:active, 101 | .btn-default.disabled.active, 102 | .btn-default[disabled].active, 103 | fieldset[disabled] .btn-default.active { 104 | background-color: #e0e0e0; 105 | background-image: none; 106 | } 107 | .btn-primary { 108 | background-image: -webkit-linear-gradient(top, #337ab7 0%, #265a88 100%); 109 | background-image: -o-linear-gradient(top, #337ab7 0%, #265a88 100%); 110 | background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#265a88)); 111 | background-image: linear-gradient(to bottom, #337ab7 0%, #265a88 100%); 112 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0); 113 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 114 | background-repeat: repeat-x; 115 | border-color: #245580; 116 | } 117 | .btn-primary:hover, 118 | .btn-primary:focus { 119 | background-color: #265a88; 120 | background-position: 0 -15px; 121 | } 122 | .btn-primary:active, 123 | .btn-primary.active { 124 | background-color: #265a88; 125 | border-color: #245580; 126 | } 127 | .btn-primary.disabled, 128 | .btn-primary[disabled], 129 | fieldset[disabled] .btn-primary, 130 | .btn-primary.disabled:hover, 131 | .btn-primary[disabled]:hover, 132 | fieldset[disabled] .btn-primary:hover, 133 | .btn-primary.disabled:focus, 134 | .btn-primary[disabled]:focus, 135 | fieldset[disabled] .btn-primary:focus, 136 | .btn-primary.disabled.focus, 137 | .btn-primary[disabled].focus, 138 | fieldset[disabled] .btn-primary.focus, 139 | .btn-primary.disabled:active, 140 | .btn-primary[disabled]:active, 141 | fieldset[disabled] .btn-primary:active, 142 | .btn-primary.disabled.active, 143 | .btn-primary[disabled].active, 144 | fieldset[disabled] .btn-primary.active { 145 | background-color: #265a88; 146 | background-image: none; 147 | } 148 | .btn-success { 149 | background-image: -webkit-linear-gradient(top, #5cb85c 0%, #419641 100%); 150 | background-image: -o-linear-gradient(top, #5cb85c 0%, #419641 100%); 151 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#419641)); 152 | background-image: linear-gradient(to bottom, #5cb85c 0%, #419641 100%); 153 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0); 154 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 155 | background-repeat: repeat-x; 156 | border-color: #3e8f3e; 157 | } 158 | .btn-success:hover, 159 | .btn-success:focus { 160 | background-color: #419641; 161 | background-position: 0 -15px; 162 | } 163 | .btn-success:active, 164 | .btn-success.active { 165 | background-color: #419641; 166 | border-color: #3e8f3e; 167 | } 168 | .btn-success.disabled, 169 | .btn-success[disabled], 170 | fieldset[disabled] .btn-success, 171 | .btn-success.disabled:hover, 172 | .btn-success[disabled]:hover, 173 | fieldset[disabled] .btn-success:hover, 174 | .btn-success.disabled:focus, 175 | .btn-success[disabled]:focus, 176 | fieldset[disabled] .btn-success:focus, 177 | .btn-success.disabled.focus, 178 | .btn-success[disabled].focus, 179 | fieldset[disabled] .btn-success.focus, 180 | .btn-success.disabled:active, 181 | .btn-success[disabled]:active, 182 | fieldset[disabled] .btn-success:active, 183 | .btn-success.disabled.active, 184 | .btn-success[disabled].active, 185 | fieldset[disabled] .btn-success.active { 186 | background-color: #419641; 187 | background-image: none; 188 | } 189 | .btn-info { 190 | background-image: -webkit-linear-gradient(top, #5bc0de 0%, #2aabd2 100%); 191 | background-image: -o-linear-gradient(top, #5bc0de 0%, #2aabd2 100%); 192 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#2aabd2)); 193 | background-image: linear-gradient(to bottom, #5bc0de 0%, #2aabd2 100%); 194 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0); 195 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 196 | background-repeat: repeat-x; 197 | border-color: #28a4c9; 198 | } 199 | .btn-info:hover, 200 | .btn-info:focus { 201 | background-color: #2aabd2; 202 | background-position: 0 -15px; 203 | } 204 | .btn-info:active, 205 | .btn-info.active { 206 | background-color: #2aabd2; 207 | border-color: #28a4c9; 208 | } 209 | .btn-info.disabled, 210 | .btn-info[disabled], 211 | fieldset[disabled] .btn-info, 212 | .btn-info.disabled:hover, 213 | .btn-info[disabled]:hover, 214 | fieldset[disabled] .btn-info:hover, 215 | .btn-info.disabled:focus, 216 | .btn-info[disabled]:focus, 217 | fieldset[disabled] .btn-info:focus, 218 | .btn-info.disabled.focus, 219 | .btn-info[disabled].focus, 220 | fieldset[disabled] .btn-info.focus, 221 | .btn-info.disabled:active, 222 | .btn-info[disabled]:active, 223 | fieldset[disabled] .btn-info:active, 224 | .btn-info.disabled.active, 225 | .btn-info[disabled].active, 226 | fieldset[disabled] .btn-info.active { 227 | background-color: #2aabd2; 228 | background-image: none; 229 | } 230 | .btn-warning { 231 | background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #eb9316 100%); 232 | background-image: -o-linear-gradient(top, #f0ad4e 0%, #eb9316 100%); 233 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#eb9316)); 234 | background-image: linear-gradient(to bottom, #f0ad4e 0%, #eb9316 100%); 235 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0); 236 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 237 | background-repeat: repeat-x; 238 | border-color: #e38d13; 239 | } 240 | .btn-warning:hover, 241 | .btn-warning:focus { 242 | background-color: #eb9316; 243 | background-position: 0 -15px; 244 | } 245 | .btn-warning:active, 246 | .btn-warning.active { 247 | background-color: #eb9316; 248 | border-color: #e38d13; 249 | } 250 | .btn-warning.disabled, 251 | .btn-warning[disabled], 252 | fieldset[disabled] .btn-warning, 253 | .btn-warning.disabled:hover, 254 | .btn-warning[disabled]:hover, 255 | fieldset[disabled] .btn-warning:hover, 256 | .btn-warning.disabled:focus, 257 | .btn-warning[disabled]:focus, 258 | fieldset[disabled] .btn-warning:focus, 259 | .btn-warning.disabled.focus, 260 | .btn-warning[disabled].focus, 261 | fieldset[disabled] .btn-warning.focus, 262 | .btn-warning.disabled:active, 263 | .btn-warning[disabled]:active, 264 | fieldset[disabled] .btn-warning:active, 265 | .btn-warning.disabled.active, 266 | .btn-warning[disabled].active, 267 | fieldset[disabled] .btn-warning.active { 268 | background-color: #eb9316; 269 | background-image: none; 270 | } 271 | .btn-danger { 272 | background-image: -webkit-linear-gradient(top, #d9534f 0%, #c12e2a 100%); 273 | background-image: -o-linear-gradient(top, #d9534f 0%, #c12e2a 100%); 274 | background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c12e2a)); 275 | background-image: linear-gradient(to bottom, #d9534f 0%, #c12e2a 100%); 276 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0); 277 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 278 | background-repeat: repeat-x; 279 | border-color: #b92c28; 280 | } 281 | .btn-danger:hover, 282 | .btn-danger:focus { 283 | background-color: #c12e2a; 284 | background-position: 0 -15px; 285 | } 286 | .btn-danger:active, 287 | .btn-danger.active { 288 | background-color: #c12e2a; 289 | border-color: #b92c28; 290 | } 291 | .btn-danger.disabled, 292 | .btn-danger[disabled], 293 | fieldset[disabled] .btn-danger, 294 | .btn-danger.disabled:hover, 295 | .btn-danger[disabled]:hover, 296 | fieldset[disabled] .btn-danger:hover, 297 | .btn-danger.disabled:focus, 298 | .btn-danger[disabled]:focus, 299 | fieldset[disabled] .btn-danger:focus, 300 | .btn-danger.disabled.focus, 301 | .btn-danger[disabled].focus, 302 | fieldset[disabled] .btn-danger.focus, 303 | .btn-danger.disabled:active, 304 | .btn-danger[disabled]:active, 305 | fieldset[disabled] .btn-danger:active, 306 | .btn-danger.disabled.active, 307 | .btn-danger[disabled].active, 308 | fieldset[disabled] .btn-danger.active { 309 | background-color: #c12e2a; 310 | background-image: none; 311 | } 312 | .thumbnail, 313 | .img-thumbnail { 314 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075); 315 | box-shadow: 0 1px 2px rgba(0, 0, 0, .075); 316 | } 317 | .dropdown-menu > li > a:hover, 318 | .dropdown-menu > li > a:focus { 319 | background-color: #e8e8e8; 320 | background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 321 | background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 322 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8)); 323 | background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%); 324 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0); 325 | background-repeat: repeat-x; 326 | } 327 | .dropdown-menu > .active > a, 328 | .dropdown-menu > .active > a:hover, 329 | .dropdown-menu > .active > a:focus { 330 | background-color: #2e6da4; 331 | background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%); 332 | background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%); 333 | background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4)); 334 | background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%); 335 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0); 336 | background-repeat: repeat-x; 337 | } 338 | .navbar-default { 339 | background-image: -webkit-linear-gradient(top, #fff 0%, #f8f8f8 100%); 340 | background-image: -o-linear-gradient(top, #fff 0%, #f8f8f8 100%); 341 | background-image: -webkit-gradient(linear, left top, left bottom, from(#fff), to(#f8f8f8)); 342 | background-image: linear-gradient(to bottom, #fff 0%, #f8f8f8 100%); 343 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0); 344 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 345 | background-repeat: repeat-x; 346 | border-radius: 4px; 347 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075); 348 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, .15), 0 1px 5px rgba(0, 0, 0, .075); 349 | } 350 | .navbar-default .navbar-nav > .open > a, 351 | .navbar-default .navbar-nav > .active > a { 352 | background-image: -webkit-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%); 353 | background-image: -o-linear-gradient(top, #dbdbdb 0%, #e2e2e2 100%); 354 | background-image: -webkit-gradient(linear, left top, left bottom, from(#dbdbdb), to(#e2e2e2)); 355 | background-image: linear-gradient(to bottom, #dbdbdb 0%, #e2e2e2 100%); 356 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0); 357 | background-repeat: repeat-x; 358 | -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075); 359 | box-shadow: inset 0 3px 9px rgba(0, 0, 0, .075); 360 | } 361 | .navbar-brand, 362 | .navbar-nav > li > a { 363 | text-shadow: 0 1px 0 rgba(255, 255, 255, .25); 364 | } 365 | .navbar-inverse { 366 | background-image: -webkit-linear-gradient(top, #3c3c3c 0%, #222 100%); 367 | background-image: -o-linear-gradient(top, #3c3c3c 0%, #222 100%); 368 | background-image: -webkit-gradient(linear, left top, left bottom, from(#3c3c3c), to(#222)); 369 | background-image: linear-gradient(to bottom, #3c3c3c 0%, #222 100%); 370 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0); 371 | filter: progid:DXImageTransform.Microsoft.gradient(enabled = false); 372 | background-repeat: repeat-x; 373 | border-radius: 4px; 374 | } 375 | .navbar-inverse .navbar-nav > .open > a, 376 | .navbar-inverse .navbar-nav > .active > a { 377 | background-image: -webkit-linear-gradient(top, #080808 0%, #0f0f0f 100%); 378 | background-image: -o-linear-gradient(top, #080808 0%, #0f0f0f 100%); 379 | background-image: -webkit-gradient(linear, left top, left bottom, from(#080808), to(#0f0f0f)); 380 | background-image: linear-gradient(to bottom, #080808 0%, #0f0f0f 100%); 381 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0); 382 | background-repeat: repeat-x; 383 | -webkit-box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25); 384 | box-shadow: inset 0 3px 9px rgba(0, 0, 0, .25); 385 | } 386 | .navbar-inverse .navbar-brand, 387 | .navbar-inverse .navbar-nav > li > a { 388 | text-shadow: 0 -1px 0 rgba(0, 0, 0, .25); 389 | } 390 | .navbar-static-top, 391 | .navbar-fixed-top, 392 | .navbar-fixed-bottom { 393 | border-radius: 0; 394 | } 395 | @media (max-width: 767px) { 396 | .navbar .navbar-nav .open .dropdown-menu > .active > a, 397 | .navbar .navbar-nav .open .dropdown-menu > .active > a:hover, 398 | .navbar .navbar-nav .open .dropdown-menu > .active > a:focus { 399 | color: #fff; 400 | background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%); 401 | background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%); 402 | background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4)); 403 | background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%); 404 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0); 405 | background-repeat: repeat-x; 406 | } 407 | } 408 | .alert { 409 | text-shadow: 0 1px 0 rgba(255, 255, 255, .2); 410 | -webkit-box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05); 411 | box-shadow: inset 0 1px 0 rgba(255, 255, 255, .25), 0 1px 2px rgba(0, 0, 0, .05); 412 | } 413 | .alert-success { 414 | background-image: -webkit-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%); 415 | background-image: -o-linear-gradient(top, #dff0d8 0%, #c8e5bc 100%); 416 | background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#c8e5bc)); 417 | background-image: linear-gradient(to bottom, #dff0d8 0%, #c8e5bc 100%); 418 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0); 419 | background-repeat: repeat-x; 420 | border-color: #b2dba1; 421 | } 422 | .alert-info { 423 | background-image: -webkit-linear-gradient(top, #d9edf7 0%, #b9def0 100%); 424 | background-image: -o-linear-gradient(top, #d9edf7 0%, #b9def0 100%); 425 | background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#b9def0)); 426 | background-image: linear-gradient(to bottom, #d9edf7 0%, #b9def0 100%); 427 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0); 428 | background-repeat: repeat-x; 429 | border-color: #9acfea; 430 | } 431 | .alert-warning { 432 | background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%); 433 | background-image: -o-linear-gradient(top, #fcf8e3 0%, #f8efc0 100%); 434 | background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#f8efc0)); 435 | background-image: linear-gradient(to bottom, #fcf8e3 0%, #f8efc0 100%); 436 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0); 437 | background-repeat: repeat-x; 438 | border-color: #f5e79e; 439 | } 440 | .alert-danger { 441 | background-image: -webkit-linear-gradient(top, #f2dede 0%, #e7c3c3 100%); 442 | background-image: -o-linear-gradient(top, #f2dede 0%, #e7c3c3 100%); 443 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#e7c3c3)); 444 | background-image: linear-gradient(to bottom, #f2dede 0%, #e7c3c3 100%); 445 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0); 446 | background-repeat: repeat-x; 447 | border-color: #dca7a7; 448 | } 449 | .progress { 450 | background-image: -webkit-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%); 451 | background-image: -o-linear-gradient(top, #ebebeb 0%, #f5f5f5 100%); 452 | background-image: -webkit-gradient(linear, left top, left bottom, from(#ebebeb), to(#f5f5f5)); 453 | background-image: linear-gradient(to bottom, #ebebeb 0%, #f5f5f5 100%); 454 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0); 455 | background-repeat: repeat-x; 456 | } 457 | .progress-bar { 458 | background-image: -webkit-linear-gradient(top, #337ab7 0%, #286090 100%); 459 | background-image: -o-linear-gradient(top, #337ab7 0%, #286090 100%); 460 | background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#286090)); 461 | background-image: linear-gradient(to bottom, #337ab7 0%, #286090 100%); 462 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0); 463 | background-repeat: repeat-x; 464 | } 465 | .progress-bar-success { 466 | background-image: -webkit-linear-gradient(top, #5cb85c 0%, #449d44 100%); 467 | background-image: -o-linear-gradient(top, #5cb85c 0%, #449d44 100%); 468 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5cb85c), to(#449d44)); 469 | background-image: linear-gradient(to bottom, #5cb85c 0%, #449d44 100%); 470 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0); 471 | background-repeat: repeat-x; 472 | } 473 | .progress-bar-info { 474 | background-image: -webkit-linear-gradient(top, #5bc0de 0%, #31b0d5 100%); 475 | background-image: -o-linear-gradient(top, #5bc0de 0%, #31b0d5 100%); 476 | background-image: -webkit-gradient(linear, left top, left bottom, from(#5bc0de), to(#31b0d5)); 477 | background-image: linear-gradient(to bottom, #5bc0de 0%, #31b0d5 100%); 478 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0); 479 | background-repeat: repeat-x; 480 | } 481 | .progress-bar-warning { 482 | background-image: -webkit-linear-gradient(top, #f0ad4e 0%, #ec971f 100%); 483 | background-image: -o-linear-gradient(top, #f0ad4e 0%, #ec971f 100%); 484 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f0ad4e), to(#ec971f)); 485 | background-image: linear-gradient(to bottom, #f0ad4e 0%, #ec971f 100%); 486 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0); 487 | background-repeat: repeat-x; 488 | } 489 | .progress-bar-danger { 490 | background-image: -webkit-linear-gradient(top, #d9534f 0%, #c9302c 100%); 491 | background-image: -o-linear-gradient(top, #d9534f 0%, #c9302c 100%); 492 | background-image: -webkit-gradient(linear, left top, left bottom, from(#d9534f), to(#c9302c)); 493 | background-image: linear-gradient(to bottom, #d9534f 0%, #c9302c 100%); 494 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0); 495 | background-repeat: repeat-x; 496 | } 497 | .progress-bar-striped { 498 | background-image: -webkit-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); 499 | background-image: -o-linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); 500 | background-image: linear-gradient(45deg, rgba(255, 255, 255, .15) 25%, transparent 25%, transparent 50%, rgba(255, 255, 255, .15) 50%, rgba(255, 255, 255, .15) 75%, transparent 75%, transparent); 501 | } 502 | .list-group { 503 | border-radius: 4px; 504 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .075); 505 | box-shadow: 0 1px 2px rgba(0, 0, 0, .075); 506 | } 507 | .list-group-item.active, 508 | .list-group-item.active:hover, 509 | .list-group-item.active:focus { 510 | text-shadow: 0 -1px 0 #286090; 511 | background-image: -webkit-linear-gradient(top, #337ab7 0%, #2b669a 100%); 512 | background-image: -o-linear-gradient(top, #337ab7 0%, #2b669a 100%); 513 | background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2b669a)); 514 | background-image: linear-gradient(to bottom, #337ab7 0%, #2b669a 100%); 515 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0); 516 | background-repeat: repeat-x; 517 | border-color: #2b669a; 518 | } 519 | .list-group-item.active .badge, 520 | .list-group-item.active:hover .badge, 521 | .list-group-item.active:focus .badge { 522 | text-shadow: none; 523 | } 524 | .panel { 525 | -webkit-box-shadow: 0 1px 2px rgba(0, 0, 0, .05); 526 | box-shadow: 0 1px 2px rgba(0, 0, 0, .05); 527 | } 528 | .panel-default > .panel-heading { 529 | background-image: -webkit-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 530 | background-image: -o-linear-gradient(top, #f5f5f5 0%, #e8e8e8 100%); 531 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f5f5f5), to(#e8e8e8)); 532 | background-image: linear-gradient(to bottom, #f5f5f5 0%, #e8e8e8 100%); 533 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0); 534 | background-repeat: repeat-x; 535 | } 536 | .panel-primary > .panel-heading { 537 | background-image: -webkit-linear-gradient(top, #337ab7 0%, #2e6da4 100%); 538 | background-image: -o-linear-gradient(top, #337ab7 0%, #2e6da4 100%); 539 | background-image: -webkit-gradient(linear, left top, left bottom, from(#337ab7), to(#2e6da4)); 540 | background-image: linear-gradient(to bottom, #337ab7 0%, #2e6da4 100%); 541 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0); 542 | background-repeat: repeat-x; 543 | } 544 | .panel-success > .panel-heading { 545 | background-image: -webkit-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%); 546 | background-image: -o-linear-gradient(top, #dff0d8 0%, #d0e9c6 100%); 547 | background-image: -webkit-gradient(linear, left top, left bottom, from(#dff0d8), to(#d0e9c6)); 548 | background-image: linear-gradient(to bottom, #dff0d8 0%, #d0e9c6 100%); 549 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0); 550 | background-repeat: repeat-x; 551 | } 552 | .panel-info > .panel-heading { 553 | background-image: -webkit-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%); 554 | background-image: -o-linear-gradient(top, #d9edf7 0%, #c4e3f3 100%); 555 | background-image: -webkit-gradient(linear, left top, left bottom, from(#d9edf7), to(#c4e3f3)); 556 | background-image: linear-gradient(to bottom, #d9edf7 0%, #c4e3f3 100%); 557 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0); 558 | background-repeat: repeat-x; 559 | } 560 | .panel-warning > .panel-heading { 561 | background-image: -webkit-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%); 562 | background-image: -o-linear-gradient(top, #fcf8e3 0%, #faf2cc 100%); 563 | background-image: -webkit-gradient(linear, left top, left bottom, from(#fcf8e3), to(#faf2cc)); 564 | background-image: linear-gradient(to bottom, #fcf8e3 0%, #faf2cc 100%); 565 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0); 566 | background-repeat: repeat-x; 567 | } 568 | .panel-danger > .panel-heading { 569 | background-image: -webkit-linear-gradient(top, #f2dede 0%, #ebcccc 100%); 570 | background-image: -o-linear-gradient(top, #f2dede 0%, #ebcccc 100%); 571 | background-image: -webkit-gradient(linear, left top, left bottom, from(#f2dede), to(#ebcccc)); 572 | background-image: linear-gradient(to bottom, #f2dede 0%, #ebcccc 100%); 573 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0); 574 | background-repeat: repeat-x; 575 | } 576 | .well { 577 | background-image: -webkit-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%); 578 | background-image: -o-linear-gradient(top, #e8e8e8 0%, #f5f5f5 100%); 579 | background-image: -webkit-gradient(linear, left top, left bottom, from(#e8e8e8), to(#f5f5f5)); 580 | background-image: linear-gradient(to bottom, #e8e8e8 0%, #f5f5f5 100%); 581 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0); 582 | background-repeat: repeat-x; 583 | border-color: #dcdcdc; 584 | -webkit-box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1); 585 | box-shadow: inset 0 1px 3px rgba(0, 0, 0, .05), 0 1px 0 rgba(255, 255, 255, .1); 586 | } 587 | /*# sourceMappingURL=bootstrap-theme.css.map */ 588 | -------------------------------------------------------------------------------- /public/css/bootstrap-3.3.7-dist/css/bootstrap-theme.min.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap v3.3.7 (http://getbootstrap.com) 3 | * Copyright 2011-2016 Twitter, Inc. 4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) 5 | */.btn-danger,.btn-default,.btn-info,.btn-primary,.btn-success,.btn-warning{text-shadow:0 -1px 0 rgba(0,0,0,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 1px rgba(0,0,0,.075)}.btn-danger.active,.btn-danger:active,.btn-default.active,.btn-default:active,.btn-info.active,.btn-info:active,.btn-primary.active,.btn-primary:active,.btn-success.active,.btn-success:active,.btn-warning.active,.btn-warning:active{-webkit-box-shadow:inset 0 3px 5px rgba(0,0,0,.125);box-shadow:inset 0 3px 5px rgba(0,0,0,.125)}.btn-danger.disabled,.btn-danger[disabled],.btn-default.disabled,.btn-default[disabled],.btn-info.disabled,.btn-info[disabled],.btn-primary.disabled,.btn-primary[disabled],.btn-success.disabled,.btn-success[disabled],.btn-warning.disabled,.btn-warning[disabled],fieldset[disabled] .btn-danger,fieldset[disabled] .btn-default,fieldset[disabled] .btn-info,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-success,fieldset[disabled] .btn-warning{-webkit-box-shadow:none;box-shadow:none}.btn-danger .badge,.btn-default .badge,.btn-info .badge,.btn-primary .badge,.btn-success .badge,.btn-warning .badge{text-shadow:none}.btn.active,.btn:active{background-image:none}.btn-default{text-shadow:0 1px 0 #fff;background-image:-webkit-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-o-linear-gradient(top,#fff 0,#e0e0e0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#e0e0e0));background-image:linear-gradient(to bottom,#fff 0,#e0e0e0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#ffe0e0e0', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#dbdbdb;border-color:#ccc}.btn-default:focus,.btn-default:hover{background-color:#e0e0e0;background-position:0 -15px}.btn-default.active,.btn-default:active{background-color:#e0e0e0;border-color:#dbdbdb}.btn-default.disabled,.btn-default.disabled.active,.btn-default.disabled.focus,.btn-default.disabled:active,.btn-default.disabled:focus,.btn-default.disabled:hover,.btn-default[disabled],.btn-default[disabled].active,.btn-default[disabled].focus,.btn-default[disabled]:active,.btn-default[disabled]:focus,.btn-default[disabled]:hover,fieldset[disabled] .btn-default,fieldset[disabled] .btn-default.active,fieldset[disabled] .btn-default.focus,fieldset[disabled] .btn-default:active,fieldset[disabled] .btn-default:focus,fieldset[disabled] .btn-default:hover{background-color:#e0e0e0;background-image:none}.btn-primary{background-image:-webkit-linear-gradient(top,#337ab7 0,#265a88 100%);background-image:-o-linear-gradient(top,#337ab7 0,#265a88 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#265a88));background-image:linear-gradient(to bottom,#337ab7 0,#265a88 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff265a88', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#245580}.btn-primary:focus,.btn-primary:hover{background-color:#265a88;background-position:0 -15px}.btn-primary.active,.btn-primary:active{background-color:#265a88;border-color:#245580}.btn-primary.disabled,.btn-primary.disabled.active,.btn-primary.disabled.focus,.btn-primary.disabled:active,.btn-primary.disabled:focus,.btn-primary.disabled:hover,.btn-primary[disabled],.btn-primary[disabled].active,.btn-primary[disabled].focus,.btn-primary[disabled]:active,.btn-primary[disabled]:focus,.btn-primary[disabled]:hover,fieldset[disabled] .btn-primary,fieldset[disabled] .btn-primary.active,fieldset[disabled] .btn-primary.focus,fieldset[disabled] .btn-primary:active,fieldset[disabled] .btn-primary:focus,fieldset[disabled] .btn-primary:hover{background-color:#265a88;background-image:none}.btn-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#419641 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#419641));background-image:linear-gradient(to bottom,#5cb85c 0,#419641 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff419641', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#3e8f3e}.btn-success:focus,.btn-success:hover{background-color:#419641;background-position:0 -15px}.btn-success.active,.btn-success:active{background-color:#419641;border-color:#3e8f3e}.btn-success.disabled,.btn-success.disabled.active,.btn-success.disabled.focus,.btn-success.disabled:active,.btn-success.disabled:focus,.btn-success.disabled:hover,.btn-success[disabled],.btn-success[disabled].active,.btn-success[disabled].focus,.btn-success[disabled]:active,.btn-success[disabled]:focus,.btn-success[disabled]:hover,fieldset[disabled] .btn-success,fieldset[disabled] .btn-success.active,fieldset[disabled] .btn-success.focus,fieldset[disabled] .btn-success:active,fieldset[disabled] .btn-success:focus,fieldset[disabled] .btn-success:hover{background-color:#419641;background-image:none}.btn-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#2aabd2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#2aabd2));background-image:linear-gradient(to bottom,#5bc0de 0,#2aabd2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff2aabd2', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#28a4c9}.btn-info:focus,.btn-info:hover{background-color:#2aabd2;background-position:0 -15px}.btn-info.active,.btn-info:active{background-color:#2aabd2;border-color:#28a4c9}.btn-info.disabled,.btn-info.disabled.active,.btn-info.disabled.focus,.btn-info.disabled:active,.btn-info.disabled:focus,.btn-info.disabled:hover,.btn-info[disabled],.btn-info[disabled].active,.btn-info[disabled].focus,.btn-info[disabled]:active,.btn-info[disabled]:focus,.btn-info[disabled]:hover,fieldset[disabled] .btn-info,fieldset[disabled] .btn-info.active,fieldset[disabled] .btn-info.focus,fieldset[disabled] .btn-info:active,fieldset[disabled] .btn-info:focus,fieldset[disabled] .btn-info:hover{background-color:#2aabd2;background-image:none}.btn-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#eb9316 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#eb9316));background-image:linear-gradient(to bottom,#f0ad4e 0,#eb9316 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffeb9316', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#e38d13}.btn-warning:focus,.btn-warning:hover{background-color:#eb9316;background-position:0 -15px}.btn-warning.active,.btn-warning:active{background-color:#eb9316;border-color:#e38d13}.btn-warning.disabled,.btn-warning.disabled.active,.btn-warning.disabled.focus,.btn-warning.disabled:active,.btn-warning.disabled:focus,.btn-warning.disabled:hover,.btn-warning[disabled],.btn-warning[disabled].active,.btn-warning[disabled].focus,.btn-warning[disabled]:active,.btn-warning[disabled]:focus,.btn-warning[disabled]:hover,fieldset[disabled] .btn-warning,fieldset[disabled] .btn-warning.active,fieldset[disabled] .btn-warning.focus,fieldset[disabled] .btn-warning:active,fieldset[disabled] .btn-warning:focus,fieldset[disabled] .btn-warning:hover{background-color:#eb9316;background-image:none}.btn-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c12e2a 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c12e2a));background-image:linear-gradient(to bottom,#d9534f 0,#c12e2a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc12e2a', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-color:#b92c28}.btn-danger:focus,.btn-danger:hover{background-color:#c12e2a;background-position:0 -15px}.btn-danger.active,.btn-danger:active{background-color:#c12e2a;border-color:#b92c28}.btn-danger.disabled,.btn-danger.disabled.active,.btn-danger.disabled.focus,.btn-danger.disabled:active,.btn-danger.disabled:focus,.btn-danger.disabled:hover,.btn-danger[disabled],.btn-danger[disabled].active,.btn-danger[disabled].focus,.btn-danger[disabled]:active,.btn-danger[disabled]:focus,.btn-danger[disabled]:hover,fieldset[disabled] .btn-danger,fieldset[disabled] .btn-danger.active,fieldset[disabled] .btn-danger.focus,fieldset[disabled] .btn-danger:active,fieldset[disabled] .btn-danger:focus,fieldset[disabled] .btn-danger:hover{background-color:#c12e2a;background-image:none}.img-thumbnail,.thumbnail{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.dropdown-menu>li>a:focus,.dropdown-menu>li>a:hover{background-color:#e8e8e8;background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.dropdown-menu>.active>a,.dropdown-menu>.active>a:focus,.dropdown-menu>.active>a:hover{background-color:#2e6da4;background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}.navbar-default{background-image:-webkit-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-o-linear-gradient(top,#fff 0,#f8f8f8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fff),to(#f8f8f8));background-image:linear-gradient(to bottom,#fff 0,#f8f8f8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffffffff', endColorstr='#fff8f8f8', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-radius:4px;-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075);box-shadow:inset 0 1px 0 rgba(255,255,255,.15),0 1px 5px rgba(0,0,0,.075)}.navbar-default .navbar-nav>.active>a,.navbar-default .navbar-nav>.open>a{background-image:-webkit-linear-gradient(top,#dbdbdb 0,#e2e2e2 100%);background-image:-o-linear-gradient(top,#dbdbdb 0,#e2e2e2 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dbdbdb),to(#e2e2e2));background-image:linear-gradient(to bottom,#dbdbdb 0,#e2e2e2 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdbdbdb', endColorstr='#ffe2e2e2', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.075);box-shadow:inset 0 3px 9px rgba(0,0,0,.075)}.navbar-brand,.navbar-nav>li>a{text-shadow:0 1px 0 rgba(255,255,255,.25)}.navbar-inverse{background-image:-webkit-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-o-linear-gradient(top,#3c3c3c 0,#222 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#3c3c3c),to(#222));background-image:linear-gradient(to bottom,#3c3c3c 0,#222 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff3c3c3c', endColorstr='#ff222222', GradientType=0);filter:progid:DXImageTransform.Microsoft.gradient(enabled=false);background-repeat:repeat-x;border-radius:4px}.navbar-inverse .navbar-nav>.active>a,.navbar-inverse .navbar-nav>.open>a{background-image:-webkit-linear-gradient(top,#080808 0,#0f0f0f 100%);background-image:-o-linear-gradient(top,#080808 0,#0f0f0f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#080808),to(#0f0f0f));background-image:linear-gradient(to bottom,#080808 0,#0f0f0f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff080808', endColorstr='#ff0f0f0f', GradientType=0);background-repeat:repeat-x;-webkit-box-shadow:inset 0 3px 9px rgba(0,0,0,.25);box-shadow:inset 0 3px 9px rgba(0,0,0,.25)}.navbar-inverse .navbar-brand,.navbar-inverse .navbar-nav>li>a{text-shadow:0 -1px 0 rgba(0,0,0,.25)}.navbar-fixed-bottom,.navbar-fixed-top,.navbar-static-top{border-radius:0}@media (max-width:767px){.navbar .navbar-nav .open .dropdown-menu>.active>a,.navbar .navbar-nav .open .dropdown-menu>.active>a:focus,.navbar .navbar-nav .open .dropdown-menu>.active>a:hover{color:#fff;background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}}.alert{text-shadow:0 1px 0 rgba(255,255,255,.2);-webkit-box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05);box-shadow:inset 0 1px 0 rgba(255,255,255,.25),0 1px 2px rgba(0,0,0,.05)}.alert-success{background-image:-webkit-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#c8e5bc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#c8e5bc));background-image:linear-gradient(to bottom,#dff0d8 0,#c8e5bc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffc8e5bc', GradientType=0);background-repeat:repeat-x;border-color:#b2dba1}.alert-info{background-image:-webkit-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#b9def0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#b9def0));background-image:linear-gradient(to bottom,#d9edf7 0,#b9def0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffb9def0', GradientType=0);background-repeat:repeat-x;border-color:#9acfea}.alert-warning{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#f8efc0 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#f8efc0));background-image:linear-gradient(to bottom,#fcf8e3 0,#f8efc0 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fff8efc0', GradientType=0);background-repeat:repeat-x;border-color:#f5e79e}.alert-danger{background-image:-webkit-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-o-linear-gradient(top,#f2dede 0,#e7c3c3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#e7c3c3));background-image:linear-gradient(to bottom,#f2dede 0,#e7c3c3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffe7c3c3', GradientType=0);background-repeat:repeat-x;border-color:#dca7a7}.progress{background-image:-webkit-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#ebebeb 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#ebebeb),to(#f5f5f5));background-image:linear-gradient(to bottom,#ebebeb 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffebebeb', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x}.progress-bar{background-image:-webkit-linear-gradient(top,#337ab7 0,#286090 100%);background-image:-o-linear-gradient(top,#337ab7 0,#286090 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#286090));background-image:linear-gradient(to bottom,#337ab7 0,#286090 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff286090', GradientType=0);background-repeat:repeat-x}.progress-bar-success{background-image:-webkit-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-o-linear-gradient(top,#5cb85c 0,#449d44 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5cb85c),to(#449d44));background-image:linear-gradient(to bottom,#5cb85c 0,#449d44 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5cb85c', endColorstr='#ff449d44', GradientType=0);background-repeat:repeat-x}.progress-bar-info{background-image:-webkit-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-o-linear-gradient(top,#5bc0de 0,#31b0d5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#5bc0de),to(#31b0d5));background-image:linear-gradient(to bottom,#5bc0de 0,#31b0d5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff5bc0de', endColorstr='#ff31b0d5', GradientType=0);background-repeat:repeat-x}.progress-bar-warning{background-image:-webkit-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-o-linear-gradient(top,#f0ad4e 0,#ec971f 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f0ad4e),to(#ec971f));background-image:linear-gradient(to bottom,#f0ad4e 0,#ec971f 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff0ad4e', endColorstr='#ffec971f', GradientType=0);background-repeat:repeat-x}.progress-bar-danger{background-image:-webkit-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-o-linear-gradient(top,#d9534f 0,#c9302c 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9534f),to(#c9302c));background-image:linear-gradient(to bottom,#d9534f 0,#c9302c 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9534f', endColorstr='#ffc9302c', GradientType=0);background-repeat:repeat-x}.progress-bar-striped{background-image:-webkit-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:-o-linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent);background-image:linear-gradient(45deg,rgba(255,255,255,.15) 25%,transparent 25%,transparent 50%,rgba(255,255,255,.15) 50%,rgba(255,255,255,.15) 75%,transparent 75%,transparent)}.list-group{border-radius:4px;-webkit-box-shadow:0 1px 2px rgba(0,0,0,.075);box-shadow:0 1px 2px rgba(0,0,0,.075)}.list-group-item.active,.list-group-item.active:focus,.list-group-item.active:hover{text-shadow:0 -1px 0 #286090;background-image:-webkit-linear-gradient(top,#337ab7 0,#2b669a 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2b669a 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2b669a));background-image:linear-gradient(to bottom,#337ab7 0,#2b669a 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2b669a', GradientType=0);background-repeat:repeat-x;border-color:#2b669a}.list-group-item.active .badge,.list-group-item.active:focus .badge,.list-group-item.active:hover .badge{text-shadow:none}.panel{-webkit-box-shadow:0 1px 2px rgba(0,0,0,.05);box-shadow:0 1px 2px rgba(0,0,0,.05)}.panel-default>.panel-heading{background-image:-webkit-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-o-linear-gradient(top,#f5f5f5 0,#e8e8e8 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f5f5f5),to(#e8e8e8));background-image:linear-gradient(to bottom,#f5f5f5 0,#e8e8e8 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff5f5f5', endColorstr='#ffe8e8e8', GradientType=0);background-repeat:repeat-x}.panel-primary>.panel-heading{background-image:-webkit-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-o-linear-gradient(top,#337ab7 0,#2e6da4 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#337ab7),to(#2e6da4));background-image:linear-gradient(to bottom,#337ab7 0,#2e6da4 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff337ab7', endColorstr='#ff2e6da4', GradientType=0);background-repeat:repeat-x}.panel-success>.panel-heading{background-image:-webkit-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-o-linear-gradient(top,#dff0d8 0,#d0e9c6 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#dff0d8),to(#d0e9c6));background-image:linear-gradient(to bottom,#dff0d8 0,#d0e9c6 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffdff0d8', endColorstr='#ffd0e9c6', GradientType=0);background-repeat:repeat-x}.panel-info>.panel-heading{background-image:-webkit-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-o-linear-gradient(top,#d9edf7 0,#c4e3f3 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#d9edf7),to(#c4e3f3));background-image:linear-gradient(to bottom,#d9edf7 0,#c4e3f3 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffd9edf7', endColorstr='#ffc4e3f3', GradientType=0);background-repeat:repeat-x}.panel-warning>.panel-heading{background-image:-webkit-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-o-linear-gradient(top,#fcf8e3 0,#faf2cc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#fcf8e3),to(#faf2cc));background-image:linear-gradient(to bottom,#fcf8e3 0,#faf2cc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fffcf8e3', endColorstr='#fffaf2cc', GradientType=0);background-repeat:repeat-x}.panel-danger>.panel-heading{background-image:-webkit-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-o-linear-gradient(top,#f2dede 0,#ebcccc 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#f2dede),to(#ebcccc));background-image:linear-gradient(to bottom,#f2dede 0,#ebcccc 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#fff2dede', endColorstr='#ffebcccc', GradientType=0);background-repeat:repeat-x}.well{background-image:-webkit-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-o-linear-gradient(top,#e8e8e8 0,#f5f5f5 100%);background-image:-webkit-gradient(linear,left top,left bottom,from(#e8e8e8),to(#f5f5f5));background-image:linear-gradient(to bottom,#e8e8e8 0,#f5f5f5 100%);filter:progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffe8e8e8', endColorstr='#fff5f5f5', GradientType=0);background-repeat:repeat-x;border-color:#dcdcdc;-webkit-box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1);box-shadow:inset 0 1px 3px rgba(0,0,0,.05),0 1px 0 rgba(255,255,255,.1)} 6 | /*# sourceMappingURL=bootstrap-theme.min.css.map */ -------------------------------------------------------------------------------- /public/css/bootstrap-3.3.7-dist/css/bootstrap-theme.min.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sources":["less/theme.less","less/mixins/vendor-prefixes.less","less/mixins/gradients.less","less/mixins/reset-filter.less"],"names":[],"mappings":";;;;AAmBA,YAAA,aAAA,UAAA,aAAA,aAAA,aAME,YAAA,EAAA,KAAA,EAAA,eC2CA,mBAAA,MAAA,EAAA,IAAA,EAAA,sBAAA,EAAA,IAAA,IAAA,iBACQ,WAAA,MAAA,EAAA,IAAA,EAAA,sBAAA,EAAA,IAAA,IAAA,iBDvCR,mBAAA,mBAAA,oBAAA,oBAAA,iBAAA,iBAAA,oBAAA,oBAAA,oBAAA,oBAAA,oBAAA,oBCsCA,mBAAA,MAAA,EAAA,IAAA,IAAA,iBACQ,WAAA,MAAA,EAAA,IAAA,IAAA,iBDlCR,qBAAA,sBAAA,sBAAA,uBAAA,mBAAA,oBAAA,sBAAA,uBAAA,sBAAA,uBAAA,sBAAA,uBAAA,+BAAA,gCAAA,6BAAA,gCAAA,gCAAA,gCCiCA,mBAAA,KACQ,WAAA,KDlDV,mBAAA,oBAAA,iBAAA,oBAAA,oBAAA,oBAuBI,YAAA,KAyCF,YAAA,YAEE,iBAAA,KAKJ,aErEI,YAAA,EAAA,IAAA,EAAA,KACA,iBAAA,iDACA,iBAAA,4CAAA,iBAAA,qEAEA,iBAAA,+CCnBF,OAAA,+GH4CA,OAAA,0DACA,kBAAA,SAuC2C,aAAA,QAA2B,aAAA,KArCtE,mBAAA,mBAEE,iBAAA,QACA,oBAAA,EAAA,MAGF,oBAAA,oBAEE,iBAAA,QACA,aAAA,QAMA,sBAAA,6BAAA,4BAAA,6BAAA,4BAAA,4BAAA,uBAAA,8BAAA,6BAAA,8BAAA,6BAAA,6BAAA,gCAAA,uCAAA,sCAAA,uCAAA,sCAAA,sCAME,iBAAA,QACA,iBAAA,KAgBN,aEtEI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDAEA,OAAA,+GCnBF,OAAA,0DH4CA,kBAAA,SACA,aAAA,QAEA,mBAAA,mBAEE,iBAAA,QACA,oBAAA,EAAA,MAGF,oBAAA,oBAEE,iBAAA,QACA,aAAA,QAMA,sBAAA,6BAAA,4BAAA,6BAAA,4BAAA,4BAAA,uBAAA,8BAAA,6BAAA,8BAAA,6BAAA,6BAAA,gCAAA,uCAAA,sCAAA,uCAAA,sCAAA,sCAME,iBAAA,QACA,iBAAA,KAiBN,aEvEI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDAEA,OAAA,+GCnBF,OAAA,0DH4CA,kBAAA,SACA,aAAA,QAEA,mBAAA,mBAEE,iBAAA,QACA,oBAAA,EAAA,MAGF,oBAAA,oBAEE,iBAAA,QACA,aAAA,QAMA,sBAAA,6BAAA,4BAAA,6BAAA,4BAAA,4BAAA,uBAAA,8BAAA,6BAAA,8BAAA,6BAAA,6BAAA,gCAAA,uCAAA,sCAAA,uCAAA,sCAAA,sCAME,iBAAA,QACA,iBAAA,KAkBN,UExEI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDAEA,OAAA,+GCnBF,OAAA,0DH4CA,kBAAA,SACA,aAAA,QAEA,gBAAA,gBAEE,iBAAA,QACA,oBAAA,EAAA,MAGF,iBAAA,iBAEE,iBAAA,QACA,aAAA,QAMA,mBAAA,0BAAA,yBAAA,0BAAA,yBAAA,yBAAA,oBAAA,2BAAA,0BAAA,2BAAA,0BAAA,0BAAA,6BAAA,oCAAA,mCAAA,oCAAA,mCAAA,mCAME,iBAAA,QACA,iBAAA,KAmBN,aEzEI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDAEA,OAAA,+GCnBF,OAAA,0DH4CA,kBAAA,SACA,aAAA,QAEA,mBAAA,mBAEE,iBAAA,QACA,oBAAA,EAAA,MAGF,oBAAA,oBAEE,iBAAA,QACA,aAAA,QAMA,sBAAA,6BAAA,4BAAA,6BAAA,4BAAA,4BAAA,uBAAA,8BAAA,6BAAA,8BAAA,6BAAA,6BAAA,gCAAA,uCAAA,sCAAA,uCAAA,sCAAA,sCAME,iBAAA,QACA,iBAAA,KAoBN,YE1EI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDAEA,OAAA,+GCnBF,OAAA,0DH4CA,kBAAA,SACA,aAAA,QAEA,kBAAA,kBAEE,iBAAA,QACA,oBAAA,EAAA,MAGF,mBAAA,mBAEE,iBAAA,QACA,aAAA,QAMA,qBAAA,4BAAA,2BAAA,4BAAA,2BAAA,2BAAA,sBAAA,6BAAA,4BAAA,6BAAA,4BAAA,4BAAA,+BAAA,sCAAA,qCAAA,sCAAA,qCAAA,qCAME,iBAAA,QACA,iBAAA,KA2BN,eAAA,WClCE,mBAAA,EAAA,IAAA,IAAA,iBACQ,WAAA,EAAA,IAAA,IAAA,iBD2CV,0BAAA,0BE3FI,iBAAA,QACA,iBAAA,oDACA,iBAAA,+CAAA,iBAAA,wEACA,iBAAA,kDACA,OAAA,+GF0FF,kBAAA,SAEF,yBAAA,+BAAA,+BEhGI,iBAAA,QACA,iBAAA,oDACA,iBAAA,+CAAA,iBAAA,wEACA,iBAAA,kDACA,OAAA,+GFgGF,kBAAA,SASF,gBE7GI,iBAAA,iDACA,iBAAA,4CACA,iBAAA,qEAAA,iBAAA,+CACA,OAAA,+GACA,OAAA,0DCnBF,kBAAA,SH+HA,cAAA,ICjEA,mBAAA,MAAA,EAAA,IAAA,EAAA,sBAAA,EAAA,IAAA,IAAA,iBACQ,WAAA,MAAA,EAAA,IAAA,EAAA,sBAAA,EAAA,IAAA,IAAA,iBD6DV,sCAAA,oCE7GI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SD2CF,mBAAA,MAAA,EAAA,IAAA,IAAA,iBACQ,WAAA,MAAA,EAAA,IAAA,IAAA,iBD0EV,cAAA,iBAEE,YAAA,EAAA,IAAA,EAAA,sBAIF,gBEhII,iBAAA,iDACA,iBAAA,4CACA,iBAAA,qEAAA,iBAAA,+CACA,OAAA,+GACA,OAAA,0DCnBF,kBAAA,SHkJA,cAAA,IAHF,sCAAA,oCEhII,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SD2CF,mBAAA,MAAA,EAAA,IAAA,IAAA,gBACQ,WAAA,MAAA,EAAA,IAAA,IAAA,gBDgFV,8BAAA,iCAYI,YAAA,EAAA,KAAA,EAAA,gBAKJ,qBAAA,kBAAA,mBAGE,cAAA,EAqBF,yBAfI,mDAAA,yDAAA,yDAGE,MAAA,KE7JF,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,UFqKJ,OACE,YAAA,EAAA,IAAA,EAAA,qBC3HA,mBAAA,MAAA,EAAA,IAAA,EAAA,sBAAA,EAAA,IAAA,IAAA,gBACQ,WAAA,MAAA,EAAA,IAAA,EAAA,sBAAA,EAAA,IAAA,IAAA,gBDsIV,eEtLI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF8KF,aAAA,QAKF,YEvLI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF8KF,aAAA,QAMF,eExLI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF8KF,aAAA,QAOF,cEzLI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF8KF,aAAA,QAeF,UEjMI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFuMJ,cE3MI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFwMJ,sBE5MI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFyMJ,mBE7MI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF0MJ,sBE9MI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF2MJ,qBE/MI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF+MJ,sBElLI,iBAAA,yKACA,iBAAA,oKACA,iBAAA,iKFyLJ,YACE,cAAA,IC9KA,mBAAA,EAAA,IAAA,IAAA,iBACQ,WAAA,EAAA,IAAA,IAAA,iBDgLV,wBAAA,8BAAA,8BAGE,YAAA,EAAA,KAAA,EAAA,QEnOE,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFiOF,aAAA,QALF,+BAAA,qCAAA,qCAQI,YAAA,KAUJ,OCnME,mBAAA,EAAA,IAAA,IAAA,gBACQ,WAAA,EAAA,IAAA,IAAA,gBD4MV,8BE5PI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFyPJ,8BE7PI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF0PJ,8BE9PI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF2PJ,2BE/PI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF4PJ,8BEhQI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SF6PJ,6BEjQI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFoQJ,MExQI,iBAAA,oDACA,iBAAA,+CACA,iBAAA,wEAAA,iBAAA,kDACA,OAAA,+GACA,kBAAA,SFsQF,aAAA,QC3NA,mBAAA,MAAA,EAAA,IAAA,IAAA,gBAAA,EAAA,IAAA,EAAA,qBACQ,WAAA,MAAA,EAAA,IAAA,IAAA,gBAAA,EAAA,IAAA,EAAA","sourcesContent":["/*!\n * Bootstrap v3.3.7 (http://getbootstrap.com)\n * Copyright 2011-2016 Twitter, Inc.\n * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)\n */\n\n//\n// Load core variables and mixins\n// --------------------------------------------------\n\n@import \"variables.less\";\n@import \"mixins.less\";\n\n\n//\n// Buttons\n// --------------------------------------------------\n\n// Common styles\n.btn-default,\n.btn-primary,\n.btn-success,\n.btn-info,\n.btn-warning,\n.btn-danger {\n text-shadow: 0 -1px 0 rgba(0,0,0,.2);\n @shadow: inset 0 1px 0 rgba(255,255,255,.15), 0 1px 1px rgba(0,0,0,.075);\n .box-shadow(@shadow);\n\n // Reset the shadow\n &:active,\n &.active {\n .box-shadow(inset 0 3px 5px rgba(0,0,0,.125));\n }\n\n &.disabled,\n &[disabled],\n fieldset[disabled] & {\n .box-shadow(none);\n }\n\n .badge {\n text-shadow: none;\n }\n}\n\n// Mixin for generating new styles\n.btn-styles(@btn-color: #555) {\n #gradient > .vertical(@start-color: @btn-color; @end-color: darken(@btn-color, 12%));\n .reset-filter(); // Disable gradients for IE9 because filter bleeds through rounded corners; see https://github.com/twbs/bootstrap/issues/10620\n background-repeat: repeat-x;\n border-color: darken(@btn-color, 14%);\n\n &:hover,\n &:focus {\n background-color: darken(@btn-color, 12%);\n background-position: 0 -15px;\n }\n\n &:active,\n &.active {\n background-color: darken(@btn-color, 12%);\n border-color: darken(@btn-color, 14%);\n }\n\n &.disabled,\n &[disabled],\n fieldset[disabled] & {\n &,\n &:hover,\n &:focus,\n &.focus,\n &:active,\n &.active {\n background-color: darken(@btn-color, 12%);\n background-image: none;\n }\n }\n}\n\n// Common styles\n.btn {\n // Remove the gradient for the pressed/active state\n &:active,\n &.active {\n background-image: none;\n }\n}\n\n// Apply the mixin to the buttons\n.btn-default { .btn-styles(@btn-default-bg); text-shadow: 0 1px 0 #fff; border-color: #ccc; }\n.btn-primary { .btn-styles(@btn-primary-bg); }\n.btn-success { .btn-styles(@btn-success-bg); }\n.btn-info { .btn-styles(@btn-info-bg); }\n.btn-warning { .btn-styles(@btn-warning-bg); }\n.btn-danger { .btn-styles(@btn-danger-bg); }\n\n\n//\n// Images\n// --------------------------------------------------\n\n.thumbnail,\n.img-thumbnail {\n .box-shadow(0 1px 2px rgba(0,0,0,.075));\n}\n\n\n//\n// Dropdowns\n// --------------------------------------------------\n\n.dropdown-menu > li > a:hover,\n.dropdown-menu > li > a:focus {\n #gradient > .vertical(@start-color: @dropdown-link-hover-bg; @end-color: darken(@dropdown-link-hover-bg, 5%));\n background-color: darken(@dropdown-link-hover-bg, 5%);\n}\n.dropdown-menu > .active > a,\n.dropdown-menu > .active > a:hover,\n.dropdown-menu > .active > a:focus {\n #gradient > .vertical(@start-color: @dropdown-link-active-bg; @end-color: darken(@dropdown-link-active-bg, 5%));\n background-color: darken(@dropdown-link-active-bg, 5%);\n}\n\n\n//\n// Navbar\n// --------------------------------------------------\n\n// Default navbar\n.navbar-default {\n #gradient > .vertical(@start-color: lighten(@navbar-default-bg, 10%); @end-color: @navbar-default-bg);\n .reset-filter(); // Remove gradient in IE<10 to fix bug where dropdowns don't get triggered\n border-radius: @navbar-border-radius;\n @shadow: inset 0 1px 0 rgba(255,255,255,.15), 0 1px 5px rgba(0,0,0,.075);\n .box-shadow(@shadow);\n\n .navbar-nav > .open > a,\n .navbar-nav > .active > a {\n #gradient > .vertical(@start-color: darken(@navbar-default-link-active-bg, 5%); @end-color: darken(@navbar-default-link-active-bg, 2%));\n .box-shadow(inset 0 3px 9px rgba(0,0,0,.075));\n }\n}\n.navbar-brand,\n.navbar-nav > li > a {\n text-shadow: 0 1px 0 rgba(255,255,255,.25);\n}\n\n// Inverted navbar\n.navbar-inverse {\n #gradient > .vertical(@start-color: lighten(@navbar-inverse-bg, 10%); @end-color: @navbar-inverse-bg);\n .reset-filter(); // Remove gradient in IE<10 to fix bug where dropdowns don't get triggered; see https://github.com/twbs/bootstrap/issues/10257\n border-radius: @navbar-border-radius;\n .navbar-nav > .open > a,\n .navbar-nav > .active > a {\n #gradient > .vertical(@start-color: @navbar-inverse-link-active-bg; @end-color: lighten(@navbar-inverse-link-active-bg, 2.5%));\n .box-shadow(inset 0 3px 9px rgba(0,0,0,.25));\n }\n\n .navbar-brand,\n .navbar-nav > li > a {\n text-shadow: 0 -1px 0 rgba(0,0,0,.25);\n }\n}\n\n// Undo rounded corners in static and fixed navbars\n.navbar-static-top,\n.navbar-fixed-top,\n.navbar-fixed-bottom {\n border-radius: 0;\n}\n\n// Fix active state of dropdown items in collapsed mode\n@media (max-width: @grid-float-breakpoint-max) {\n .navbar .navbar-nav .open .dropdown-menu > .active > a {\n &,\n &:hover,\n &:focus {\n color: #fff;\n #gradient > .vertical(@start-color: @dropdown-link-active-bg; @end-color: darken(@dropdown-link-active-bg, 5%));\n }\n }\n}\n\n\n//\n// Alerts\n// --------------------------------------------------\n\n// Common styles\n.alert {\n text-shadow: 0 1px 0 rgba(255,255,255,.2);\n @shadow: inset 0 1px 0 rgba(255,255,255,.25), 0 1px 2px rgba(0,0,0,.05);\n .box-shadow(@shadow);\n}\n\n// Mixin for generating new styles\n.alert-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 7.5%));\n border-color: darken(@color, 15%);\n}\n\n// Apply the mixin to the alerts\n.alert-success { .alert-styles(@alert-success-bg); }\n.alert-info { .alert-styles(@alert-info-bg); }\n.alert-warning { .alert-styles(@alert-warning-bg); }\n.alert-danger { .alert-styles(@alert-danger-bg); }\n\n\n//\n// Progress bars\n// --------------------------------------------------\n\n// Give the progress background some depth\n.progress {\n #gradient > .vertical(@start-color: darken(@progress-bg, 4%); @end-color: @progress-bg)\n}\n\n// Mixin for generating new styles\n.progress-bar-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 10%));\n}\n\n// Apply the mixin to the progress bars\n.progress-bar { .progress-bar-styles(@progress-bar-bg); }\n.progress-bar-success { .progress-bar-styles(@progress-bar-success-bg); }\n.progress-bar-info { .progress-bar-styles(@progress-bar-info-bg); }\n.progress-bar-warning { .progress-bar-styles(@progress-bar-warning-bg); }\n.progress-bar-danger { .progress-bar-styles(@progress-bar-danger-bg); }\n\n// Reset the striped class because our mixins don't do multiple gradients and\n// the above custom styles override the new `.progress-bar-striped` in v3.2.0.\n.progress-bar-striped {\n #gradient > .striped();\n}\n\n\n//\n// List groups\n// --------------------------------------------------\n\n.list-group {\n border-radius: @border-radius-base;\n .box-shadow(0 1px 2px rgba(0,0,0,.075));\n}\n.list-group-item.active,\n.list-group-item.active:hover,\n.list-group-item.active:focus {\n text-shadow: 0 -1px 0 darken(@list-group-active-bg, 10%);\n #gradient > .vertical(@start-color: @list-group-active-bg; @end-color: darken(@list-group-active-bg, 7.5%));\n border-color: darken(@list-group-active-border, 7.5%);\n\n .badge {\n text-shadow: none;\n }\n}\n\n\n//\n// Panels\n// --------------------------------------------------\n\n// Common styles\n.panel {\n .box-shadow(0 1px 2px rgba(0,0,0,.05));\n}\n\n// Mixin for generating new styles\n.panel-heading-styles(@color) {\n #gradient > .vertical(@start-color: @color; @end-color: darken(@color, 5%));\n}\n\n// Apply the mixin to the panel headings only\n.panel-default > .panel-heading { .panel-heading-styles(@panel-default-heading-bg); }\n.panel-primary > .panel-heading { .panel-heading-styles(@panel-primary-heading-bg); }\n.panel-success > .panel-heading { .panel-heading-styles(@panel-success-heading-bg); }\n.panel-info > .panel-heading { .panel-heading-styles(@panel-info-heading-bg); }\n.panel-warning > .panel-heading { .panel-heading-styles(@panel-warning-heading-bg); }\n.panel-danger > .panel-heading { .panel-heading-styles(@panel-danger-heading-bg); }\n\n\n//\n// Wells\n// --------------------------------------------------\n\n.well {\n #gradient > .vertical(@start-color: darken(@well-bg, 5%); @end-color: @well-bg);\n border-color: darken(@well-bg, 10%);\n @shadow: inset 0 1px 3px rgba(0,0,0,.05), 0 1px 0 rgba(255,255,255,.1);\n .box-shadow(@shadow);\n}\n","// Vendor Prefixes\n//\n// All vendor mixins are deprecated as of v3.2.0 due to the introduction of\n// Autoprefixer in our Gruntfile. They have been removed in v4.\n\n// - Animations\n// - Backface visibility\n// - Box shadow\n// - Box sizing\n// - Content columns\n// - Hyphens\n// - Placeholder text\n// - Transformations\n// - Transitions\n// - User Select\n\n\n// Animations\n.animation(@animation) {\n -webkit-animation: @animation;\n -o-animation: @animation;\n animation: @animation;\n}\n.animation-name(@name) {\n -webkit-animation-name: @name;\n animation-name: @name;\n}\n.animation-duration(@duration) {\n -webkit-animation-duration: @duration;\n animation-duration: @duration;\n}\n.animation-timing-function(@timing-function) {\n -webkit-animation-timing-function: @timing-function;\n animation-timing-function: @timing-function;\n}\n.animation-delay(@delay) {\n -webkit-animation-delay: @delay;\n animation-delay: @delay;\n}\n.animation-iteration-count(@iteration-count) {\n -webkit-animation-iteration-count: @iteration-count;\n animation-iteration-count: @iteration-count;\n}\n.animation-direction(@direction) {\n -webkit-animation-direction: @direction;\n animation-direction: @direction;\n}\n.animation-fill-mode(@fill-mode) {\n -webkit-animation-fill-mode: @fill-mode;\n animation-fill-mode: @fill-mode;\n}\n\n// Backface visibility\n// Prevent browsers from flickering when using CSS 3D transforms.\n// Default value is `visible`, but can be changed to `hidden`\n\n.backface-visibility(@visibility) {\n -webkit-backface-visibility: @visibility;\n -moz-backface-visibility: @visibility;\n backface-visibility: @visibility;\n}\n\n// Drop shadows\n//\n// Note: Deprecated `.box-shadow()` as of v3.1.0 since all of Bootstrap's\n// supported browsers that have box shadow capabilities now support it.\n\n.box-shadow(@shadow) {\n -webkit-box-shadow: @shadow; // iOS <4.3 & Android <4.1\n box-shadow: @shadow;\n}\n\n// Box sizing\n.box-sizing(@boxmodel) {\n -webkit-box-sizing: @boxmodel;\n -moz-box-sizing: @boxmodel;\n box-sizing: @boxmodel;\n}\n\n// CSS3 Content Columns\n.content-columns(@column-count; @column-gap: @grid-gutter-width) {\n -webkit-column-count: @column-count;\n -moz-column-count: @column-count;\n column-count: @column-count;\n -webkit-column-gap: @column-gap;\n -moz-column-gap: @column-gap;\n column-gap: @column-gap;\n}\n\n// Optional hyphenation\n.hyphens(@mode: auto) {\n word-wrap: break-word;\n -webkit-hyphens: @mode;\n -moz-hyphens: @mode;\n -ms-hyphens: @mode; // IE10+\n -o-hyphens: @mode;\n hyphens: @mode;\n}\n\n// Placeholder text\n.placeholder(@color: @input-color-placeholder) {\n // Firefox\n &::-moz-placeholder {\n color: @color;\n opacity: 1; // Override Firefox's unusual default opacity; see https://github.com/twbs/bootstrap/pull/11526\n }\n &:-ms-input-placeholder { color: @color; } // Internet Explorer 10+\n &::-webkit-input-placeholder { color: @color; } // Safari and Chrome\n}\n\n// Transformations\n.scale(@ratio) {\n -webkit-transform: scale(@ratio);\n -ms-transform: scale(@ratio); // IE9 only\n -o-transform: scale(@ratio);\n transform: scale(@ratio);\n}\n.scale(@ratioX; @ratioY) {\n -webkit-transform: scale(@ratioX, @ratioY);\n -ms-transform: scale(@ratioX, @ratioY); // IE9 only\n -o-transform: scale(@ratioX, @ratioY);\n transform: scale(@ratioX, @ratioY);\n}\n.scaleX(@ratio) {\n -webkit-transform: scaleX(@ratio);\n -ms-transform: scaleX(@ratio); // IE9 only\n -o-transform: scaleX(@ratio);\n transform: scaleX(@ratio);\n}\n.scaleY(@ratio) {\n -webkit-transform: scaleY(@ratio);\n -ms-transform: scaleY(@ratio); // IE9 only\n -o-transform: scaleY(@ratio);\n transform: scaleY(@ratio);\n}\n.skew(@x; @y) {\n -webkit-transform: skewX(@x) skewY(@y);\n -ms-transform: skewX(@x) skewY(@y); // See https://github.com/twbs/bootstrap/issues/4885; IE9+\n -o-transform: skewX(@x) skewY(@y);\n transform: skewX(@x) skewY(@y);\n}\n.translate(@x; @y) {\n -webkit-transform: translate(@x, @y);\n -ms-transform: translate(@x, @y); // IE9 only\n -o-transform: translate(@x, @y);\n transform: translate(@x, @y);\n}\n.translate3d(@x; @y; @z) {\n -webkit-transform: translate3d(@x, @y, @z);\n transform: translate3d(@x, @y, @z);\n}\n.rotate(@degrees) {\n -webkit-transform: rotate(@degrees);\n -ms-transform: rotate(@degrees); // IE9 only\n -o-transform: rotate(@degrees);\n transform: rotate(@degrees);\n}\n.rotateX(@degrees) {\n -webkit-transform: rotateX(@degrees);\n -ms-transform: rotateX(@degrees); // IE9 only\n -o-transform: rotateX(@degrees);\n transform: rotateX(@degrees);\n}\n.rotateY(@degrees) {\n -webkit-transform: rotateY(@degrees);\n -ms-transform: rotateY(@degrees); // IE9 only\n -o-transform: rotateY(@degrees);\n transform: rotateY(@degrees);\n}\n.perspective(@perspective) {\n -webkit-perspective: @perspective;\n -moz-perspective: @perspective;\n perspective: @perspective;\n}\n.perspective-origin(@perspective) {\n -webkit-perspective-origin: @perspective;\n -moz-perspective-origin: @perspective;\n perspective-origin: @perspective;\n}\n.transform-origin(@origin) {\n -webkit-transform-origin: @origin;\n -moz-transform-origin: @origin;\n -ms-transform-origin: @origin; // IE9 only\n transform-origin: @origin;\n}\n\n\n// Transitions\n\n.transition(@transition) {\n -webkit-transition: @transition;\n -o-transition: @transition;\n transition: @transition;\n}\n.transition-property(@transition-property) {\n -webkit-transition-property: @transition-property;\n transition-property: @transition-property;\n}\n.transition-delay(@transition-delay) {\n -webkit-transition-delay: @transition-delay;\n transition-delay: @transition-delay;\n}\n.transition-duration(@transition-duration) {\n -webkit-transition-duration: @transition-duration;\n transition-duration: @transition-duration;\n}\n.transition-timing-function(@timing-function) {\n -webkit-transition-timing-function: @timing-function;\n transition-timing-function: @timing-function;\n}\n.transition-transform(@transition) {\n -webkit-transition: -webkit-transform @transition;\n -moz-transition: -moz-transform @transition;\n -o-transition: -o-transform @transition;\n transition: transform @transition;\n}\n\n\n// User select\n// For selecting text on the page\n\n.user-select(@select) {\n -webkit-user-select: @select;\n -moz-user-select: @select;\n -ms-user-select: @select; // IE10+\n user-select: @select;\n}\n","// Gradients\n\n#gradient {\n\n // Horizontal gradient, from left to right\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .horizontal(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(left, @start-color @start-percent, @end-color @end-percent); // Opera 12\n background-image: linear-gradient(to right, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n background-repeat: repeat-x;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down\n }\n\n // Vertical gradient, from top to bottom\n //\n // Creates two color stops, start and end, by specifying a color and position for each color stop.\n // Color stops are not available in IE9 and below.\n .vertical(@start-color: #555; @end-color: #333; @start-percent: 0%; @end-percent: 100%) {\n background-image: -webkit-linear-gradient(top, @start-color @start-percent, @end-color @end-percent); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(top, @start-color @start-percent, @end-color @end-percent); // Opera 12\n background-image: linear-gradient(to bottom, @start-color @start-percent, @end-color @end-percent); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n background-repeat: repeat-x;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down\n }\n\n .directional(@start-color: #555; @end-color: #333; @deg: 45deg) {\n background-repeat: repeat-x;\n background-image: -webkit-linear-gradient(@deg, @start-color, @end-color); // Safari 5.1-6, Chrome 10+\n background-image: -o-linear-gradient(@deg, @start-color, @end-color); // Opera 12\n background-image: linear-gradient(@deg, @start-color, @end-color); // Standard, IE10, Firefox 16+, Opera 12.10+, Safari 7+, Chrome 26+\n }\n .horizontal-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n background-image: -o-linear-gradient(left, @start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(to right, @start-color, @mid-color @color-stop, @end-color);\n background-repeat: no-repeat;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=1)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n }\n .vertical-three-colors(@start-color: #00b3ee; @mid-color: #7a43b6; @color-stop: 50%; @end-color: #c3325f) {\n background-image: -webkit-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-image: -o-linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-image: linear-gradient(@start-color, @mid-color @color-stop, @end-color);\n background-repeat: no-repeat;\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(startColorstr='%d', endColorstr='%d', GradientType=0)\",argb(@start-color),argb(@end-color))); // IE9 and down, gets no color-stop at all for proper fallback\n }\n .radial(@inner-color: #555; @outer-color: #333) {\n background-image: -webkit-radial-gradient(circle, @inner-color, @outer-color);\n background-image: radial-gradient(circle, @inner-color, @outer-color);\n background-repeat: no-repeat;\n }\n .striped(@color: rgba(255,255,255,.15); @angle: 45deg) {\n background-image: -webkit-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n background-image: -o-linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n background-image: linear-gradient(@angle, @color 25%, transparent 25%, transparent 50%, @color 50%, @color 75%, transparent 75%, transparent);\n }\n}\n","// Reset filters for IE\n//\n// When you need to remove a gradient background, do not forget to use this to reset\n// the IE filter for IE9 and below.\n\n.reset-filter() {\n filter: e(%(\"progid:DXImageTransform.Microsoft.gradient(enabled = false)\"));\n}\n"]} -------------------------------------------------------------------------------- /public/css/bootstrap-3.3.7-dist/fonts/glyphicons-halflings-regular.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purpleru/AutoStudy/e08dabaa20cbace94c321c6393c61f8649eafe6c/public/css/bootstrap-3.3.7-dist/fonts/glyphicons-halflings-regular.eot -------------------------------------------------------------------------------- /public/css/bootstrap-3.3.7-dist/fonts/glyphicons-halflings-regular.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purpleru/AutoStudy/e08dabaa20cbace94c321c6393c61f8649eafe6c/public/css/bootstrap-3.3.7-dist/fonts/glyphicons-halflings-regular.ttf -------------------------------------------------------------------------------- /public/css/bootstrap-3.3.7-dist/fonts/glyphicons-halflings-regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purpleru/AutoStudy/e08dabaa20cbace94c321c6393c61f8649eafe6c/public/css/bootstrap-3.3.7-dist/fonts/glyphicons-halflings-regular.woff -------------------------------------------------------------------------------- /public/css/bootstrap-3.3.7-dist/fonts/glyphicons-halflings-regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purpleru/AutoStudy/e08dabaa20cbace94c321c6393c61f8649eafe6c/public/css/bootstrap-3.3.7-dist/fonts/glyphicons-halflings-regular.woff2 -------------------------------------------------------------------------------- /public/css/bootstrap-3.3.7-dist/js/npm.js: -------------------------------------------------------------------------------- 1 | // This file is autogenerated via the `commonjs` Grunt task. You can require() this file in a CommonJS environment. 2 | require('../../js/transition.js') 3 | require('../../js/alert.js') 4 | require('../../js/button.js') 5 | require('../../js/carousel.js') 6 | require('../../js/collapse.js') 7 | require('../../js/dropdown.js') 8 | require('../../js/modal.js') 9 | require('../../js/tooltip.js') 10 | require('../../js/popover.js') 11 | require('../../js/scrollspy.js') 12 | require('../../js/tab.js') 13 | require('../../js/affix.js') -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 8 | 自动学习 - 快速完成学习任务! 9 | 10 | 39 | 40 | 41 | 42 | 43 |
44 | 58 | 59 |
60 | 61 | 62 |
63 |
64 |

Message

65 |
66 |
67 | 时间从来不说话,却回答了所有问题! 68 |
69 | 70 |
71 | 75 | 76 |
77 |
78 |

登陆

79 |
80 |
81 |
82 | 83 | 87 | 88 | 92 |
93 | 94 |
95 |
96 | 98 |
99 | 100 |
101 |
102 | 103 |
104 |
105 | 107 |
108 |
109 | 110 | 135 | 136 | 137 | 138 | 148 | 149 |
150 | 151 | 154 | 157 |
158 | 159 | 160 | 161 | 165 |
166 |
167 |
168 | 169 | 188 | 189 |
190 |
191 | 192 | 193 | 194 | 195 | 196 | 197 | -------------------------------------------------------------------------------- /public/js/index.js: -------------------------------------------------------------------------------- 1 | function login(data) { 2 | 3 | if (data['code'] === 1000 || data['code'] === 200) { 4 | 5 | var $placeOption = $('#place option:checked'), 6 | $schoolOption = $('#schools option:checked'); 7 | 8 | localStorage.setItem('userInit', JSON.stringify({ 9 | login_name: user.val(), 10 | login_pwd: password.val(), 11 | login_type: getRadioVal('type'), 12 | userInfo: queryString.parse(Cookies.get('userInfo')), 13 | schoolInfo: { 14 | baseURL: $schoolOption.attr('data-baseURL'), 15 | urlHost: $placeOption.attr('data-urlHost'), 16 | placeId: $placeOption.prop('value'), 17 | placeName: $placeOption.text().trim(), 18 | schoolName: $schoolOption.text().trim() 19 | } 20 | })); 21 | 22 | $placeOption.parent().prop('disabled', true); 23 | $schoolOption.parent().prop('disabled', true); 24 | 25 | // 获取学期 26 | getSemester($('input[name="type"]:checked').val()); 27 | // 显示 28 | display('登陆成功,欢迎: ' + user.val() + ' 使用本程序!', true); 29 | 30 | } else { 31 | msg.show().find('span:last').html(data['message'] || data['msg'] || '登陆失败,出现未知错误!'); 32 | } 33 | } 34 | 35 | var user = $('#user'), 36 | password = $('#password'), 37 | msg = $('#msg'), 38 | queryString = { 39 | parse: function (str) { 40 | if (!str) return null; 41 | var strArr = str.split('&'), 42 | cookies = {}; 43 | strArr.forEach(function (item) { 44 | var itemArr = item.split('='), 45 | itemName = itemArr[0], 46 | itemValue = itemArr[1]; 47 | if (itemName) { 48 | cookies[itemName] = window.decodeURIComponent(itemValue || ''); 49 | } 50 | }); 51 | return cookies; 52 | }, 53 | stringify: function (target) { 54 | var ifys = []; 55 | for (var key in target) { 56 | var val = target[key] || ''; 57 | ifys.push(key + '=' + encodeURIComponent(val)); 58 | } 59 | return ifys.join('&'); 60 | } 61 | }; 62 | 63 | function display(msgStr, isShow) { 64 | user.prop('disabled', isShow || false); 65 | password.prop('disabled', isShow || false); 66 | $('[name=type]').prop('disabled', isShow || false); 67 | if (isShow) { 68 | msg.show().removeClass('alert-danger').find('span:first').removeClass('glyphicon-exclamation-sign'); 69 | $('[type="submit"]').hide(); 70 | $('#loginSuccess').slideDown(200, 'linear'); 71 | } else { 72 | $('[type="submit"]').show(); 73 | $('#loginSuccess').hide(); 74 | msg.show().addClass('alert-danger').find('span:first').addClass('glyphicon-exclamation-sign'); 75 | } 76 | 77 | msg.find('[data-msg="msg"]').html(msgStr); 78 | } 79 | 80 | function getUserInit(uname) { 81 | try { 82 | var userInit = JSON.parse(localStorage.getItem('userInit') || '{}'); 83 | } catch (err) { } 84 | 85 | if (uname) { 86 | return userInit[uname]; 87 | } else { 88 | return userInit; 89 | } 90 | } 91 | 92 | 93 | var userInit = getUserInit(); 94 | 95 | // 登陆状态 96 | var loginStatus; 97 | 98 | switch (userInit['login_type']) { 99 | case 'chaoxing': 100 | var UID = Cookies.get('UID'); 101 | if (UID) { 102 | loginStatus = { 103 | user_name: UID 104 | }; 105 | } 106 | $('input[value=chaoxing]').prop('checked', 'checked'); 107 | break; 108 | case 'lemon': 109 | var baseURL = userInit.schoolInfo.baseURL, 110 | schoolPrefix = baseURL.substr(baseURL.lastIndexOf('/') + 1), 111 | status = Cookies.get(schoolPrefix + '_student_COOKIE'); 112 | if (status) { 113 | loginStatus = userInit.userInfo; 114 | $('input[value=lemon]').prop('checked', 'checked'); 115 | } 116 | break; 117 | } 118 | 119 | if (loginStatus) { 120 | $('[name=type]').prop('disabled', true); 121 | user.val(userInit['login_name']); 122 | password.val(userInit['login_pwd']); 123 | // 获取学期 124 | getSemester($('input[name="type"]:checked').val()); 125 | // 显示 126 | display('欢迎 ' + loginStatus.user_name + ' 再次使用本程序!', true); 127 | } 128 | 129 | function getSemester(type) { 130 | var url; 131 | 132 | if (type === 'lemon') { 133 | url = '/lemonSchool/semester'; 134 | } else { 135 | url = 'chaoxing/course'; 136 | } 137 | 138 | var data = sessionStorage.getItem('data'); 139 | if (data) { 140 | success(JSON.parse(data)); 141 | } else { 142 | $.ajax({ 143 | url: url, 144 | success: success 145 | }); 146 | } 147 | 148 | 149 | function success(data) { 150 | 151 | if (data['code'] === 1000 || Array.isArray(data) || data['code'] === 200) { 152 | 153 | sessionStorage.setItem('data', JSON.stringify(data)); 154 | 155 | $('#semester').html(''); 156 | 157 | if (type === 'lemon') { 158 | lemon(data); 159 | } else { 160 | chaoxing(data); 161 | } 162 | $('#semester').parents('.form-group').show(); 163 | } else { 164 | $('#semester').parents('.form-group').hide() 165 | } 166 | } 167 | 168 | function lemon(data) { 169 | var arr = data.data; 170 | for (var i = 0; i < arr.length; i++) { 171 | 172 | for (var j = 0; j < arr.length - 1; j++) { 173 | 174 | if (arr[j] > arr[j + 1]) { 175 | var val = arr[j]; 176 | arr[j] = arr[j + 1]; 177 | arr[j + 1] = val; 178 | } 179 | } 180 | 181 | } 182 | 183 | $.each(arr, function (index, item) { 184 | var option = document.createElement('option'); 185 | option.innerText = '第' + item.term + '学期'; 186 | option.selected = item.isCurrentTerm; 187 | option.value = item.termCode; 188 | $('#semester').append(option); 189 | }); 190 | } 191 | 192 | function chaoxing(data) { 193 | var courseLists = data['data']; 194 | $('#semester').parents('.form-group').children('label').text('刷取课程:'); 195 | $.each(courseLists, function (index, item) { 196 | var option = document.createElement('option'); 197 | option.innerText = item.name; 198 | option.value = JSON.stringify(item); 199 | option.setAttribute('data-info', JSON.stringify(item)); 200 | $('#semester').append(option); 201 | }); 202 | 203 | } 204 | } 205 | 206 | 207 | function getRadioVal(uname) { 208 | var uname = document.getElementsByName(uname); 209 | for (var i = 0; i < uname.length; i++) { 210 | if (uname[i].checked) { 211 | return uname[i].value; 212 | } 213 | } 214 | return null; 215 | } 216 | 217 | 218 | var events = { 219 | // 立即刷取 220 | autoPlay: function () { 221 | 222 | var login_type = getUserInit('login_type'), 223 | url, term = $('#semester').val() || ''; 224 | console.log(term); 225 | 226 | switch (login_type) { 227 | case 'lemon': 228 | url = '/lemonSchool/autoplay?user=' + user.val() + '&term=' + term; 229 | break; 230 | case 'chaoxing': 231 | var info = JSON.parse(term); 232 | url = '/chaoxing/auto?' + queryString.stringify({ 233 | uname: user.val(), 234 | courseId: info['courseid'], 235 | clazzid: info['clazzid'], 236 | personid: info['personid'] 237 | }); 238 | break; 239 | } 240 | 241 | if (!url) return display('请重新登陆账号'); 242 | 243 | $.ajax({ 244 | url: url, 245 | success: function (data) { 246 | var code = data['code'], 247 | message = data['msg']; 248 | if (code == 200) { 249 | msg.show().removeClass('alert-danger').find('span:first').removeClass('glyphicon-exclamation-sign'); 250 | msg.find('[data-msg="msg"]').html(message + ',一般10分钟左右即可刷取完成!'); 251 | } else if (code == 201) { 252 | display('请重新登陆账号'); 253 | } else { 254 | msg.show().addClass('alert-danger').find('span:first').addClass('glyphicon-exclamation-sign'); 255 | msg.find('[data-msg="msg"]').html(message); 256 | } 257 | } 258 | }) 259 | }, 260 | loginOut: function () { 261 | if (confirm('你确定要退出当前账号吗?')) { 262 | Cookies.remove('openlearning_COOKIE'); 263 | Cookies.remove(schoolPrefix + '_student_COOKIE'); 264 | Cookies.remove('UID'); 265 | Cookies.remove('userInfo'); 266 | localStorage.removeItem('userInit'); 267 | sessionStorage.removeItem('data'); 268 | location.reload(); 269 | } 270 | } 271 | } 272 | 273 | // 绑定事件 274 | document.getElementById('loginSuccess').addEventListener('click', function (evnt) { 275 | if (this == evnt.target) return; 276 | var evntName = evnt.target.getAttribute('data-event'); 277 | for (var k in events) { 278 | if (k === evntName) { 279 | return events[k].call(evnt.target, evnt); 280 | } 281 | } 282 | }); 283 | 284 | function loginType(type, params) { 285 | var params = params || {}, 286 | user = params['user'], 287 | pwd = params['pwd']; 288 | 289 | switch (type) { 290 | case 'lemon': 291 | return '/lemonSchool/login?user=' + user + '&pwd=' + pwd; 292 | case 'chaoxing': 293 | return '/chaoxing/login?uname=' + user + '&password=' + pwd; 294 | default: 295 | return null 296 | } 297 | } 298 | 299 | function lemonInit(el) { 300 | 301 | var $el = $(el), $place = $el.find('#place'), $school = $el.find('#schools'), schoolInfo = userInit.schoolInfo || {}; 302 | 303 | $el.show(); 304 | 305 | function renderSchoolLists($container, schoolLists) { 306 | $container.empty(); 307 | $.each(schoolLists, function (index, item) { 308 | var $option = $(''); 309 | $option.prop('value', item.value); 310 | $option.html(item.text); 311 | $option.attr('data-baseURL', item.value); 312 | $option.prop('selected', item.value === schoolInfo.baseURL); 313 | $container.append($option); 314 | }); 315 | } 316 | 317 | function renderPlaces($container, places) { 318 | $container.empty(); 319 | $container.append($('')); 320 | $.each(places, function (index, item) { 321 | var $option = $(''); 322 | $option.prop('value', item.placeId); 323 | $option.html(item.placeName); 324 | $option.attr('data-urlHost', 'http://' + item.urlHost); 325 | $option.prop('selected', item.placeId === schoolInfo.placeId); 326 | $container.append($option); 327 | }); 328 | } 329 | 330 | if (loginStatus) { 331 | var places = JSON.parse(localStorage.getItem('places')), 332 | schoolLists = JSON.parse(localStorage.getItem('schoolLists')); 333 | renderPlaces($place, places); 334 | renderSchoolLists($school, schoolLists); 335 | $place.prop('disabled', true); 336 | $school.prop('disabled', true); 337 | return false; 338 | } 339 | 340 | function getSchollLists($option) { 341 | var urlHost = Cookies.get('urlHost'); 342 | $.get('/lemonSchool/schoollist', { 343 | place_id: $option.prop('value'), 344 | urlHost: urlHost 345 | }, function (data) { 346 | var schoolLists = data['data']; 347 | if (data.code === 1000) { 348 | renderSchoolLists($school, schoolLists); 349 | localStorage.setItem('schoolLists', JSON.stringify(schoolLists)); 350 | var $checkedOption = $school.find('option:checked'); 351 | Cookies.set('baseURL', $checkedOption.attr('data-baseURL'), { expires: 30 }); 352 | } 353 | 354 | }); 355 | } 356 | 357 | // 省份 358 | $.get('/lemonSchool/portal', function (data) { 359 | var places = JSON.parse(data)['data']; 360 | renderPlaces($place, places); 361 | localStorage.setItem('places', JSON.stringify(places)); 362 | var $checkedOption = $place.find('option:checked'); 363 | Cookies.set('urlHost', $checkedOption.attr('data-urlHost'), { expires: 30 }); 364 | getSchollLists($checkedOption); 365 | }); 366 | 367 | $place.on('change', function () { 368 | var $checkedOption = $place.find('option:checked'); 369 | Cookies.set('urlHost', $checkedOption.attr('data-urlHost'), { expires: 30 }); 370 | getSchollLists($checkedOption); 371 | }); 372 | 373 | $school.on('change', function () { 374 | Cookies.set('baseURL', this.value, { expires: 30 }); 375 | }); 376 | 377 | } 378 | 379 | function init() { 380 | var loginPlatform = $('#loginPlatform input:radio:checked').prop('value'); 381 | 382 | switch (loginPlatform) { 383 | case 'lemon': 384 | lemonInit('#entry'); 385 | break; 386 | } 387 | 388 | } 389 | 390 | $(function () { 391 | 392 | init(); 393 | 394 | $('#loginPlatform').on('click', 'input:radio', function () { 395 | var loginPlatform = $(this).prop('value'); 396 | if (loginPlatform !== 'lemon') { 397 | $('#entry').fadeOut(); 398 | } else { 399 | if ($('#place').prop('value')) { 400 | $('#entry').fadeIn(); 401 | } else { 402 | init(); 403 | } 404 | 405 | } 406 | }); 407 | 408 | $('#login').on('submit', function (e) { 409 | var loginPlatform = $('#loginPlatform input:radio:checked').prop('value'); 410 | 411 | if (user.val().trim().length === 0) { 412 | msg.fadeIn().find('span:last').html('请输入账号'); 413 | return false; 414 | } else if (password.val().trim().length === 0) { 415 | msg.fadeIn().find('span:last').html('请输入密码'); 416 | return false; 417 | } else if (loginPlatform === 'lemon') { 418 | var urlHost = Cookies.get('urlHost') || '', 419 | baseURL = Cookies.get('baseURL') || ''; 420 | if (urlHost.length === 0 || baseURL.length === 0) { 421 | msg.fadeIn().find('span:last').html('请输选择学校平台'); 422 | return false; 423 | } 424 | } 425 | 426 | var url = loginType(getRadioVal('type'), { 427 | user: user.val(), 428 | pwd: password.val() 429 | }); 430 | 431 | if (!url) { 432 | msg.fadeIn().find('span:last').html('亲,请先选择要登陆的平台!'); 433 | return false; 434 | } 435 | msg.hide(); 436 | 437 | $.ajax({ 438 | url: url, 439 | success: login, 440 | beforeSend: function () { $('[type="submit"]').prop('disabled', true); }, 441 | complete: function () { $('[type="submit"]').prop('disabled', false); } 442 | }); 443 | return false; 444 | }); 445 | 446 | 447 | }); -------------------------------------------------------------------------------- /public/js/js-cookie.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * JavaScript Cookie v2.2.1 3 | * https://github.com/js-cookie/js-cookie 4 | * 5 | * Copyright 2006, 2015 Klaus Hartl & Fagner Brack 6 | * Released under the MIT license 7 | */ 8 | ; 9 | (function(factory) { 10 | var registeredInModuleLoader; 11 | if (typeof define === 'function' && define.amd) { 12 | define(factory); 13 | registeredInModuleLoader = true; 14 | } 15 | if (typeof exports === 'object') { 16 | module.exports = factory(); 17 | registeredInModuleLoader = true; 18 | } 19 | if (!registeredInModuleLoader) { 20 | var OldCookies = window.Cookies; 21 | var api = window.Cookies = factory(); 22 | api.noConflict = function() { 23 | window.Cookies = OldCookies; 24 | return api; 25 | }; 26 | } 27 | }(function() { 28 | function extend() { 29 | var i = 0; 30 | var result = {}; 31 | for (; i < arguments.length; i++) { 32 | var attributes = arguments[i]; 33 | for (var key in attributes) { 34 | result[key] = attributes[key]; 35 | } 36 | } 37 | return result; 38 | } 39 | 40 | function decode(s) { 41 | return s.replace(/(%[0-9A-Z]{2})+/g, decodeURIComponent); 42 | } 43 | 44 | function init(converter) { 45 | function api() {} 46 | 47 | function set(key, value, attributes) { 48 | if (typeof document === 'undefined') { 49 | return; 50 | } 51 | 52 | attributes = extend({ 53 | path: '/' 54 | }, api.defaults, attributes); 55 | 56 | if (typeof attributes.expires === 'number') { 57 | attributes.expires = new Date(new Date() * 1 + attributes.expires * 864e+5); 58 | } 59 | 60 | // We're using "expires" because "max-age" is not supported by IE 61 | attributes.expires = attributes.expires ? attributes.expires.toUTCString() : ''; 62 | 63 | try { 64 | var result = JSON.stringify(value); 65 | if (/^[\{\[]/.test(result)) { 66 | value = result; 67 | } 68 | } catch (e) {} 69 | 70 | value = converter.write ? 71 | converter.write(value, key) : 72 | encodeURIComponent(String(value)) 73 | .replace(/%(23|24|26|2B|3A|3C|3E|3D|2F|3F|40|5B|5D|5E|60|7B|7D|7C)/g, decodeURIComponent); 74 | 75 | key = encodeURIComponent(String(key)) 76 | .replace(/%(23|24|26|2B|5E|60|7C)/g, decodeURIComponent) 77 | .replace(/[\(\)]/g, escape); 78 | 79 | var stringifiedAttributes = ''; 80 | for (var attributeName in attributes) { 81 | if (!attributes[attributeName]) { 82 | continue; 83 | } 84 | stringifiedAttributes += '; ' + attributeName; 85 | if (attributes[attributeName] === true) { 86 | continue; 87 | } 88 | 89 | // Considers RFC 6265 section 5.2: 90 | // ... 91 | // 3. If the remaining unparsed-attributes contains a %x3B (";") 92 | // character: 93 | // Consume the characters of the unparsed-attributes up to, 94 | // not including, the first %x3B (";") character. 95 | // ... 96 | stringifiedAttributes += '=' + attributes[attributeName].split(';')[0]; 97 | } 98 | 99 | return (document.cookie = key + '=' + value + stringifiedAttributes); 100 | } 101 | 102 | function get(key, json) { 103 | if (typeof document === 'undefined') { 104 | return; 105 | } 106 | 107 | var jar = {}; 108 | // To prevent the for loop in the first place assign an empty array 109 | // in case there are no cookies at all. 110 | var cookies = document.cookie ? document.cookie.split('; ') : []; 111 | var i = 0; 112 | 113 | for (; i < cookies.length; i++) { 114 | var parts = cookies[i].split('='); 115 | var cookie = parts.slice(1).join('='); 116 | 117 | if (!json && cookie.charAt(0) === '"') { 118 | cookie = cookie.slice(1, -1); 119 | } 120 | 121 | try { 122 | var name = decode(parts[0]); 123 | cookie = (converter.read || converter)(cookie, name) || 124 | decode(cookie); 125 | 126 | if (json) { 127 | try { 128 | cookie = JSON.parse(cookie); 129 | } catch (e) {} 130 | } 131 | 132 | jar[name] = cookie; 133 | 134 | if (key === name) { 135 | break; 136 | } 137 | } catch (e) {} 138 | } 139 | 140 | return key ? jar[key] : jar; 141 | } 142 | 143 | api.set = set; 144 | api.get = function(key) { 145 | return get(key, false /* read as raw */ ); 146 | }; 147 | api.getJSON = function(key) { 148 | return get(key, true /* read as json */ ); 149 | }; 150 | api.remove = function(key, attributes) { 151 | set(key, '', extend(attributes, { 152 | expires: -1 153 | })); 154 | }; 155 | 156 | api.defaults = {}; 157 | 158 | api.withConverter = init; 159 | 160 | return api; 161 | } 162 | 163 | return init(function() {}); 164 | })); -------------------------------------------------------------------------------- /public/test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 | 12 | 13 | 14 | 46 | 47 | 48 | 49 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # 自动学习 2 | 3 | ## 工作原理 4 | 5 | - 跨站请求伪造 (CSRF), 伪造请求头 , 调用官方 API 6 | 7 | ## 项目介绍 8 | 9 | - 这是一个能够快速完成你的大学课程的项目,目前实现了两个课程平台(超星学习通和柠檬学堂) 10 | - 如果使用过程中出现任何问题,可以联系我wx:wx_v988(良言一句三冬暖,恶语伤人六月寒) 11 | - 项目API接口文档:https://docs.apipost.cn/preview/0e16a078ec779fbb/d742afe1e625f5ec 12 | 13 | ## 注意项 14 | 15 | - 本项目不提供线上 demo,请不要轻易信任使用他人提供的公开服务,以免发生安全问题,泄露自己的账号和密码 16 | 17 | - 本项目仅供学习使用,请尊重版权,请勿利用此项目从事商业行为或进行破坏版权行为 18 | 19 | ## 运行 20 | 21 | - 拉取本项目,使用 `npm install` 下载依赖包。 22 | - 安装MongoDB数据库,确保MongoDB服务正在运行。 23 | - 使用 `node` 命令启动根目录下的 `servr.js` 文件。 24 | - 浏览器访问 `http://127.0.0.1:3001` 默认端口为 `3001` 25 | 26 | 27 | ## 项目效果 28 | 29 | [点我前往查看GIF动态演示图](http://www.wgudu.com/wp-content/uploads/Rec-0002.gif) 30 | 31 | ![](./upload/img.jpg) 32 | 33 | ### 柠檬文才 34 | 35 | ![](./upload/new_01.jpg) 36 | 37 | ![](./upload/new_02.jpg) 38 | 39 | ![](./upload/new_03.jpg) -------------------------------------------------------------------------------- /server.js: -------------------------------------------------------------------------------- 1 | const express = require('express'); 2 | 3 | const app = express(); 4 | 5 | const cookieParser = require('cookie-parser'); 6 | 7 | const path = require('path'); 8 | 9 | // 端口 10 | const port = 3001; 11 | 12 | require('./mongo/mongodb'); 13 | 14 | app.use(express.static(path.join(__dirname, 'public'))); 15 | 16 | app.use(cookieParser()); 17 | 18 | // 超星 19 | app.use('/chaoxing', require('./modules/chaoxing/chaoxingRoute')); 20 | 21 | // 柠檬学堂 22 | app.use('/lemonSchool', require('./modules/lemonSchool/lemonSchoolRoute')); 23 | 24 | app.listen(port, function() { 25 | console.log(`服务启动成功 地址:http://127.0.0.1:${port}`); 26 | }); -------------------------------------------------------------------------------- /tools/HttpRequest.js: -------------------------------------------------------------------------------- 1 | const url = require('url'); 2 | 3 | // 用于调试 4 | const isDebug = false; 5 | 6 | function HttpRequest() { 7 | this.responseText = ''; 8 | // this.responseURL = ''; 9 | this.statusText = ''; 10 | this.responseHeaders = ''; 11 | this.requestURL = ''; 12 | this.onload = null; 13 | this.onerror = null; 14 | this.requestConfig = { 15 | headers: {}, 16 | // insecureHTTPParse: true 17 | }; 18 | } 19 | 20 | 21 | function open(method, httpUrl) { 22 | 23 | this.requestURL = httpUrl; 24 | 25 | method = method.toUpperCase(); 26 | 27 | if (method == 'GET' || method == 'POST') { 28 | this.requestConfig.method = method; 29 | } else { 30 | throw new Error('Request Method Error!'); 31 | } 32 | 33 | httpUrl = new url.URL(httpUrl); 34 | 35 | this.requestConfig.host = httpUrl.hostname; 36 | this.requestConfig.path = httpUrl.pathname + httpUrl.search; 37 | this.requestConfig.port = httpUrl.port; 38 | this.requestConfig.protocol = httpUrl.protocol; 39 | // console.log(httpUrl); 40 | 41 | } 42 | 43 | function send(postData) { 44 | var http; 45 | 46 | if (!this.requestConfig.host) { 47 | throw new Error('The send method cannot be called without calling open!'); 48 | 49 | } 50 | 51 | if (this.requestConfig.protocol === 'http:') { 52 | http = require('http'); 53 | // this.requestConfig.agent = new http.Agent({ keepAlive: true }); 54 | } else { 55 | http = require('https'); 56 | 57 | } 58 | // this.requestConfig.agent = new http.Agent({ keepAlive: true }); 59 | // console.log(http.globalAgent); 60 | 61 | const req = http.request(this.requestConfig, (res) => { 62 | 63 | var resData = ''; 64 | 65 | res.on('data', data => { 66 | resData += data 67 | }); 68 | 69 | res.on('end', () => { 70 | this.statusText = res.statusMessage; 71 | this.status = res.statusCode; 72 | this.responseHeaders = res.headers; 73 | // this.responseURL = ; 74 | this.responseText = resData; 75 | this.onload && this.onload({ 76 | aborted: res.aborted, 77 | upgrade: res.upgrade, 78 | complete: res.complete, 79 | httpVersion: res.httpVersion, 80 | target: this 81 | }); 82 | }); 83 | 84 | }); 85 | 86 | postData && req.write(postData); 87 | 88 | req.on('error', err => { 89 | this.onerror && this.onerror(err, this); 90 | }); 91 | 92 | req.end(); 93 | 94 | if (isDebug) { 95 | console.log(postData); 96 | console.log(this.requestConfig); 97 | } 98 | 99 | delete this.requestConfig; 100 | } 101 | 102 | function setRequestHeader(requestHeaderKey, requestHeaderValue) { 103 | 104 | this.requestConfig.headers[requestHeaderKey] = requestHeaderValue; 105 | } 106 | 107 | function getAllResponseHeaders() { 108 | return this.responseHeaders; 109 | } 110 | 111 | function getResponseHeader(key) { 112 | return this.responseHeaders[key]; 113 | } 114 | 115 | HttpRequest.prototype = { 116 | constructor: HttpRequest, 117 | open, 118 | send, 119 | setRequestHeader, 120 | getAllResponseHeaders, 121 | getResponseHeader 122 | }; 123 | 124 | 125 | module.exports = { 126 | HttpRequest, 127 | HttpRequestConfig: (req, res, next) => { 128 | HttpRequest.prototype.next = next; 129 | next(); 130 | } 131 | }; -------------------------------------------------------------------------------- /tools/request.js: -------------------------------------------------------------------------------- 1 | const { HttpRequest } = require('./HttpRequest'); 2 | 3 | function ajax(options) { 4 | 5 | if (Object.prototype.toLocaleString.call(options) != '[object Object]') { 6 | throw new Error('Options is not a valid option!'); 7 | } 8 | 9 | var defaults = { 10 | method: 'get', 11 | headers: {} 12 | }; 13 | 14 | if (options.headers && Object.keys(options.headers).length > 0 && Object.prototype.toLocaleString.call(options.headers) === '[object Object]') { 15 | for (let key in options.headers) { 16 | defaults.headers[key.toLowerCase()] = options.headers[key] || ''; 17 | } 18 | delete options.headers; 19 | } 20 | 21 | Object.assign(defaults, options); 22 | 23 | var xhr = new HttpRequest(); 24 | 25 | // 设置请求头 26 | for (let key in defaults.headers) { 27 | xhr.setRequestHeader(key, defaults.headers[key]); 28 | } 29 | 30 | defaults.method = defaults.method.toLowerCase(); 31 | 32 | var contentType = defaults.headers['content-type'] || ''; 33 | 34 | if (!contentType && defaults.method === 'post') { 35 | contentType = 'application/x-www-form-urlencoded'; 36 | } 37 | 38 | if (contentType.includes('application/json') && defaults.method === 'post') { 39 | defaults.data = JSON.stringify(defaults.data); 40 | } else { 41 | var str = ''; 42 | for (let key in defaults.data) { 43 | str += key + '=' + defaults.data[key] + '&'; 44 | } 45 | defaults.data = str.substr(0, str.length - 1); 46 | } 47 | 48 | contentType && xhr.setRequestHeader('content-type', contentType); 49 | 50 | if (defaults.method === 'get' && str) { 51 | defaults.url = defaults.url + '?' + defaults.data; 52 | } 53 | 54 | xhr.open(defaults.method, defaults.url); 55 | 56 | xhr.onload = function() { 57 | // var resContentType = this.getResponseHeader('content-type') && this.getResponseHeader('content-type').search(/^application\/json/i) != -1 ? true : false; 58 | 59 | if (true) { 60 | try { 61 | this.responseText = JSON.parse(this.responseText); 62 | } catch (e) {} 63 | 64 | } 65 | 66 | if (this.status >= 200 && this.status <= 302) { 67 | defaults.success && defaults.success(xhr.responseText, xhr); 68 | } else { 69 | defaults.error && defaults.error(xhr.responseText, xhr); 70 | } 71 | } 72 | 73 | xhr.onerror = function(err, xhr) { 74 | // console.log(err); 75 | console.log('远程服务器 ' + xhr.requestURL + '可能出现 DNS 解析错误、TCP 层的错误、或实际的 HTTP 解析错误'); 76 | if (typeof defaults.onerror == 'function') { 77 | defaults.onerror(err, xhr); 78 | } else { 79 | defaults.error && defaults.error(err, xhr); 80 | } 81 | } 82 | 83 | if (defaults.method === 'post') { 84 | xhr.send(defaults.data); 85 | } else { 86 | xhr.send(); 87 | } 88 | 89 | } 90 | 91 | function post() { 92 | ajax({ 93 | method: 'post', 94 | data: arguments[1], 95 | url: arguments[0], 96 | success: (data, xhr) => { 97 | if (arguments[2] instanceof Function) { 98 | arguments[2](data, xhr); 99 | } 100 | } 101 | }); 102 | } 103 | 104 | function get() { 105 | 106 | var i = 2; 107 | 108 | if (arguments[1] instanceof Function) { 109 | i = 1; 110 | } 111 | 112 | ajax({ 113 | method: 'get', 114 | data: i === 1 ? {} : arguments[1], 115 | url: arguments[0], 116 | success: (data, xhr) => { 117 | if (arguments[i] instanceof Function) { 118 | arguments[i](data, xhr); 119 | } 120 | } 121 | }); 122 | } 123 | 124 | // 深拷贝 125 | function copyObject(newObject, coverObject) { 126 | for (var k in coverObject) { 127 | var coverObjectValue = coverObject[k]; 128 | if (Array.isArray(coverObjectValue)) { 129 | newObject[k] = []; 130 | copyObject(newObject[k], coverObjectValue); 131 | } else if (coverObject instanceof Object) { 132 | newObject[k] = {}; 133 | copyObject(newObject[k], coverObjectValue); 134 | } else { 135 | newObject[k] = coverObject[k]; 136 | } 137 | } 138 | } 139 | 140 | function asynAjax(options = {}) { 141 | // var { url, method, headers, data } = options; 142 | return new Promise(function(resolve, reject) { 143 | ajax({ 144 | ...options, 145 | success: function(data, xhr) { 146 | resolve({ 147 | data, 148 | xhr 149 | }); 150 | }, 151 | error: function(err) { 152 | reject(err); 153 | } 154 | }) 155 | }); 156 | } 157 | module.exports = { 158 | ajax, 159 | post, 160 | get, 161 | asynAjax 162 | } -------------------------------------------------------------------------------- /tools/tools.js: -------------------------------------------------------------------------------- 1 | function deURI(deuri) { 2 | for (var k in deuri) { 3 | deuri[k] = deuri[k] && decodeURIComponent(deuri[k]); 4 | } 5 | return deuri; 6 | } 7 | 8 | // 对象转cookie字符串 9 | function cookieStringify(cookie) { 10 | if (!(cookie instanceof Object && Object.keys(cookie).length > 0)) return ''; 11 | return Object.keys(cookie).map((value) => 12 | cookie[value] && encodeURIComponent(value) + '=' + encodeURIComponent(cookie[value]) 13 | ).join(';'); 14 | } 15 | 16 | // 解析cookie数组为对象,去重复 17 | function cookieParse(cookieArr) { 18 | var cookies = {}; 19 | if (Array.isArray(cookieArr)) { 20 | 21 | // 以后尽量不要用for in 遍历数组,因为for in 会遍历到原始链中自己添加的属性,原生的并不会遍历到。 22 | // for (var k in cookieArr) { 23 | // var { name, value } = cookieArr[k]; 24 | // cookies[name] = value; 25 | // } 26 | 27 | cookieArr.forEach((item) => { 28 | var { name, value } = item; 29 | cookies[name] = value; 30 | }) 31 | 32 | } else if (typeof cookieArr === 'string') { 33 | cookieArr.split(';').forEach(item => { 34 | const name = item.split('=')[0]; 35 | const value = item.split('=')[1]; 36 | cookies[name] = value; 37 | }); 38 | } 39 | 40 | // return Object.keys(cookies).length > 0 ? cookies : ''; 41 | return cookies; 42 | } 43 | 44 | function findKey(target, keyName, flags) { 45 | 46 | var reg = new RegExp(keyName, flags) 47 | 48 | for (var key in target) { 49 | if (reg.test(key)) return target[key]; 50 | } 51 | 52 | return null; 53 | } 54 | 55 | 56 | module.exports = { 57 | deURI, 58 | cookieStringify, 59 | cookieParse, 60 | findKey 61 | } -------------------------------------------------------------------------------- /upload/Rec 0002.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purpleru/AutoStudy/e08dabaa20cbace94c321c6393c61f8649eafe6c/upload/Rec 0002.gif -------------------------------------------------------------------------------- /upload/img.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purpleru/AutoStudy/e08dabaa20cbace94c321c6393c61f8649eafe6c/upload/img.jpg -------------------------------------------------------------------------------- /upload/new_01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purpleru/AutoStudy/e08dabaa20cbace94c321c6393c61f8649eafe6c/upload/new_01.jpg -------------------------------------------------------------------------------- /upload/new_02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purpleru/AutoStudy/e08dabaa20cbace94c321c6393c61f8649eafe6c/upload/new_02.jpg -------------------------------------------------------------------------------- /upload/new_03.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/purpleru/AutoStudy/e08dabaa20cbace94c321c6393c61f8649eafe6c/upload/new_03.jpg --------------------------------------------------------------------------------