├── .gitignore ├── LICENSE ├── README.md ├── config.sample.js ├── index.js ├── package.json └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.gitignore.io/api/node 3 | # Edit at https://www.gitignore.io/?templates=node 4 | 5 | ### Node ### 6 | # Logs 7 | logs 8 | *.log 9 | npm-debug.log* 10 | yarn-debug.log* 11 | yarn-error.log* 12 | lerna-debug.log* 13 | 14 | # Diagnostic reports (https://nodejs.org/api/report.html) 15 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 16 | 17 | # Runtime data 18 | pids 19 | *.pid 20 | *.seed 21 | *.pid.lock 22 | 23 | # Directory for instrumented libs generated by jscoverage/JSCover 24 | lib-cov 25 | 26 | # Coverage directory used by tools like istanbul 27 | coverage 28 | *.lcov 29 | 30 | # nyc test coverage 31 | .nyc_output 32 | 33 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 34 | .grunt 35 | 36 | # Bower dependency directory (https://bower.io/) 37 | bower_components 38 | 39 | # node-waf configuration 40 | .lock-wscript 41 | 42 | # Compiled binary addons (https://nodejs.org/api/addons.html) 43 | build/Release 44 | 45 | # Dependency directories 46 | node_modules/ 47 | jspm_packages/ 48 | 49 | # TypeScript v1 declaration files 50 | typings/ 51 | 52 | # TypeScript cache 53 | *.tsbuildinfo 54 | 55 | # Optional npm cache directory 56 | .npm 57 | 58 | # Optional eslint cache 59 | .eslintcache 60 | 61 | # Optional REPL history 62 | .node_repl_history 63 | 64 | # Output of 'npm pack' 65 | *.tgz 66 | 67 | # Yarn Integrity file 68 | .yarn-integrity 69 | 70 | # dotenv environment variables file 71 | .env 72 | .env.test 73 | 74 | # parcel-bundler cache (https://parceljs.org/) 75 | .cache 76 | 77 | # next.js build output 78 | .next 79 | 80 | # nuxt.js build output 81 | .nuxt 82 | 83 | # rollup.js default build output 84 | dist/ 85 | 86 | # Uncomment the public line if your project uses Gatsby 87 | # https://nextjs.org/blog/next-9-1#public-directory-support 88 | # https://create-react-app.dev/docs/using-the-public-folder/#docsNav 89 | # public 90 | 91 | # Storybook build outputs 92 | .out 93 | .storybook-out 94 | 95 | # vuepress build output 96 | .vuepress/dist 97 | 98 | # Serverless directories 99 | .serverless/ 100 | 101 | # FuseBox cache 102 | .fusebox/ 103 | 104 | # DynamoDB Local files 105 | .dynamodb/ 106 | 107 | # Temporary folders 108 | tmp/ 109 | temp/ 110 | 111 | # End of https://www.gitignore.io/api/node 112 | 113 | config.js 114 | *.json 115 | secret/* 116 | log/* 117 | test.js 118 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Konano 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # thu-weblearn-tgbot 2 | 3 | 实时监控网络学堂的 Telegram Bot 4 | 5 | ## Usage 6 | 7 | ``` 8 | $ cp config.example.js config.js 9 | $ vim config.js 10 | $ ... # 修改 config.js 配置文件 11 | $ yarn # 安装依赖 12 | $ node index.js # 运行 13 | ``` 14 | -------------------------------------------------------------------------------- /config.sample.js: -------------------------------------------------------------------------------- 1 | export let config = { 2 | debug: true, 3 | name: 'THULearnBot', 4 | token: '000000000:XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX', 5 | owner: '000000000', 6 | channel: '-100000000000', // or '@xxxxxx' 7 | apiproxy: 'tg.nano.ac', // or api.telegram.org 8 | user: { 9 | name: '', 10 | pwd: '', 11 | }, 12 | semesters: ['2021-2022-1'] 13 | }; 14 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | import { readFileSync, writeFileSync } from 'fs'; 2 | import { htmlToText } from 'html-to-text'; 3 | import { Learn2018Helper } from 'thu-learn-lib'; 4 | import moment from 'moment'; 5 | import { request } from 'https'; 6 | import { stringify } from 'querystring'; 7 | import pkg from 'log4js'; 8 | const { configure, getLogger } = pkg; 9 | 10 | import { config } from './config.js'; 11 | 12 | configure({ 13 | appenders: { 14 | stdout: { type: 'stdout' }, 15 | stderr: { type: 'stderr' }, 16 | logfile: { type: 'file', filename: 'log/runtime.log', maxLogSize: 1024 * 128, backups: 10 }, 17 | stdoutFilter: { type: 'logLevelFilter', level: 'info', maxLevel: 'warn', appender: 'stdout' }, 18 | stderrFilter: { type: 'logLevelFilter', level: 'error', appender: 'stderr' }, 19 | fileFilter: { type: 'logLevelFilter', level: 'debug', appender: 'logfile' } 20 | }, 21 | categories: { 22 | default: { appenders: ['stdoutFilter', 'stderrFilter', 'fileFilter'], level: 'debug' } 23 | } 24 | }); 25 | const logger = getLogger('default'); 26 | 27 | function sendMessage(msg, errmsg) { 28 | logger.debug('sendMessage Start'); 29 | try { 30 | const params = { 31 | chat_id: config.channel, 32 | text: msg, 33 | parse_mode: 'Markdown' 34 | }; 35 | const options = { 36 | hostname: config.apiproxy, 37 | port: 443, 38 | path: `/bot${config.token}/sendMessage?${stringify(params)}`, 39 | method: 'GET' 40 | }; 41 | request(options, res => { 42 | logger.debug(`statusCode: ${res.statusCode}`); 43 | res.on('data', d => { logger.debug(d.toString()) }) 44 | }).on('error', error => { 45 | logger.debug('request error'); 46 | logger.debug(error); 47 | logger.error(errmsg); 48 | delay(10 * 1000).then(() => { 49 | sendMessage(msg, errmsg); 50 | }); 51 | }).end(() => { 52 | logger.debug('request end'); 53 | }); 54 | } catch (err) { 55 | logger.error(err); 56 | } 57 | logger.debug('sendMessage Return'); 58 | } 59 | 60 | const helper = new Learn2018Helper({ provider: () => { return { username: config.user.name, password: config.user.pwd }; } }); 61 | 62 | async function delay(ms) { 63 | return await new Promise(resolve => setTimeout(resolve, ms)); 64 | } 65 | 66 | function findCourse(predata, courseID) { 67 | let ret = null; 68 | predata.forEach(x => { if (x.id == courseID) ret = x }); 69 | return ret; 70 | } 71 | 72 | function reBlank(str) { 73 | if (typeof str == 'string') { 74 | return str.replace(/\n\s*\n/gi, '\n').replace(/^\s*/m, '').replace(/\s*$/m, ''); 75 | } else { 76 | return str; 77 | } 78 | } 79 | 80 | function reMarkdown(str) { 81 | if (typeof str == 'string') { 82 | return str.replace(/([\*\_\`\[])/gi, '\\$1'); 83 | } else { 84 | return str; 85 | } 86 | } 87 | 88 | function compareFiles(courseName, nowdata, predata) { 89 | nowdata.forEach(file => { 90 | if (predata.filter(x => { return file.id == x.id }).length == 0 && nowTimestamp - file.uploadTime < Date2ms(3, 0)) { 91 | logger.info(`New file: <${courseName}> ${file.title}`); 92 | let text = 93 | `「${reMarkdown(courseName)}」发布了新的文件:` + 94 | `[${reMarkdown(file.title)}](${file.downloadUrl.replace(/learn2018/, 'learn')})`; 95 | if (file.description != "") { 96 | text += 97 | `\n====================\n` + 98 | reMarkdown(reBlank(htmlToText(file.description))); 99 | } 100 | sendMessage(text, 'New file: sendMessage FAIL'); 101 | } 102 | }); 103 | } 104 | 105 | let preTimestamp = new Date(); 106 | let nowTimestamp = new Date(); 107 | let Date2ms = (day, hour) => (day * 24 + hour) * 60 * 60 * 1000; 108 | 109 | function reminder(deadline) { 110 | return (deadline < nowTimestamp) ? null : 111 | (deadline - nowTimestamp < Date2ms(3, 0) && deadline - preTimestamp > Date2ms(3, 0)) ? ['*3 天*', '3 days'] : 112 | (deadline - nowTimestamp < Date2ms(1, 0) && deadline - preTimestamp > Date2ms(1, 0)) ? ['*1 天*', '1 day'] : 113 | (deadline - nowTimestamp < Date2ms(0, 6) && deadline - preTimestamp > Date2ms(0, 6)) ? ['*6 小时*', '6 hours'] : 114 | (deadline - nowTimestamp < Date2ms(0, 1) && deadline - preTimestamp > Date2ms(0, 1)) ? ['*1 小时*', '1 hour'] : 115 | null; 116 | } 117 | 118 | function overdue(deadline) { 119 | return deadline < nowTimestamp && deadline > preTimestamp; 120 | } 121 | 122 | function compareHomeworks(courseName, nowdata, predata) { 123 | nowdata.forEach(homework => { 124 | const pre = predata.filter(x => { return homework.id == x.id }); 125 | if (pre.length == 0) { 126 | logger.info(`New homework: <${courseName}> ${homework.title}`); 127 | let text = 128 | `「${reMarkdown(courseName)}」布置了新的作业:` + 129 | `[${reMarkdown(homework.title)}](${homework.url.replace(/learn2018/, 'learn')})\n` + 130 | `截止时间:${moment(homework.deadline).format('YYYY-MM-DD HH:mm:ss')}` 131 | if (homework.description != "") { 132 | text += 133 | `\n====================\n` + 134 | reMarkdown(reBlank(htmlToText(homework.description))); 135 | } 136 | sendMessage(text, 'New homework: sendMessage FAIL'); 137 | return; 138 | } 139 | let ret; 140 | if (homework.deadline.toISOString() != (typeof pre[0].deadline == 'string' ? pre[0].deadline : pre[0].deadline.toISOString())) { 141 | logger.info(`Homework deadline modified: <${courseName}> ${homework.title}`); 142 | sendMessage( 143 | `截止时间变更:「${reMarkdown(courseName)}」` + 144 | `[${reMarkdown(homework.title)}](${homework.url.replace(/learn2018/, 'learn')})\n` + 145 | `截止时间:${moment(homework.deadline).format('YYYY-MM-DD HH:mm:ss')}`, 146 | 'Homework deadline modified: sendMessage FAIL'); 147 | } else if (homework.submitted == false && (ret = reminder(homework.deadline)) != null) { 148 | logger.info(`Homework deadline ${ret[1]} left: <${courseName}> ${homework.title}`); 149 | sendMessage( 150 | `作业还剩 ${ret[0]}!\n` + 151 | `「${reMarkdown(courseName)}」` + 152 | `[${reMarkdown(homework.title)}](${homework.url.replace(/learn2018/, 'learn')})\n` + 153 | `截止时间:${moment(homework.deadline).format('YYYY-MM-DD HH:mm:ss')}`, 154 | `Homework deadline ${ret[1]} left: sendMessage FAIL`); 155 | } else if (homework.submitted == false && overdue(homework.deadline)) { 156 | logger.info(`Homework deadline overdue: <${courseName}> ${homework.title}`); 157 | sendMessage( 158 | `作业截止!\n` + 159 | `「${reMarkdown(courseName)}」` + 160 | `[${reMarkdown(homework.title)}](${homework.url.replace(/learn2018/, 'learn')})\n` + 161 | `截止时间:${moment(homework.deadline).format('YYYY-MM-DD HH:mm:ss')}`, 162 | `Homework deadline overdue: sendMessage FAIL`); 163 | } 164 | if (homework.submitted && !pre[0].submitted) { 165 | logger.info(`Homework submited: <${courseName}> ${homework.title}`); 166 | sendMessage( 167 | `已提交作业:「${reMarkdown(courseName)}」` + 168 | `[${reMarkdown(homework.title)}](${homework.url.replace(/learn2018/, 'learn')})\n`, 169 | 'Homework submited: sendMessage FAIL'); 170 | } 171 | if (homework.gradeTime && (pre[0].gradeTime == undefined || 172 | homework.gradeTime.toISOString() != (typeof pre[0].gradeTime == 'string' ? pre[0].gradeTime : pre[0].gradeTime.toISOString()))) { 173 | logger.info(`Homework scored: <${courseName}> ${homework.title}`); 174 | let content = 175 | `作业有新的评分:「${reMarkdown(courseName)}」` + 176 | `[${reMarkdown(homework.title)}](${homework.url.replace(/learn2018/, 'learn')})\n`; 177 | if (homework.gradeLevel) 178 | content += `分数等级:${reMarkdown(homework.gradeLevel)}\n` 179 | else if (homework.grade) 180 | content += `分数:${reMarkdown(homework.grade)}\n` 181 | if (homework.gradeContent) 182 | content += `====================\n` + `${reMarkdown(homework.gradeContent)}` 183 | sendMessage(content, 'Homework scored: sendMessage FAIL'); 184 | } 185 | }); 186 | } 187 | 188 | function compareNotifications(courseName, nowdata, predata) { 189 | try { 190 | nowdata.forEach(notification => { 191 | if (predata.filter(x => { return notification.id == x.id }).length == 0 && nowTimestamp - notification.publishTime < Date2ms(3, 0)) { 192 | logger.info(`New nofitication: <${courseName}> ${notification.title}`); 193 | let text = 194 | `「${reMarkdown(courseName)}」发布了新的公告:` + 195 | `[${reMarkdown(notification.title)}](${notification.url.replace(/learn2018/, 'learn')})`; 196 | if (notification.content != "") { 197 | text += 198 | `\n====================\n` + 199 | reMarkdown(reBlank(htmlToText(notification.content))); 200 | } 201 | sendMessage(text, 'New nofitication: sendMessage FAIL'); 202 | } 203 | }); 204 | } catch (err) { 205 | logger.error(err); 206 | } 207 | } 208 | 209 | const TIMEOUT = Symbol('Timeout'); 210 | 211 | async function getCourseList(semester) { 212 | return Promise.race([ 213 | helper.getCourseList(semester), 214 | new Promise((resolve, reject) => setTimeout(() => reject(TIMEOUT), 30 * 1000)) 215 | ]) 216 | } 217 | 218 | (async () => { 219 | while (true) { 220 | try { 221 | logger.info('Login...'); 222 | await Promise.race([ 223 | helper.login(config.user.name, config.user.pwd), 224 | new Promise((resolve, reject) => setTimeout(() => reject(TIMEOUT), 60 * 1000)) 225 | ]); 226 | logger.info('Login successful.'); 227 | break; 228 | } catch (err) { logger.error('Login timeout.'); } 229 | } 230 | 231 | let predata = []; 232 | 233 | try { 234 | predata = await JSON.parse(readFileSync('data.json', 'utf8')); 235 | } catch (err) { 236 | logger.error(err); 237 | let tasks = []; 238 | let courses = []; 239 | for (let semester of config.semesters) { 240 | courses = courses.concat(await getCourseList(semester)); 241 | } 242 | for (let course of courses) { 243 | tasks.push((async () => { 244 | course.files = await helper.getFileList(course.id); 245 | // course.discussions = await helper.getDiscussionList(course.id); 246 | course.notifications = await helper.getNotificationList(course.id); 247 | course.homeworks = await helper.getHomeworkList(course.id); 248 | // course.questions = await helper.getAnsweredQuestionList(course.id); 249 | 250 | await new Promise((resolve => { 251 | predata.push(course); 252 | resolve(); 253 | })); 254 | })()); 255 | }; 256 | 257 | await Promise.all(tasks); 258 | writeFileSync('data.json', JSON.stringify(predata, null, 4)); 259 | }; 260 | 261 | while (true) { 262 | logger.debug('Start checking...'); 263 | try { 264 | let nowdata = []; 265 | let tasks = []; 266 | nowTimestamp = new Date(); 267 | 268 | // logger.debug('Getting course list...'); 269 | let courses = []; 270 | for (let semester of config.semesters) { 271 | courses = courses.concat(await getCourseList(semester)); 272 | } 273 | // logger.debug('Got course list.'); 274 | // logger.debug(courses); 275 | for (let course of courses) { 276 | tasks.push((async () => { 277 | course.files = await helper.getFileList(course.id); 278 | // course.discussions = await helper.getDiscussionList(course.id); 279 | course.notifications = await helper.getNotificationList(course.id); 280 | course.homeworks = await helper.getHomeworkList(course.id); 281 | // course.questions = await helper.getAnsweredQuestionList(course.id); 282 | 283 | logger.debug(`Course <${course.name}>: files ${course.files.length} notifications ${course.notifications.length} homeworks ${course.homeworks.length}`); 284 | 285 | await new Promise((resolve => { 286 | nowdata.push(course); 287 | // logger.debug(`Course <${course.name}> finished.`); 288 | resolve(); 289 | })); 290 | })()); 291 | }; 292 | await Promise.race([ 293 | Promise.all(tasks), 294 | new Promise((resolve, reject) => setTimeout(() => reject(TIMEOUT), 120 * 1000)) 295 | ]); 296 | // logger.debug('Got all data.'); 297 | 298 | for (let course of nowdata) { 299 | const coursePredata = findCourse(predata, course.id); 300 | if (coursePredata != null) { 301 | compareFiles(course.name, course.files, coursePredata.files); 302 | // compareDiscussions(course.discussions, coursePredata.discussions); 303 | compareNotifications(course.name, course.notifications, coursePredata.notifications); 304 | compareHomeworks(course.name, course.homeworks, coursePredata.homeworks); 305 | // compareQuestions(course.questions, coursePredata.questions); 306 | } else { 307 | logger.info(`New course: <${course.name}>`); 308 | sendMessage(`新课程:「${reMarkdown(course.name)}」`, 'New course: sendMessage FAIL'); 309 | } 310 | } 311 | 312 | writeFileSync('data.json', JSON.stringify(nowdata, null, 4)); 313 | predata = nowdata; 314 | preTimestamp = nowTimestamp; 315 | logger.debug('Checked.'); 316 | } catch (err) { 317 | if (err === TIMEOUT) { 318 | logger.error('Timeout.'); 319 | continue; 320 | } else { 321 | logger.error(err); 322 | while (true) { 323 | try { 324 | logger.info('Relogin...'); 325 | await Promise.race([ 326 | helper.login(config.user.name, config.user.pwd), 327 | new Promise((resolve, reject) => setTimeout(() => reject(TIMEOUT), 60 * 1000)) 328 | ]); 329 | logger.info('Relogin successful.'); 330 | break; 331 | } catch (err) { 332 | logger.error('Relogin timeout.'); 333 | await delay(10 * 1000); 334 | } 335 | } 336 | } 337 | } 338 | await delay(60 * 1000); 339 | } 340 | })(); 341 | 342 | (async () => { 343 | while (true) { 344 | try { 345 | if (global.gc) { 346 | global.gc(); 347 | logger.info('global.gc()'); 348 | } 349 | } catch (e) { 350 | logger.error('ERROR: `node --expose-gc index.js`'); 351 | } 352 | await delay(3600 * 1000); 353 | } 354 | })(); 355 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "thu-weblearn-tgbot", 3 | "version": "1.1.0", 4 | "description": "A telegram bot to monitor Tsinghua web learning and push new messages to users.", 5 | "main": "index.js", 6 | "type": "module", 7 | "scripts": { 8 | "test": "echo \"Error: no test specified\" && exit 1" 9 | }, 10 | "author": "Konano", 11 | "license": "MIT", 12 | "dependencies": { 13 | "html-to-text": "^8.0.0", 14 | "log4js": "^6.4.0", 15 | "moment": "^2.29.4", 16 | "thu-learn-lib": "^3.0.1" 17 | }, 18 | "devDependencies": {}, 19 | "repository": "git+https://github.com/Konano/thu-weblearn-tgbot.git", 20 | "bugs": { 21 | "url": "https://github.com/Konano/thu-weblearn-tgbot/issues" 22 | }, 23 | "homepage": "https://github.com/Konano/thu-weblearn-tgbot#readme" 24 | } 25 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@selderee/plugin-htmlparser2@^0.6.0": 6 | version "0.6.0" 7 | resolved "https://registry.nlark.com/@selderee/plugin-htmlparser2/download/@selderee/plugin-htmlparser2-0.6.0.tgz#27e994afd1c2cb647ceb5406a185a5574188069d" 8 | integrity sha1-J+mUr9HCy2R861QGoYWlV0GIBp0= 9 | dependencies: 10 | domhandler "^4.2.0" 11 | selderee "^0.6.0" 12 | 13 | asynckit@^0.4.0: 14 | version "0.4.0" 15 | resolved "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" 16 | integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== 17 | 18 | boolbase@^1.0.0: 19 | version "1.0.0" 20 | resolved "https://registry.npmmirror.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" 21 | integrity sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww== 22 | 23 | cheerio-select@^1.5.0: 24 | version "1.6.0" 25 | resolved "https://registry.npmmirror.com/cheerio-select/-/cheerio-select-1.6.0.tgz#489f36604112c722afa147dedd0d4609c09e1696" 26 | integrity sha512-eq0GdBvxVFbqWgmCm7M3XGs1I8oLy/nExUnh6oLqmBditPO9AqQJrkslDpMun/hZ0yyTs8L0m85OHp4ho6Qm9g== 27 | dependencies: 28 | css-select "^4.3.0" 29 | css-what "^6.0.1" 30 | domelementtype "^2.2.0" 31 | domhandler "^4.3.1" 32 | domutils "^2.8.0" 33 | 34 | cheerio@^1.0.0-rc.10: 35 | version "1.0.0-rc.10" 36 | resolved "https://registry.npmmirror.com/cheerio/-/cheerio-1.0.0-rc.10.tgz#2ba3dcdfcc26e7956fc1f440e61d51c643379f3e" 37 | integrity sha512-g0J0q/O6mW8z5zxQ3A8E8J1hUgp4SMOvEoW/x84OwyHKe/Zccz83PVT4y5Crcr530FV6NgmKI1qvGTKVl9XXVw== 38 | dependencies: 39 | cheerio-select "^1.5.0" 40 | dom-serializer "^1.3.2" 41 | domhandler "^4.2.0" 42 | htmlparser2 "^6.1.0" 43 | parse5 "^6.0.1" 44 | parse5-htmlparser2-tree-adapter "^6.0.1" 45 | tslib "^2.2.0" 46 | 47 | combined-stream@^1.0.8: 48 | version "1.0.8" 49 | resolved "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" 50 | integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== 51 | dependencies: 52 | delayed-stream "~1.0.0" 53 | 54 | commander@^2.19.0: 55 | version "2.20.3" 56 | resolved "https://registry.nlark.com/commander/download/commander-2.20.3.tgz?cache=0&sync_timestamp=1631257724267&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fcommander%2Fdownload%2Fcommander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" 57 | integrity sha1-/UhehMA+tIgcIHIrpIA16FMa6zM= 58 | 59 | cross-fetch@^3.1.5: 60 | version "3.1.5" 61 | resolved "https://registry.npmmirror.com/cross-fetch/-/cross-fetch-3.1.5.tgz#e1389f44d9e7ba767907f7af8454787952ab534f" 62 | integrity sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw== 63 | dependencies: 64 | node-fetch "2.6.7" 65 | 66 | css-select@^4.3.0: 67 | version "4.3.0" 68 | resolved "https://registry.npmmirror.com/css-select/-/css-select-4.3.0.tgz#db7129b2846662fd8628cfc496abb2b59e41529b" 69 | integrity sha512-wPpOYtnsVontu2mODhA19JrqWxNsfdatRKd64kmpRbQgh1KtItko5sTnEpPdpSaJszTOhEMlF/RPz28qj4HqhQ== 70 | dependencies: 71 | boolbase "^1.0.0" 72 | css-what "^6.0.1" 73 | domhandler "^4.3.1" 74 | domutils "^2.8.0" 75 | nth-check "^2.0.1" 76 | 77 | css-what@^6.0.1: 78 | version "6.1.0" 79 | resolved "https://registry.npmmirror.com/css-what/-/css-what-6.1.0.tgz#fb5effcf76f1ddea2c81bdfaa4de44e79bac70f4" 80 | integrity sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw== 81 | 82 | date-format@^4.0.3: 83 | version "4.0.3" 84 | resolved "https://registry.yarnpkg.com/date-format/-/date-format-4.0.3.tgz#f63de5dc08dc02efd8ef32bf2a6918e486f35873" 85 | integrity sha512-7P3FyqDcfeznLZp2b+OMitV9Sz2lUnsT87WaTat9nVwqsBkTzPG3lPLNwW3en6F4pHUiWzr6vb8CLhjdK9bcxQ== 86 | 87 | debug@^4.1.1, debug@^4.3.3: 88 | version "4.3.3" 89 | resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" 90 | integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== 91 | dependencies: 92 | ms "2.1.2" 93 | 94 | deepmerge@^4.2.2: 95 | version "4.2.2" 96 | resolved "https://registry.nlark.com/deepmerge/download/deepmerge-4.2.2.tgz?cache=0&sync_timestamp=1622025358084&other_urls=https%3A%2F%2Fregistry.nlark.com%2Fdeepmerge%2Fdownload%2Fdeepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" 97 | integrity sha1-RNLqNnm49NT/ujPwPYZfwee/SVU= 98 | 99 | delayed-stream@~1.0.0: 100 | version "1.0.0" 101 | resolved "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" 102 | integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== 103 | 104 | discontinuous-range@1.0.0: 105 | version "1.0.0" 106 | resolved "https://registry.npm.taobao.org/discontinuous-range/download/discontinuous-range-1.0.0.tgz#e38331f0844bba49b9a9cb71c771585aab1bc65a" 107 | integrity sha1-44Mx8IRLukm5qctxx3FYWqsbxlo= 108 | 109 | dom-serializer@^1.0.1, dom-serializer@^1.3.2: 110 | version "1.4.1" 111 | resolved "https://registry.npmmirror.com/dom-serializer/-/dom-serializer-1.4.1.tgz#de5d41b1aea290215dc45a6dae8adcf1d32e2d30" 112 | integrity sha512-VHwB3KfrcOOkelEG2ZOfxqLZdfkil8PtJi4P8N2MMXucZq2yLp75ClViUlOVwyoHEDjYU433Aq+5zWP61+RGag== 113 | dependencies: 114 | domelementtype "^2.0.1" 115 | domhandler "^4.2.0" 116 | entities "^2.0.0" 117 | 118 | domelementtype@^2.0.1, domelementtype@^2.2.0: 119 | version "2.3.0" 120 | resolved "https://registry.npmmirror.com/domelementtype/-/domelementtype-2.3.0.tgz#5c45e8e869952626331d7aab326d01daf65d589d" 121 | integrity sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw== 122 | 123 | domhandler@^4.0.0, domhandler@^4.2.0, domhandler@^4.3.1: 124 | version "4.3.1" 125 | resolved "https://registry.npmmirror.com/domhandler/-/domhandler-4.3.1.tgz#8d792033416f59d68bc03a5aa7b018c1ca89279c" 126 | integrity sha512-GrwoxYN+uWlzO8uhUXRl0P+kHE4GtVPfYzVLcUxPL7KNdHKj66vvlhiweIHqYYXWlw+T8iLMp42Lm67ghw4WMQ== 127 | dependencies: 128 | domelementtype "^2.2.0" 129 | 130 | domutils@^2.5.2, domutils@^2.8.0: 131 | version "2.8.0" 132 | resolved "https://registry.npmmirror.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135" 133 | integrity sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A== 134 | dependencies: 135 | dom-serializer "^1.0.1" 136 | domelementtype "^2.2.0" 137 | domhandler "^4.2.0" 138 | 139 | entities@^2.0.0: 140 | version "2.2.0" 141 | resolved "https://registry.npmmirror.com/entities/-/entities-2.2.0.tgz#098dc90ebb83d8dffa089d55256b351d34c4da55" 142 | integrity sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A== 143 | 144 | es6-denodeify@^0.1.5: 145 | version "0.1.5" 146 | resolved "https://registry.npmmirror.com/es6-denodeify/-/es6-denodeify-0.1.5.tgz#31d4d5fe9c5503e125460439310e16a2a3f39c1f" 147 | integrity sha512-731Rf4NqlPvhkT1pIF7r8vZxESJlWocNpXLuyPlVnfEGXlwuJaMvU5WpyyDjpudDC2cgXVX849xljzvQqBg1QQ== 148 | 149 | flatted@^3.2.4: 150 | version "3.2.4" 151 | resolved "https://registry.yarnpkg.com/flatted/-/flatted-3.2.4.tgz#28d9969ea90661b5134259f312ab6aa7929ac5e2" 152 | integrity sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw== 153 | 154 | form-data@^4.0.0: 155 | version "4.0.0" 156 | resolved "https://registry.npmmirror.com/form-data/-/form-data-4.0.0.tgz#93919daeaf361ee529584b9b31664dc12c9fa452" 157 | integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== 158 | dependencies: 159 | asynckit "^0.4.0" 160 | combined-stream "^1.0.8" 161 | mime-types "^2.1.12" 162 | 163 | fs-extra@^10.0.0: 164 | version "10.0.0" 165 | resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-10.0.0.tgz#9ff61b655dde53fb34a82df84bb214ce802e17c1" 166 | integrity sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ== 167 | dependencies: 168 | graceful-fs "^4.2.0" 169 | jsonfile "^6.0.1" 170 | universalify "^2.0.0" 171 | 172 | graceful-fs@^4.1.6, graceful-fs@^4.2.0: 173 | version "4.2.4" 174 | resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.4.tgz#2256bde14d3632958c465ebc96dc467ca07a29fb" 175 | integrity sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw== 176 | 177 | he@^1.2.0: 178 | version "1.2.0" 179 | resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" 180 | integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== 181 | 182 | html-to-text@^8.0.0: 183 | version "8.0.0" 184 | resolved "https://registry.nlark.com/html-to-text/download/html-to-text-8.0.0.tgz#5848681a5a38d657a7bb58cf5006d1c29fe64ce3" 185 | integrity sha1-WEhoGlo41lenu1jPUAbRwp/mTOM= 186 | dependencies: 187 | "@selderee/plugin-htmlparser2" "^0.6.0" 188 | deepmerge "^4.2.2" 189 | he "^1.2.0" 190 | htmlparser2 "^6.1.0" 191 | minimist "^1.2.5" 192 | selderee "^0.6.0" 193 | 194 | htmlparser2@^6.1.0: 195 | version "6.1.0" 196 | resolved "https://registry.npmmirror.com/htmlparser2/-/htmlparser2-6.1.0.tgz#c4d762b6c3371a05dbe65e94ae43a9f845fb8fb7" 197 | integrity sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A== 198 | dependencies: 199 | domelementtype "^2.0.1" 200 | domhandler "^4.0.0" 201 | domutils "^2.5.2" 202 | entities "^2.0.0" 203 | 204 | ip-regex@^1.0.0: 205 | version "1.0.3" 206 | resolved "https://registry.npmmirror.com/ip-regex/-/ip-regex-1.0.3.tgz#dc589076f659f419c222039a33316f1c7387effd" 207 | integrity sha512-HjpCHTuxbR/6jWJroc/VN+npo5j0T4Vv2TAI5qdEHQx7hsL767MeccGFSsLtF694EiZKTSEqgoeU6DtGFCcuqQ== 208 | 209 | is-ip@^1.0.0: 210 | version "1.0.0" 211 | resolved "https://registry.npmmirror.com/is-ip/-/is-ip-1.0.0.tgz#2bb6959f797ccd6f9fdc812758bcbc87c4c59074" 212 | integrity sha512-9FOEPG/qVtJrEWSOb27DwfWdQhE2pfnUJjO4zn+/1s03idfz+9lrS0aK32tie+TDcAHdLhZR01udvB6kg/x+qA== 213 | dependencies: 214 | ip-regex "^1.0.0" 215 | 216 | js-base64@^3.7.2: 217 | version "3.7.2" 218 | resolved "https://registry.npmmirror.com/js-base64/-/js-base64-3.7.2.tgz#816d11d81a8aff241603d19ce5761e13e41d7745" 219 | integrity sha512-NnRs6dsyqUXejqk/yv2aiXlAvOs56sLkX6nUdeaNezI5LFFLlsZjOThmwnrcwh5ZZRwZlCMnVAY3CvhIhoVEKQ== 220 | 221 | jsonfile@^6.0.1: 222 | version "6.1.0" 223 | resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" 224 | integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== 225 | dependencies: 226 | universalify "^2.0.0" 227 | optionalDependencies: 228 | graceful-fs "^4.1.6" 229 | 230 | log4js@^6.4.0: 231 | version "6.4.0" 232 | resolved "https://registry.yarnpkg.com/log4js/-/log4js-6.4.0.tgz#3f63ccfc8033c83cd617a4d2d50e48be5944eae9" 233 | integrity sha512-ysc/XUecZJuN8NoKOssk3V0cQ29xY4fra6fnigZa5VwxFsCsvdqsdnEuAxNN89LlHpbE4KUD3zGcn+kFqonSVQ== 234 | dependencies: 235 | date-format "^4.0.3" 236 | debug "^4.3.3" 237 | flatted "^3.2.4" 238 | rfdc "^1.3.0" 239 | streamroller "^3.0.2" 240 | 241 | mime-db@1.52.0: 242 | version "1.52.0" 243 | resolved "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70" 244 | integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== 245 | 246 | mime-types@^2.1.12: 247 | version "2.1.35" 248 | resolved "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a" 249 | integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== 250 | dependencies: 251 | mime-db "1.52.0" 252 | 253 | minimist@^1.2.5: 254 | version "1.2.6" 255 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" 256 | integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== 257 | 258 | moment@^2.29.4: 259 | version "2.29.4" 260 | resolved "https://registry.yarnpkg.com/moment/-/moment-2.29.4.tgz#3dbe052889fe7c1b2ed966fcb3a77328964ef108" 261 | integrity sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w== 262 | 263 | moo@^0.5.0, moo@^0.5.1: 264 | version "0.5.1" 265 | resolved "https://registry.npm.taobao.org/moo/download/moo-0.5.1.tgz#7aae7f384b9b09f620b6abf6f74ebbcd1b65dbc4" 266 | integrity sha1-eq5/OEubCfYgtqv29067zRtl28Q= 267 | 268 | ms@2.1.2: 269 | version "2.1.2" 270 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" 271 | integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== 272 | 273 | nearley@^2.20.1: 274 | version "2.20.1" 275 | resolved "https://registry.nlark.com/nearley/download/nearley-2.20.1.tgz#246cd33eff0d012faf197ff6774d7ac78acdd474" 276 | integrity sha1-JGzTPv8NAS+vGX/2d016x4rN1HQ= 277 | dependencies: 278 | commander "^2.19.0" 279 | moo "^0.5.0" 280 | railroad-diagrams "^1.0.0" 281 | randexp "0.4.6" 282 | 283 | node-fetch@2.6.7: 284 | version "2.6.7" 285 | resolved "https://registry.npmmirror.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" 286 | integrity sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ== 287 | dependencies: 288 | whatwg-url "^5.0.0" 289 | 290 | nth-check@^2.0.1: 291 | version "2.0.1" 292 | resolved "https://registry.npmmirror.com/nth-check/-/nth-check-2.0.1.tgz#2efe162f5c3da06a28959fbd3db75dbeea9f0fc2" 293 | integrity sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w== 294 | dependencies: 295 | boolbase "^1.0.0" 296 | 297 | parse5-htmlparser2-tree-adapter@^6.0.1: 298 | version "6.0.1" 299 | resolved "https://registry.npmmirror.com/parse5-htmlparser2-tree-adapter/-/parse5-htmlparser2-tree-adapter-6.0.1.tgz#2cdf9ad823321140370d4dbf5d3e92c7c8ddc6e6" 300 | integrity sha512-qPuWvbLgvDGilKc5BoicRovlT4MtYT6JfJyBOMDsKoiT+GiuP5qyrPCnR9HcPECIJJmZh5jRndyNThnhhb/vlA== 301 | dependencies: 302 | parse5 "^6.0.1" 303 | 304 | parse5@^6.0.1: 305 | version "6.0.1" 306 | resolved "https://registry.npmmirror.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b" 307 | integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw== 308 | 309 | parseley@^0.7.0: 310 | version "0.7.0" 311 | resolved "https://registry.nlark.com/parseley/download/parseley-0.7.0.tgz#9949e3a0ed05c5072adb04f013c2810cf49171a8" 312 | integrity sha1-mUnjoO0FxQcq2wTwE8KBDPSRcag= 313 | dependencies: 314 | moo "^0.5.1" 315 | nearley "^2.20.1" 316 | 317 | punycode@1.3.2: 318 | version "1.3.2" 319 | resolved "https://registry.npmmirror.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" 320 | integrity sha512-RofWgt/7fL5wP1Y7fxE7/EmTLzQVnB0ycyibJ0OOHIlJqTNzglYFxVwETOcIoJqJmpDXJ9xImDv+Fq34F/d4Dw== 321 | 322 | querystring@0.2.0: 323 | version "0.2.0" 324 | resolved "https://registry.npmmirror.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" 325 | integrity sha512-X/xY82scca2tau62i9mDyU9K+I+djTMUsvwf7xnUX5GLvVzgJybOJf4Y6o9Zx3oJK/LSXg5tTZBjwzqVPaPO2g== 326 | 327 | railroad-diagrams@^1.0.0: 328 | version "1.0.0" 329 | resolved "https://registry.npm.taobao.org/railroad-diagrams/download/railroad-diagrams-1.0.0.tgz#eb7e6267548ddedfb899c1b90e57374559cddb7e" 330 | integrity sha1-635iZ1SN3t+4mcG5Dlc3RVnN234= 331 | 332 | randexp@0.4.6: 333 | version "0.4.6" 334 | resolved "https://registry.npm.taobao.org/randexp/download/randexp-0.4.6.tgz#e986ad5e5e31dae13ddd6f7b3019aa7c87f60ca3" 335 | integrity sha1-6YatXl4x2uE93W97MBmqfIf2DKM= 336 | dependencies: 337 | discontinuous-range "1.0.0" 338 | ret "~0.1.10" 339 | 340 | real-isomorphic-fetch@^3.0.0: 341 | version "3.0.0" 342 | resolved "https://registry.npmmirror.com/real-isomorphic-fetch/-/real-isomorphic-fetch-3.0.0.tgz#803321cc9851e5861d7e3c6113fbc6a5ef31d341" 343 | integrity sha512-aPuZOztgPFB9b/6BzpMSuEmEdfsH2yZu3mub7kjUh7STeAsMmnidvznRIE5AycoqYrfV2mu0m1Jb9BxUf3SfBQ== 344 | dependencies: 345 | tough-cookie-no-native "^2.4.1" 346 | 347 | ret@~0.1.10: 348 | version "0.1.15" 349 | resolved "https://registry.nlark.com/ret/download/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" 350 | integrity sha1-uKSCXVvbH8P29Twrwz+BOIaBx7w= 351 | 352 | rfdc@^1.3.0: 353 | version "1.3.0" 354 | resolved "https://registry.yarnpkg.com/rfdc/-/rfdc-1.3.0.tgz#d0b7c441ab2720d05dc4cf26e01c89631d9da08b" 355 | integrity sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA== 356 | 357 | selderee@^0.6.0: 358 | version "0.6.0" 359 | resolved "https://registry.nlark.com/selderee/download/selderee-0.6.0.tgz#f3bee66cfebcb6f33df98e4a1df77388b42a96f7" 360 | integrity sha1-877mbP68tvM9+Y5KHfdziLQqlvc= 361 | dependencies: 362 | parseley "^0.7.0" 363 | 364 | streamroller@^3.0.2: 365 | version "3.0.2" 366 | resolved "https://registry.yarnpkg.com/streamroller/-/streamroller-3.0.2.tgz#30418d0eee3d6c93ec897f892ed098e3a81e68b7" 367 | integrity sha512-ur6y5S5dopOaRXBuRIZ1u6GC5bcEXHRZKgfBjfCglMhmIf+roVCECjvkEYzNQOXIN2/JPnkMPW/8B3CZoKaEPA== 368 | dependencies: 369 | date-format "^4.0.3" 370 | debug "^4.1.1" 371 | fs-extra "^10.0.0" 372 | 373 | thu-learn-lib@^3.0.1: 374 | version "3.0.2" 375 | resolved "https://registry.npmmirror.com/thu-learn-lib/-/thu-learn-lib-3.0.2.tgz#9fab6d2fae8d58c60267bdfc9caafe2bb5b636b1" 376 | integrity sha512-vJpoVef7cjLwCH6btrKJxhLymM38imkfV11ve6+BK7uV6eIPjaSbqA53iTX/PoGOvbh9cnnod2TjT8nMCE1qpw== 377 | dependencies: 378 | cheerio "^1.0.0-rc.10" 379 | cross-fetch "^3.1.5" 380 | entities "^2.0.0" 381 | es6-denodeify "^0.1.5" 382 | form-data "^4.0.0" 383 | js-base64 "^3.7.2" 384 | real-isomorphic-fetch "^3.0.0" 385 | 386 | tough-cookie-no-native@^2.4.1: 387 | version "2.4.1" 388 | resolved "https://registry.npmmirror.com/tough-cookie-no-native/-/tough-cookie-no-native-2.4.1.tgz#515ad76ce9b5e0abfa87dd83f5f0cae0af99498e" 389 | integrity sha512-EqljmbL21LEmzw0WwZy3TO6qhFaEYtDWMlutXhXCj/5vDWn+qFkU9t54YF09PGR9IartVFTrsCb2RzEqMsw0oQ== 390 | dependencies: 391 | is-ip "^1.0.0" 392 | url "^0.11.0" 393 | 394 | tr46@~0.0.3: 395 | version "0.0.3" 396 | resolved "https://registry.npmmirror.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" 397 | integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== 398 | 399 | tslib@^2.2.0: 400 | version "2.3.1" 401 | resolved "https://registry.npmmirror.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" 402 | integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== 403 | 404 | universalify@^2.0.0: 405 | version "2.0.0" 406 | resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" 407 | integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== 408 | 409 | url@^0.11.0: 410 | version "0.11.0" 411 | resolved "https://registry.npmmirror.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" 412 | integrity sha512-kbailJa29QrtXnxgq+DdCEGlbTeYM2eJUxsz6vjZavrCYPMIFHMKQmSKYAIuUK2i7hgPm28a8piX5NTUtM/LKQ== 413 | dependencies: 414 | punycode "1.3.2" 415 | querystring "0.2.0" 416 | 417 | webidl-conversions@^3.0.0: 418 | version "3.0.1" 419 | resolved "https://registry.npmmirror.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" 420 | integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== 421 | 422 | whatwg-url@^5.0.0: 423 | version "5.0.0" 424 | resolved "https://registry.npmmirror.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" 425 | integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== 426 | dependencies: 427 | tr46 "~0.0.3" 428 | webidl-conversions "^3.0.0" 429 | --------------------------------------------------------------------------------