// ==UserScript== // @name ⭐超星学习通智能助手Pro-全自动学习|可处理视频内题目|考试助手|智能答题|章节刷课|云端题库|AI辅助|可视化配置 // @namespace http://tampermonkey.net/ // @version 5.2.1.0 // @description ⭐超星智能学习助手Pro-支持📹章节视频自动播放与⏩倍速、📄阅读/文档任务自动完成,✏️章节作业与📝考试智能答题(可选💡自动提交/❓随机答题),还集成📚免费+付费云端题库,搭配🤖AI辅助解题!内置⏳复习模式补时长、🔒进程守护防卡死,更有🎛️可视化配置面板+⚙️自定义学习参数,一站式解决学习通网课需求💯! // @author 禁止蕉绿 // @run-at document-end // @match *://*.chaoxing.com/* // @match *://*.edu.cn/* // @match *://*.nbdlib.cn/* // @match *://*.hnsyu.net/* // @match *://*.gdhkmooc.com/* // @connect cx.icodef.com // @connect api.tikuhai.com // @connect sso.chaoxing.com // @connect mooc1-api.chaoxing.com // @connect mooc1-1.chaoxing.com // @connect mooc1-2.chaoxing.com // @connect mooc2-ans.chaoxing.com // @connect cdn.bootcdn.net // @connect cdnjs.cloudflare.com // @connect mooc1.chaoxing.com // @connect fystat-ans.chaoxing.com // @connect stat2-ans.chaoxing.com // @connect mooc1.gdhkmooc.com // @connect mooc2-ans.hnsyu.net // @connect mooc1.hnsyu.net // @connect mooc1.hlju.edu.cn // @icon http://cur.cursors-4u.net/anime/ani-12/ani1136.gif // @grant unsafeWindow // @grant GM_info // @grant GM_getResourceText // @grant GM_addStyle // @grant GM_setValue // @grant GM_getValue // @grant GM_xmlhttpRequest // @require https://greasyfork.org/scripts/456170-hacktimerjs/code/hacktimerjs.js?version=1143079 // @require https://cdn.jsdelivr.net/npm/jquery@3.6.0/dist/jquery.min.js // @require https://mirrors.sustech.edu.cn/cdnjs/ajax/libs/layx/2.5.4/layx.min.js // @require https://cdn.jsdelivr.net/npm/blueimp-md5@2.19.0/js/md5.min.js // @resource layxcss https://mirrors.sustech.edu.cn/cdnjs/ajax/libs/layx/2.5.4/layx.min.css // @resource layuicss https://cdn.jsdelivr.net/npm/layui@2.6.8/dist/css/layui.css // @resource ttf1 http://www.forestpolice.org/ttf/2.0/table.json?t=1 // @resource ttf2 https://chaoxing.tech/table.json // @resource ttf3 https://static.muketool.com/scripts/cx/v2/fonts/cxsecret.json // @antifeature payment 存在第三方付费接口 // ==/UserScript== /******/ (() => { // webpackBootstrap var __webpack_exports__ = {}; var defaultConfig = { ua: 'Dalvik/2.1.0 (Linux; U; Android 11; M3121K1AB Build/SKQ1.211006.001) (device:M3121K1AB) Language/zh_CN com.chaoxing.mobile/ChaoXingStudy_3_5.1.4_android_phone_614_74 (@Kalimdor)_', interval: 3000, autoVideo: true, autoRead: true, autoAnswer: true, videoSpeed: 2, reviewMode: false, matchRate: 0.8, autoSubmitRate: 0.8, autoSubmit: true, autoSwitch: true, tutorial: true, randomAnswer: false, threadWatch: true, freeFirst: true, readSpeed: 0.2, notice: '本脚本仅供学习研究,请勿使用于非法用途!', debugger: false, types: { '单选题': '0', '多选题': '1', '填空题': '2', '判断题': '3', '简答题': '4', '名词解释': '5', '论述题': '6', '计算题': '7', }, token: '', yizhiToken: '', aiAsk: false }, otherApi = [ { desc: "接口来源:https://cx.icodef.com/query.html", url: 'http://cx.icodef.com/wyn-nb?v=4', headers: { 'Content-Type': 'application/x-www-form-urlencoded;charset=utf-8', 'Authorization': defaultConfig.yizhiToken || ''/** 一之题库token填写 */ }, method: 'post', getdata: (data) => { return `question=${encodeURIComponent(data.question)}`; }, getanswer: (response) => { const res = JSON.parse(response.responseText); if (res.code === 1) { let data = res.data.replace(/javascript:void\(0\);/g, '').trim().replace(/\n/g, ''); if (data.includes('叛逆') || data.includes('公众号') || data.includes('李恒雅') || data.includes('一之')) { return false; } else { return data.split("#"); } } return false; } } ], _self = unsafeWindow, top = (/* unused pure expression or super */ null && (_self)), script_info = GM_info.script, cache_key = "20230524", reqUrl = [ { "api": "https://api.tikuhai.com/", "headers": {} }, ], icon = ``; let cacheData = GM_getValue(cache_key); if (cacheData && !cacheData.token) cacheData.token = defaultConfig.token; defaultConfig = cacheData || defaultConfig; const log = msg => defaultConfig.debugger && console.log(msg); (function () { 'use strict'; const _postMessage = unsafeWindow.postMessage; unsafeWindow.postMessage = function (msg, targetOrigin, transfer) { if (msg && msg.includes('"toggle":true')) { msg = msg.replace('"toggle":true', '"toggle":false'); } _postMessage.call(unsafeWindow, msg, targetOrigin, transfer); }; String.prototype.cl = function () { return this.replace(/^【.*?】\s*/, '').replace(/\s*(\d+\.\d+分)$/, '') }; var utils = { randomStr: (len = 32) => { const $chars = 'qwertyuioplkjhgfdsazxcvbnm1234567890'; let ss = ''; for (let i = 0; i < len; i++) { ss += $chars.charAt(Math.floor(Math.random() * $chars.length)); } return ss; }, notify: (level, msg) => { let data = { level: level, msg: msg } return JSON.stringify(data); }, sortData: (data) => { const arr = []; data.forEach(item => { const parent = data.find(item2 => item2.id === item.parentnodeid); parent ? (parent.children || (parent.children = [])).push(item) : arr.push(item); }); return arr; }, toOneArray: (arr) => { return arr.reduce((newArr, item) => newArr.concat(item, item.children ? utils.toOneArray(item.children) : []), []); }, sleep: (time) => { return new Promise(resolve => setTimeout(resolve, time)); }, getUrlParam: (name) => { const reg = new RegExp("(^|&)" + name + "=([^&]*)(&|$)"); const r = window.location.search.substr(1).match(reg); return r ? unescape(r[2]) : null; }, toQueryString: (obj) => { return obj ? Object.keys(obj).sort().map(key => { const val = obj[key]; return Array.isArray(val) ? val.sort().map(val2 => encodeURIComponent(key) + '=' + encodeURIComponent(val2)).join('&') : encodeURIComponent(key) + '=' + encodeURIComponent(val); }).join('&') : ''; }, getInputParam: (name) => { const input = document.getElementsByName(name)[0]; return input ? input.value : null; }, getVideoEnc: (clazzid, uid, jobid, objectId, playingTime, duration) => { return md5("[" + clazzid + "][" + uid + "][" + jobid + "][" + objectId + "][" + (playingTime * 1000) + "][d_yHJ!$pdA~5][" + (duration * 1000) + "][0_" + duration + "]"); }, getTimestamp: () => { return new Date().getTime(); } , removeHtml: (html) => { if (html == null) { return ''; } // 判断是否为字符串 if (typeof html !== 'string') { return html; } return html.replace(/<((?!img|sub|sup|br)[^>]+)>/g, '').replace(/ /g, ' ').replace(/\s+/g, ' ').replace(//g, '\n').replace(//g, '').trim(); } , cache: (key, value) => { GM_setValue(key, { value: value, time: utils.getTimestamp() }); return value; }, cacheExpired: (key, time) => { var cache = GM_getValue(key); if (cache) { if (cache.time + time > utils.getTimestamp()) { return cache.value; } } return false; }, matchIndex: (options, answer) => { var matchArr = []; for (var i = 0; i < answer.length; i++) { for (var j = 0; j < options.length; j++) { if (answer[i] == options[j]) { matchArr.push(j); } } } return matchArr; } , similarity: (s, t) => { let l = Math.max(s.length, t.length); let n = s.length; let m = t.length; let d = Array.from({ length: n + 1 }, (_, i) => [i]); for (let j = 0; j <= m; j++) d[0][j] = j; for (let i = 1; i <= n; i++) for (let j = 1; j <= m; j++) { let cost = s[i - 1] === t[j - 1] ? 0 : 1; d[i][j] = Math.min(d[i - 1][j] + 1, d[i][j - 1] + 1, d[i - 1][j - 1] + cost); } return (1 - d[n][m] / l); } , fuzzyMatchIndex: (options, answer) => { const matchArr = []; for (const ans of answer) { let maxSim = 0, index = 0; for (let i = 0; i < options.length; i++) { const sim = utils.similarity(ans, options[i]); if (sim > maxSim) { maxSim = sim; index = i; } } if (maxSim > defaultConfig.matchRate) matchArr.push(index); } return matchArr; } }; var api = { monitorVerify: (responseText, url, method, data, ua) => { return new Promise((resolve, reject) => { try { let obj = JSON.parse(responseText); let divHtml = ' '; layx.prompt(divHtml, "请输入验证码", function (id, value, textarea, button, event) { let url = obj.verify_path + "&ucode=" + value; window.open(url); }); } catch (error) { let domain = url.match(/:\/\/(.[^/]+)/)[1]; let urlShowVerify = "https://" + domain + "/antispiderShowVerify.ac"; page.layx_log(`若未自动弹出页面,请点我打开`, 'error'); layx.iframe('verifyCode', '验证码验证', urlShowVerify); let timer = setInterval(() => { api.defaultRequest(url, method, data, ua, true).then((response) => { if (response.responseText && !response.responseText.includes('输入验证码')) { layx.destroy('verifyCode'); clearInterval(timer); page.layx_log('验证码验证成功!', 'success'); resolve(response); } else { page.layx_log('验证码验证失败!将在5s后重新验证', 'error'); } }) }, 5000); } }); }, defaultRequest: async (url, method, data = {}, ua = defaultConfig.ua, verify = false) => { try { const response = await new Promise((resolve, reject) => { if (method == "post") { GM_xmlhttpRequest({ url, method, headers: { 'User-Agent': ua, 'Content-Type': 'application/x-www-form-urlencoded', }, data: utils.toQueryString(data), onload: resolve, onerror: reject }); } else { GM_xmlhttpRequest({ url, method, headers: { 'User-Agent': ua, }, onload: resolve, onerror: reject }); } }); if (!verify && response.responseText && response.responseText.includes('输入验证码')) { page.layx_log( '检测到验证码!将弹出新页面自行验证验证码(出现验证码多为间隔频率过短,或者请求过多,请根据自己情况调高运行间隔)', 'error' ); await api.monitorVerify(response.responseText, url, method, data, ua); return await api.defaultRequest(url, method, data); } return response; } catch (err) { if (err.error && err.error.includes("connect list")) { const domain = err.error.match(/:\/\/(.[^/]+)/)[1]; const notice = `由于connect未添加导致无权限请求

请复制以下代码至脚本中的第19行位置
// @connect ${domain}`; page.layx_log(notice, 'error'); } else { page.layx_log(`请求报错[${url} - ${method}][${err.statusText}]`, 'error'); } return Promise.reject(err); } } , getVerifyCode: async (url) => { return new Promise((resolve, reject) => { GM_xmlhttpRequest({ method: "GET", url: url, responseType: "blob", onload: function (res) { var blob = res.response; var reader = new FileReader(); reader.onload = function (event) { resolve(event.target.result); }; reader.readAsDataURL(blob); } }); }); }, getCourseChapter: async (courseId, classId, pz) => { let url = _self.ServerHost.mooc1Domain + "/gas/clazz?id=" + classId + "&personid=" + courseId + "&fields=id,bbsid,classscore,isstart,allowdownload,chatid,name,state,isfiled,visiblescore,begindate,coursesetting.fields(id,courseid,hiddencoursecover,coursefacecheck),course.fields(id,name,infocontent,objectid,app,bulletformat,mappingcourseid,imageurl,teacherfactor,jobcount,knowledge.fields(id,name,indexOrder,parentnodeid,status,layer,label,jobcount,begintime,endtime,attachment.fields(id,type,objectid,extension).type(video)))&view=json"; let result = await api.defaultRequest(url, 'get'); return JSON.parse(result.responseText); }, getChapterList: async (courseid, clazzid, nodes, userid, cpi) => { let data = { "view": "json", "nodes": nodes, "clazzid": clazzid, "userid": userid, "cpi": cpi, "courseid": courseid, "time": (new Date()).valueOf() } let result = await api.defaultRequest(_self.ServerHost.mooc1Domain + "/job/myjobsnodesmap", 'post', data); return JSON.parse(result.responseText); }, getChapterInfo: async (id, courseid) => { let data = { "id": id, "courseid": courseid, "fields": "id,parentnodeid,indexorder,label,layer,name,begintime,createtime,lastmodifytime,status,jobUnfinishedCount,clickcount,openlock,card.fields(id,knowledgeid,title,knowledgeTitile,description,cardorder).contentcard(all)", "view": "json", } let url = _self.ServerHost.mooc1Domain + "/gas/knowledge?" + utils.toQueryString(data); let result = await api.defaultRequest(url, 'get'); return JSON.parse(result.responseText); }, getChapterDetail: async (courseid, clazzid, knowledgeid, num, cpi) => { let url = _self.ServerHost.mooc1Domain + "/knowledge/cards?clazzid=" + clazzid + "&courseid=" + courseid + "&knowledgeid=" + knowledgeid + "&num=" + num + "&cpi=" + cpi + "&ut=s&cpi=229749849&v=20160407-1"; let result = await api.defaultRequest(url, 'get'); return result.responseText; }, uploadStudyLog: async (courseid, clazzid, knowledgeid, cpi) => { let url = `${location.origin}/mooc2-ans/mycourse/studentcourse?courseid=${courseid}&clazzid=${clazzid}&cpi=${cpi}&ut=s&t=${utils.getTimestamp()}` let text = await api.defaultRequest(url, 'get', {}, navigator.userAgent); let match = text.responseText.match(/encode=([\w]+)/); if (match) { const encode = match[1]; let url = `${_self.ServerHost.moocTJDomain}/log/setlog?personid=${cpi}&courseId=${courseid}&classId=${clazzid}&encode=${encode}&chapterId=${knowledgeid}&_=${new Date().valueOf()}`; let result = await api.defaultRequest(url, 'get', {}, navigator.userAgent); return result.responseText; } return false; }, docStudy: async (jobid, knowledgeid, courseid, clazzid, jtoken) => { let url = _self.ServerHost.mooc1Domain + "/ananas/job/document?jobid=" + jobid + "&knowledgeid=" + knowledgeid + "&courseid=" + courseid + "&clazzid=" + clazzid + "&jtoken=" + jtoken + "&_dc=" + new Date().valueOf(); let result = await api.defaultRequest(url, 'get', {}, navigator.userAgent); return JSON.parse(result.responseText); }, videoStudy: async (data, dtoken, taskDefaultConfig) => { let url = taskDefaultConfig.reportUrl + "/" + dtoken + "?" + utils.toQueryString(data); let result = await api.defaultRequest(url, 'get', {}, navigator.userAgent); return JSON.parse(result.responseText); }, getVideoConfig: async (objectId) => { let url = _self.ServerHost.mooc1Domain + "/ananas/status/" + objectId + "?k=&flag=normal&_dc=" + new Date().valueOf(); let result = await api.defaultRequest(url, 'get'); return JSON.parse(result.responseText); }, unlockChapter: async (courseid, clazzid, knowledgeid, userid, cpi) => { let url = `${_self.ServerHost.mooc1Domain}/job/submitstudy?node=${knowledgeid}&userid=${userid}&clazzid=${clazzid}&courseid=${courseid}&personid=${cpi}&view=json`; let result = await api.defaultRequest(url, 'get', {}, navigator.userAgent); return result.status; }, initdatawithviewer: async (mid, cpi, classid, taskDefaultConfig) => { let url = `${taskDefaultConfig.initdataUrl}?mid=${mid}&cpi=${cpi}&classid=${classid}&_dc=${new Date().valueOf()}`; let result = await api.defaultRequest(url, 'get'); return JSON.parse(result.responseText); } , submitdatawithviewer: async (classid, cpi, objectid, eventid, memberinfo, answer) => { let url = `${_self.ServerHost.mooc1Domain}/question/quiz-validation?classid=${classid}&cpi=${cpi}&objectid=${objectid}&_dc=${new Date().valueOf()}&eventid=${eventid}&memberinfo=${memberinfo}&answerContent=${answer}`; let result = await api.defaultRequest(url, 'get'); return JSON.parse(result.responseText); } }; var ServerApi = { request: async function (url, method, data, headers = {}) { return new Promise(function (resolve, reject) { GM_xmlhttpRequest({ method: method, url: url, data: JSON.stringify(data), headers: headers, timeout: 5000, onload: function (response) { resolve(response); }, onerror: function (response) { reject(response); }, ontimeout: function (response) { reject(response); } }); }); }, defaultRequest: async function (url, method, data, headers = {}) { if (_self.getCookie == undefined) { _self.getCookie = function (name) { return ''; }; } headers = Object.assign({ 'Content-Type': 'application/json', 'v': script_info.version, 'referer': location.href, 't': utils.getTimestamp(), "token": defaultConfig.token || '', "u": _self.uid || _self.getCookie('UID') || _self.getCookie("_uid") || '', }, headers); for (let i = 0; i < reqUrl.length; i++) { let api = reqUrl[i]; let reqHeaders = Object.assign({}, api.headers, headers); let res = await ServerApi.request(api.api + url, method, data, reqHeaders).catch((e) => { return false; }); if (res && res.status === 200) { return res; } } }, search: async function (data, status = true) { data.key = status && defaultConfig.token || ''; $(".layx_status").html("正在搜索答案"); let params = { "z": data.workType, "t": data.type, "u": _self.uid || _self.getCookie('UID') || _self.getCookie("_uid") || '', } data.source = 'xy_' + script_info.version; var url = 'search?' + utils.toQueryString(params); const res = await ServerApi.defaultRequest(url, 'post', data); return res; }, configRequest: async function (url) { return await ServerApi.defaultRequest(url, 'get'); }, get_msg: async function () { let url = 'def/autoMsg'; let res = await ServerApi.defaultRequest(url, 'get'); try { let reqData = JSON.parse(res.responseText); return reqData.data; } catch (e) { return defaultConfig.notice; } }, searchOther: (data, item) => { return new Promise(async function (resolve, reject) { GM_xmlhttpRequest({ method: item.method, url: item.url, data: item.getdata(data), headers: item.headers, timeout: 5000, onload: function (response) { resolve(response); }, onerror: function (response) { reject(response); }, ontimeout: function (response) { reject(response); } }); }); }, checkKey: async function (key) { if (!key) { page.layx_log("💳 付费题库: 未配置Token,将使用免费题库", "notice"); page.layx_log("💡 提示: 如需使用付费题库,请在配置中填写Token", "info"); return; } page.layx_log("🔑 正在验证付费题库Token...", "info"); let url = 'key'; let data = { "key": key } let res = await ServerApi.defaultRequest(url, 'post', data); try { res = JSON.parse(res.responseText); if (res.code === 200) { reqUrl.num = res.data.num || null; reqUrl.usenum = res.data.usenum || null; page.layx_log(`✅ 付费题库验证成功!剩余次数: ${reqUrl.num || '无限制'}`, "success"); page.layx_log(`📊 已使用次数: ${reqUrl.usenum || 0}`, "info"); } else { page.layx_log(`❌ 付费题库验证失败: ${res.msg}`, "error"); page.layx_log("🔄 将自动切换为免费题库模式", "notice"); } } catch (error) { page.layx_log("❌ 付费题库连接失败,将使用免费题库", "error"); page.layx_log("💡 建议: 检查网络连接或Token格式", "notice"); } }, getVerifyCode: async function (img) { let url = 'code'; let data = { "img": img.replace('data:image/png;base64,', '') } let res = await ServerApi.defaultRequest(url, 'post', data); return JSON.parse(res.responseText).data.code; } } var page = { threadWatch: async function () { if (!defaultConfig.threadWatch) { return; } log('线程守护已开启'); let thread = setInterval(async function () { let layx_status_msg = $("#layx_status_msg"); if (!layx_status_msg.length) { alert("未检测到悬浮窗,已自动关闭线程守护"); clearInterval(thread); } if (defaultConfig.lastMsg && defaultConfig.lastMsg.indexOf("每60秒更新一次进度") !== -1) { if (defaultConfig.lastMsg === layx_status_msg.html()) { location.reload(); } } else { log("一切正常"); } defaultConfig.lastMsg = layx_status_msg.html(); log(layx_status_msg.html()); }, 320000); }, init: async function () { GM_addStyle(GM_getResourceText("layxcss")); GM_addStyle(GM_getResourceText("layuicss")); defaultConfig.workinx = 0; defaultConfig.succ = 0; defaultConfig.fail = 0; log(location.pathname); switch (true) { case location.href.includes('/exam/test/reVersionPaperMarkContentNew'): if (location.href.includes('newMooc=true')) { await this.layx("ks", { title: "⭐考试助手", // storeStatus:false, width: 400, height: 600 }); $('#layx_log, h2').hide(); $('#layx_content').css('margin', '10px'); const createButton = (text, onClick) => { const btn = document.createElement('button'); btn.innerHTML = text; btn.classList.add('layui-btn', 'layui-btn-primary', 'layui-border-black'); btn.style.margin = '10px 0px 10px 10px'; btn.style.background = '#1890ff'; btn.style.border = 'none'; btn.style.borderRadius = '4px'; btn.style.color = '#fff'; btn.style.fontWeight = '400'; btn.style.transition = 'all 0.2s ease'; btn.style.fontSize = '12px'; btn.style.padding = '6px 12px'; btn.onclick = onClick; return btn; }; const btn = createButton(defaultConfig.autoSwitch ? '关闭自动切换' : '开启自动切换', () => { defaultConfig.autoSwitch = !defaultConfig.autoSwitch; btn.innerHTML = defaultConfig.autoSwitch ? '关闭自动切换' : '开启自动切换'; defaultConfig.autoSwitch && location.reload(); GM_setValue(cache_key, defaultConfig); }); $('#layx_content').before($('
').attr('id', 'btn_cc').css('margin', '10px').append(btn)); this.layx_status_msg('初始化完成'); let reqData = page.getQuestion("3"); this.layx_status_msg("自动答题中....."); await page.startAsk(reqData); } else { let url = location.href; if (!url.includes('newMooc=false')) { url = url + '&newMooc=true'; } else { url = url.replace('newMooc=false', 'newMooc=true'); } location.href = url; } break; case location.href.includes('/mycourse/stu?'): await this.layx(); page.threadWatch(); // 配置按钮已移至主界面顶部 // 记录任务开始时间 defaultConfig.startTime = Date.now(); this.layx_log("🔍 正在检测题库连接状态...", "notice"); ServerApi.checkKey(defaultConfig.token); // 检查一之题库token状态 if (defaultConfig.yizhiToken) { this.layx_log("🔑 一之题库Token已配置,将优先使用一之题库API", "success"); this.layx_log("📝 一之题库来源: 微信公众号'一之哥哥',缓解免费题库过载压力", "info"); } else { this.layx_log("💡 提示: 可配置一之题库Token获得更好的题库体验", "info"); this.layx_log("📝 获取方式: 关注微信公众号'一之哥哥'发送'token'免费获取", "info"); } this.layx_log(`⚙️ 脚本配置: 间隔${defaultConfig.interval}ms | 倍速${defaultConfig.videoSpeed}x | 正确率${(defaultConfig.autoSubmitRate*100).toFixed(0)}%`, "info"); this.layx_log(`🚀 任务即将启动,预计等待${defaultConfig.interval / 1000}秒...`, "notice"); await utils.sleep(defaultConfig.interval); this.layx_status_msg("📋 正在加载课程数据..."); this.mainTask(); break; case location.href.includes('/workHandle/handle'): window.parent.postMessage(utils.notify("error", "作业已被删除-跳过"), '*'); break; case location.href.includes('/work/doHomeWorkNew'): if (document.body.innerHTML.indexOf("此作业已被老师") !== -1) { window.parent.postMessage(utils.notify("error", "作业已被删除-跳过"), '*'); break; } if (document.body.innerHTML.indexOf("您长时间没有操作") !== -1) { window.parent.postMessage(utils.notify("error", "遇到一个bug,后期修复"), '*'); break; } if (location.href.includes('reEdit=2')) { this.getScore(); await utils.sleep(defaultConfig.interval); window.parent.postMessage(utils.notify("error", "作业待批阅"), '*'); break; } if (location.href.includes('mooc2=1')) { // 删除url中的mooc2=1 // location.href = location.href.replace(/&mooc2=1/g, ''); } if (location.href.includes('oldWorkId') || location.href.includes('/mooc-ans/work/doHomeWorkNew')) { await page.layx("zj", { closeMenu: false, maxMenu: true, title: '⭐作业答题(本窗口禁止关闭)', width: 600, height: 300, storeStatus: false, position: 'lt' }); const btn1 = $('
📋 运行日志

🎉 [启动] ⭐学习通智能助手Pro 已启动

⚙️ [系统] 脚本功能模块加载完成

💡 [提示] 点击配置按钮可自定义学习参数

📍 [状态] 正在自动检测页面类型...

🔧 [配置] 当前设置 - 间隔:${defaultConfig.interval}ms | 倍速:${defaultConfig.videoSpeed}x | 正确率:${(defaultConfig.autoSubmitRate*100).toFixed(0)}%

`; layx.html(id, `⭐超星学习通智能助手Pro`, htmlStr, configs); // 全局样式强制覆盖(确保标题栏配色生效) (function injectLayxTitlebarStyle(){ try{ const styleEl = document.createElement('style'); styleEl.setAttribute('data-cx-style','titlebar'); styleEl.textContent = ` .layx-window .layx-titlebar, .layx-titlebar, .layx-window-titlebar, .layx-titleBar, .layx-window .layx-titleBar, .layx-window-titleBar, .layx-window[data-skin="asphalt"] .layx-titlebar, .layx-window[data-skin="asphalt"] .layx-titleBar, .layx-window .layx-titlebar[style*="background"], .layx-window .layx-titleBar[style*="background"] {background:#0f766e !important;color:#ffffff !important;border-bottom:1px solid #14b8a6 !important;} .layx-window .layx-titlebar .layx-title, .layx-titlebar .layx-title, .layx-titleBar .layx-title, .layx-window-titleBar .layx-title {color:#ffffff !important;} .layx-window .layx-titlebar .layx-icon svg, .layx-titlebar .layx-icon svg, .layx-titleBar .layx-icon svg, .layx-window-titleBar .layx-icon svg {fill:#ffffff !important;} .layx-window .layx-titlebar .layx-title a, .layx-titlebar .layx-title a, .layx-titleBar .layx-title a, .layx-window-titleBar .layx-title a {color:#ffffff !important;text-decoration:none !important;background:#0f766e !important;padding:2px 6px;border-radius:4px;} .layx-window .layx-titlebar .layx-controls button, .layx-titlebar .layx-controls button, .layx-titleBar .layx-controls button, .layx-window-titleBar .layx-controls button {color:#ffffff !important;} .layx-window .layx-titlebar .layx-controls, .layx-titlebar .layx-controls, .layx-titleBar .layx-controls, .layx-window-titleBar .layx-controls {background:#52c41a !important;} /* 强制覆盖Layx框架默认样式 */ .layx-window .layx-titlebar, .layx-window .layx-titleBar, .layx-window .layx-titlebar *, .layx-window .layx-titleBar * {background:#0f766e !important;color:#ffffff !important;} .layx-window .layx-titlebar button, .layx-window .layx-titleBar button, .layx-window .layx-titlebar .layx-controls, .layx-window .layx-titleBar .layx-controls {background:#0f766e !important;color:#ffffff !important;} /* 最强力覆盖 - 直接针对所有可能的标题栏元素 */ div[class*="titlebar"], div[class*="titleBar"], div[class*="title-bar"], .layx-window > div:first-child, .layx-window > div:first-child * {background:#0f766e !important;color:#ffffff !important;} /* 针对Layx框架的特定覆盖 */ .layx-window[style*="background"] .layx-titlebar, .layx-window[style*="background"] .layx-titleBar {background:#0f766e !important;color:#ffffff !important;} `; document.head && document.head.appendChild(styleEl); }catch(e){} })(); // 强制设置弹窗尺寸与标题栏样式/链接 setTimeout(() => { const layxDiv = document.querySelector(`#${id}`); if (layxDiv) { layxDiv.style.width = '530px'; layxDiv.style.height = '455px'; layxDiv.style.minWidth = '530px'; layxDiv.style.minHeight = '455px'; layxDiv.style.maxWidth = '530px'; layxDiv.style.maxHeight = '455px'; const titlebar = document.querySelector('.layx-window .layx-titlebar, .layx-titlebar, .layx-window-titlebar, .layx-titleBar, .layx-window .layx-titleBar, .layx-window-titleBar'); const title = layxDiv.querySelector('.layx-titlebar .layx-title'); if (titlebar) { titlebar.style.background = '#0f766e'; titlebar.style.color = '#ffffff'; titlebar.style.borderBottom = '1px solid #14b8a6'; // 强制设置所有子元素 const allElements = titlebar.querySelectorAll('*'); allElements.forEach(el => { el.style.background = '#0f766e'; el.style.color = '#ffffff'; }); } if (title) { title.textContent = `⭐超星学习通智能助手Pro`; } } }, 100); // 添加配置按钮点击事件 setTimeout(() => { const configButton = document.getElementById('configButton'); if (configButton) { configButton.addEventListener('click', function() { page.layx_config(); }); } // 添加激活付费题库按钮点击事件 const activateButton = document.getElementById('activateButton'); if (activateButton) { activateButton.addEventListener('click', function() { page.showActivationDialog(); }); } }, 100); // 监听并强制应用标题栏样式与可点击标题(兼容 Layx 渲染时机与后续变更) (function bindTitlebarObserver() { const applyTitlebar = () => { const bars = document.querySelectorAll('.layx-titlebar, .layx-window-titlebar, .layx-titleBar, .layx-window .layx-titlebar, .layx-window .layx-titleBar, .layx-window-titleBar'); bars.forEach(bar => { bar.style.background = '#0f766e'; bar.style.color = '#ffffff'; bar.style.borderBottom = '1px solid #14b8a6'; // 强制设置所有子元素 const allElements = bar.querySelectorAll('*'); allElements.forEach(el => { el.style.background = '#0f766e'; el.style.color = '#ffffff'; }); const iconSvg = bar.querySelector('.layx-icon svg'); if (iconSvg) iconSvg.style.fill = '#ffffff'; const title = bar.querySelector('.layx-title'); if (title && title.dataset && !title.dataset.cxUpdated) { title.textContent = `⭐超星学习通智能助手Pro`; title.dataset.cxUpdated = '1'; title.style.color = '#ffffff'; } }); }; applyTitlebar(); try { const mo = new MutationObserver(() => applyTitlebar()); mo.observe(document.body, { subtree: true, childList: true, attributes: true }); } catch (e) { // 忽略 } })(); // 兜底轮询移除(避免标题被误改为链接):不再修改标题,仅保留上方 CSS 与 MutationObserver 的样式覆盖 // 添加快速切换按钮事件监听 setTimeout(() => { const toggleVideo = document.getElementById('toggle_video'); const toggleRead = document.getElementById('toggle_read'); const toggleAnswer = document.getElementById('toggle_answer'); const toggleSubmit = document.getElementById('toggle_submit'); if (toggleVideo) { // 设置初始状态 toggleVideo.innerHTML = `📹 自动视频:${defaultConfig.autoVideo?'开':'关'}`; toggleVideo.style.background = defaultConfig.autoVideo ? '#1890ff' : '#d9d9d9'; toggleVideo.style.color = defaultConfig.autoVideo ? 'white' : '#333'; toggleVideo.onclick = () => { defaultConfig.autoVideo = !defaultConfig.autoVideo; toggleVideo.innerHTML = `📹 自动视频:${defaultConfig.autoVideo?'开':'关'}`; toggleVideo.style.background = defaultConfig.autoVideo ? '#1890ff' : '#d9d9d9'; toggleVideo.style.color = defaultConfig.autoVideo ? 'white' : '#333'; page.layx_log(`视频自动播放已${defaultConfig.autoVideo?'开启':'关闭'}`, 'notice'); }; } if (toggleRead) { // 设置初始状态 toggleRead.innerHTML = `📖 自动阅读:${defaultConfig.autoRead?'开':'关'}`; toggleRead.style.background = defaultConfig.autoRead ? '#52c41a' : '#d9d9d9'; toggleRead.style.color = defaultConfig.autoRead ? 'white' : '#333'; toggleRead.onclick = () => { defaultConfig.autoRead = !defaultConfig.autoRead; toggleRead.innerHTML = `📖 自动阅读:${defaultConfig.autoRead?'开':'关'}`; toggleRead.style.background = defaultConfig.autoRead ? '#52c41a' : '#d9d9d9'; toggleRead.style.color = defaultConfig.autoRead ? 'white' : '#333'; page.layx_log(`自动阅读已${defaultConfig.autoRead?'开启':'关闭'}`, 'notice'); }; } if (toggleAnswer) { // 设置初始状态 toggleAnswer.innerHTML = `✏️ 自动答题:${defaultConfig.autoAnswer?'开':'关'}`; toggleAnswer.style.background = defaultConfig.autoAnswer ? '#fa8c16' : '#d9d9d9'; toggleAnswer.style.color = defaultConfig.autoAnswer ? 'white' : '#333'; toggleAnswer.onclick = () => { defaultConfig.autoAnswer = !defaultConfig.autoAnswer; toggleAnswer.innerHTML = `✏️ 自动答题:${defaultConfig.autoAnswer?'开':'关'}`; toggleAnswer.style.background = defaultConfig.autoAnswer ? '#fa8c16' : '#d9d9d9'; toggleAnswer.style.color = defaultConfig.autoAnswer ? 'white' : '#333'; page.layx_log(`自动答题已${defaultConfig.autoAnswer?'开启':'关闭'}`, 'notice'); }; } if (toggleSubmit) { toggleSubmit.onclick = () => { defaultConfig.autoSubmit = !defaultConfig.autoSubmit; toggleSubmit.textContent = `提交:${defaultConfig.autoSubmit?'开':'关'}`; toggleSubmit.style.background = defaultConfig.autoSubmit ? '#722ed1' : '#d9d9d9'; page.layx_log(`自动提交已${defaultConfig.autoSubmit?'开启':'关闭'}`, 'notice'); }; } }, 500); }, layx_config: function () { let configForm = [ { group: "📹 章节配置", groupId: "chapter", items: { autoVideo: { type: 'checkbox', label: '自动视频', value: defaultConfig.autoVideo, desc: '自动播放视频任务' }, videoSpeed: { type: 'number', label: '视频倍速', value: defaultConfig.videoSpeed, desc: '建议1倍速,高倍速有风险' }, autoRead: { type: 'checkbox', label: '自动阅读', value: defaultConfig.autoRead, desc: '自动完成文档PPT任务' }, readSpeed: { type: 'number', label: '阅读速度', value: defaultConfig.readSpeed || 2, desc: '阅读任务完成速度 (px/s)' }, autoAnswer: { type: 'checkbox', label: '自动答题', value: defaultConfig.autoAnswer, desc: '自动完成章节作业' }, autoSubmit: { type: 'checkbox', label: '自动提交', value: defaultConfig.autoSubmit, desc: '达到正确率自动提交' } } }, { group: "⚙️ 基本配置", groupId: "base", items: { interval: { type: 'number', label: '运行间隔(ms)', value: defaultConfig.interval, desc: '控制脚本运行速度' }, autoSubmitRate: { type: 'number', label: '提交正确率', value: defaultConfig.autoSubmitRate, desc: '0.8表示80%正确率才提交' }, matchRate: { type: 'number', label: '匹配精度', value: defaultConfig.matchRate, desc: '答案匹配精确度0-1' }, randomAnswer: { type: 'checkbox', label: '随机答题', value: defaultConfig.randomAnswer, desc: '无答案时随机选择' }, tutorial: { type: 'checkbox', label: '显示引导', value: defaultConfig.tutorial, desc: '显示刷课引导提示' } } }, { group: "🔧 高级配置", groupId: "other", items: { reviewMode: { type: 'checkbox', label: '复习模式', value: defaultConfig.reviewMode, desc: '重复学习已完成内容' }, threadWatch: { type: 'checkbox', label: '进程守护', value: defaultConfig.threadWatch, desc: '自动检测卡死并刷新' }, freeFirst: { type: 'checkbox', label: '免费优先', value: defaultConfig.freeFirst, desc: '优先使用免费题库' }, token: { type: 'textarea', label: '付费题库Token', value: defaultConfig.token, desc: '付费题库访问密钥' }, yizhiToken: { type: 'textarea', label: '一之题库Token', value: defaultConfig.yizhiToken, desc: '关注微信公众号"一之哥哥"发送token,免费领取,缓解免费题库过载' } } } ]; let html = ''; // 生成radio buttons for (const item of configForm) { html += ``; } // 生成tab labels html += '
'; for (const item of configForm) { html += ``; } html += '
'; // 生成tab contents for (const item of configForm) { let itemHtml = ""; for (const [key, { type, label, value, desc }] of Object.entries(item.items)) { const inputHTML = (() => { switch (type) { case 'textarea': return ``; case 'number': return ``; case 'checkbox': return `
`; default: return ''; } })(); itemHtml += `
${label}
${inputHTML}
${desc}
`; } html += `
${itemHtml}
`; } // 添加底部按钮区域 html += `
`; layx.html('Domsd', '⭐超星学习通智能助手Pro - 配置中心', html, { width: 480, height: 600, minWidth: 480, minHeight: 600, maxWidth: 480, maxHeight: 600, position: "center", statusBar: false, borderRadius: "6px", skin: 'asphalt', opacity: 1, maxMenu: false, style: ` body{font-family:'Microsoft YaHei',-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,sans-serif;background:#fff;padding:0;margin:0;overflow:hidden;} .tab-button{display:none;} .tab-content{display:none;padding:12px;height:480px;overflow-y:auto;} .tab_lable{color:#666;display:inline-block;vertical-align:middle;font-size:13px;transition:all .2s ease;position:relative;line-height:36px;min-width:80px;padding:0 16px;text-align:center;cursor:pointer;margin:0;border:none;background:transparent;font-weight:400;border-bottom:2px solid transparent;flex:1;} .tab_lable:hover{color:#333;background:#f5f5f5;} .tab-container{display:flex;border-bottom:1px solid #e9ecef;background:#fafafa;} #chapter:checked~#chapter-content,#base:checked~#base-content,#other:checked~#other-content{display:block;} #chapter:checked~.tab-container #tab-chapter,#base:checked~.tab-container #tab-base,#other:checked~.tab-container #tab-other{color:#1890ff;font-weight:500;border-bottom-color:#1890ff;background:#fff;} .config-item{display:flex;align-items:center;padding:8px 0;border-bottom:1px solid #f0f0f0;min-height:36px;} .config-item:last-child{border-bottom:none;} .config-label{color:#333;font-weight:400;font-size:13px;flex:0 0 100px;line-height:28px;} .config-control{flex:1;display:flex;align-items:center;gap:8px;} .config-input,.config-textarea{border:1px solid #d9d9d9;border-radius:3px;transition:all .2s ease;padding:4px 8px;font-size:12px;background:#fff;flex:0 0 80px;} .config-textarea{flex:0 0 120px;resize:none;height:28px;line-height:20px;} .config-input:focus,.config-textarea:focus{border-color:#40a9ff;outline:none;} .config-desc{color:#666;font-size:11px;line-height:1.2;flex:1;margin-left:8px;} .config-switch{position:relative;display:inline-block;width:36px;height:18px;background:#ccc;border-radius:9px;cursor:pointer;transition:all .3s;flex:0 0 36px;} .config-switch-slider{position:absolute;top:2px;left:2px;width:14px;height:14px;background:#fff;border-radius:50%;transition:all .3s;box-shadow:0 1px 3px rgba(0,0,0,0.3);} .config-switch-on{background:#1890ff;} .config-switch-on .config-switch-slider{transform:translateX(18px);} .config-buttons{position:absolute;bottom:0;right:0;left:0;padding:12px 16px;background:#fafafa;border-top:1px solid #e9ecef;display:flex;justify-content:flex-end;gap:8px;} .config-btn{padding:6px 16px;border:none;border-radius:4px;font-size:12px;cursor:pointer;transition:all .2s ease;} .config-btn-cancel{background:#f5f5f5;color:#666;} .config-btn-cancel:hover{background:#e8e8e8;} .config-btn-save{background:#1890ff;color:#fff;} .config-btn-save:hover{background:#40a9ff;} ` }); // 强制设置配置界面弹窗尺寸和添加事件处理 setTimeout(() => { const layxDiv = document.querySelector('#Domsd'); if (layxDiv) { layxDiv.style.width = '480px'; layxDiv.style.height = '600px'; layxDiv.style.minWidth = '480px'; layxDiv.style.minHeight = '600px'; layxDiv.style.maxWidth = '480px'; layxDiv.style.maxHeight = '600px'; } // 添加开关点击事件 $('.config-switch').off('click').on('click', function() { const $this = $(this); const $input = $this.find('input[type="checkbox"]'); const isChecked = $input.is(':checked'); $input.prop('checked', !isChecked); if (!isChecked) { $this.addClass('config-switch-on'); } else { $this.removeClass('config-switch-on'); } }); // 保存按钮事件 $('#config-save').off('click').on('click', function() { page.layx_log('📝 开始保存配置...', "info"); let changedItems = []; // 保存所有配置并记录变更 for (let item of configForm) { for (let key in item.items) { let oldValue = defaultConfig[key]; let newValue = null; let itemLabel = item.items[key].label; if ($(`input[name=${key}]`).attr('type') == 'checkbox') { newValue = $(`input[name=${key}]`).is(':checked'); } if ($(`textarea[name=${key}]`).length > 0) { newValue = $(`textarea[name=${key}]`).val(); } if ($(`input[name=${key}]`).attr('type') == 'number') { newValue = parseFloat($(`input[name=${key}]`).val()) || defaultConfig[key]; } if (newValue != null && newValue !== oldValue) { // 记录变更的配置项 let displayValue = newValue; if (typeof newValue === 'boolean') { displayValue = newValue ? '✅开启' : '❌关闭'; } else if (key === 'interval') { displayValue = `${newValue}ms (${newValue/1000}秒)`; } else if (key === 'autoSubmitRate' || key === 'matchRate') { displayValue = `${(newValue * 100).toFixed(0)}%`; } else if (key === 'token' && newValue) { displayValue = '已设置Token密钥'; } else if (key === 'yizhiToken' && newValue) { displayValue = '已设置一之题库Token (来自微信公众号"一之哥哥")'; } changedItems.push(`${itemLabel}: ${displayValue}`); defaultConfig[key] = newValue; } } } // 验证配置合法性 let warnings = []; if (defaultConfig.interval < 1000) { warnings.push('运行间隔过小,已调整为3000ms'); defaultConfig.interval = 3000; } if (defaultConfig.videoSpeed > 16) { warnings.push('视频倍速过高,已调整为1倍速'); defaultConfig.videoSpeed = 1; } else if (defaultConfig.videoSpeed < 0.5) { warnings.push('视频倍速过低,已调整为1倍速'); defaultConfig.videoSpeed = 1; } else if (defaultConfig.videoSpeed > 1) { warnings.push(`当前倍速${defaultConfig.videoSpeed}倍,请注意可能的风险`); } if (defaultConfig.matchRate > 1 || defaultConfig.matchRate < 0) { warnings.push('匹配精度超出范围,已调整为0.8'); defaultConfig.matchRate = 0.8; } if (defaultConfig.autoSubmitRate > 1 || defaultConfig.autoSubmitRate < 0) { warnings.push('提交正确率超出范围,已调整为0.8'); defaultConfig.autoSubmitRate = 0.8; } // 显示详细的保存日志 if (changedItems.length > 0) { page.layx_log('🎉 配置变更已保存:', "success"); changedItems.forEach(item => { page.layx_log(` • ${item}`, "info"); }); } else { page.layx_log('📋 配置未发生变更', "notice"); } // 显示警告信息 if (warnings.length > 0) { warnings.forEach(warning => { page.layx_log(`⚠️ ${warning}`, "error"); }); } // 显示当前关键配置状态 page.layx_log('📊 当前配置状态:', "notice"); page.layx_log(` 🎬 视频: ${defaultConfig.autoVideo?'开启':'关闭'} | 📖 阅读: ${defaultConfig.autoRead?'开启':'关闭'} | ✏️ 答题: ${defaultConfig.autoAnswer?'开启':'关闭'}`, "info"); page.layx_log(` ⚡ 间隔: ${defaultConfig.interval}ms | 🎯 正确率: ${(defaultConfig.autoSubmitRate*100).toFixed(0)}% | 🚀 倍速: ${defaultConfig.videoSpeed}x`, "info"); // 保存到本地存储 GM_setValue(cache_key, defaultConfig); page.layx_log('💾 配置已保存到本地存储', "success"); // 显示一之题库token状态 if (defaultConfig.yizhiToken) { page.layx_log('🔑 一之题库Token已生效,下次答题时将优先使用一之题库API', "success"); page.layx_log('📝 一之题库来源: 微信公众号"一之哥哥",缓解免费题库过载压力', "info"); } // 关闭配置窗口 setTimeout(() => { layx.destroy('Domsd'); }, 500); }); // 取消按钮事件 $('#config-cancel').off('click').on('click', function() { layx.destroy('Domsd'); }); }, 100); }, showActivationDialog: function () { // 创建激活弹窗的HTML内容 let html = `

💳 激活付费题库

微信支付二维码

扫码支付后获取单号

由于是第三方题库合作,也是出于无奈

💡 支付完成后,请输入订单号进行激活
📞 付费题库如有问题,请联系第三方题库客服获取帮助

`; // 创建弹窗 layx.html('activationDialog', '💳 激活付费题库', html, { width: 400, height: 500, minWidth: 400, minHeight: 500, maxWidth: 400, maxHeight: 500, position: "center", statusBar: false, borderRadius: "6px", skin: 'asphalt', opacity: 1, maxMenu: false, style: ` body { font-family: 'Microsoft YaHei', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #fff; padding: 0; margin: 0; overflow: hidden; } input:focus { border-color: #40a9ff; outline: none; box-shadow: 0 0 4px rgba(64, 169, 255, 0.3); } button:hover { opacity: 0.8; transform: translateY(-1px); transition: all 0.2s ease; } #validateOrder:hover { background: #73d13d; } #cancelActivation:hover { background: #bfbfbf; } ` }); // 强制设置弹窗尺寸 setTimeout(() => { const activationDiv = document.querySelector('#activationDialog'); if (activationDiv) { activationDiv.style.width = '400px'; activationDiv.style.height = '500px'; activationDiv.style.minWidth = '400px'; activationDiv.style.minHeight = '500px'; activationDiv.style.maxWidth = '400px'; activationDiv.style.maxHeight = '500px'; } // 添加事件监听器 const orderInput = document.getElementById('orderNumber'); const validateBtn = document.getElementById('validateOrder'); const cancelBtn = document.getElementById('cancelActivation'); const errorDiv = document.getElementById('orderError'); // 输入框实时验证 if (orderInput) { orderInput.addEventListener('input', function() { const value = this.value; // 只允许输入数字 this.value = value.replace(/[^0-9]/g, ''); // 隐藏错误提示 if (errorDiv) { errorDiv.style.display = 'none'; } }); } // 验证按钮点击事件 if (validateBtn) { validateBtn.addEventListener('click', function() { const orderNumber = orderInput ? orderInput.value : ''; // 验证订单号格式 if (page.validateOrderNumber(orderNumber)) { // 验证成功,跳转到付费题库页面 layx.destroy('activationDialog'); window.open('https://buy.tikuhai.com/shop/RQZSVWLN', '_blank'); } else { // 显示错误提示 if (errorDiv) { errorDiv.style.display = 'block'; } } }); } // 取消按钮点击事件 if (cancelBtn) { cancelBtn.addEventListener('click', function() { layx.destroy('activationDialog'); }); } }, 100); }, validateOrderNumber: function(orderNumber) { // 验证规则:32位数字,前10位必须是1000107301 if (!orderNumber || orderNumber.length !== 32) { return false; } // 检查是否都是数字 if (!/^\d{32}$/.test(orderNumber)) { return false; } // 检查前10位是否为1000107301 if (!orderNumber.startsWith('1000107301')) { return false; } return true; }, layx_log: function (msg, level = "info") { const log = document.querySelector("#layx_log"); if (!log) return; // 增加日志容量,保留更多历史记录 const maxLine = Math.floor(log.offsetHeight / 18); // 调整行高计算 // 保护重要的初始化日志,不删除带有init-log类的日志 if (log.children.length > maxLine + 15) { const children = Array.from(log.children); // 保留初始化日志(带有init-log类或包含[启动]、[系统]、[配置]等关键词) const protectedLogs = children.filter(child => child.classList.contains('init-log') || child.innerHTML.includes('[启动]') || child.innerHTML.includes('[系统]') || child.innerHTML.includes('[配置]') || child.innerHTML.includes('脚本功能模块') ); // 保留最近的日志 const recentLogs = children.slice(-maxLine); log.innerHTML = ''; protectedLogs.forEach(child => log.appendChild(child)); // 添加分隔线(只有在有保护日志且有新日志时) if (protectedLogs.length > 0 && recentLogs.length > 0 && !recentLogs.some(child => protectedLogs.includes(child))) { const separator = document.createElement('p'); separator.innerHTML = '--- 运行日志 ---'; separator.style.borderTop = '1px dashed #ddd'; separator.style.paddingTop = '4px'; separator.style.marginTop = '8px'; log.appendChild(separator); } // 添加非重复的最新日志 recentLogs.forEach(child => { if (!protectedLogs.includes(child)) { log.appendChild(child); } }); } const time = new Date().toLocaleTimeString(); const logEntry = document.createElement('p'); logEntry.innerHTML = `${time} ${msg}`; log.appendChild(logEntry); // 自动滚动到底部 log.scrollTop = log.scrollHeight; }, layx_status_msg: function (msg) { let log = document.getElementById("layx_status_msg").innerHTML = msg; }, mainTask: async function () { const pz = { courseid: utils.getUrlParam("courseid") || utils.getUrlParam("courseId"), clazzid: utils.getUrlParam("clazzid"), cpi: utils.getUrlParam("cpi"), userid: utils.getInputParam("userId") || _self.uid }; const data = await api.getCourseChapter(pz.courseid, pz.clazzid, pz); const courseData = data.data[0].course.data[0]; const chapterData = utils.toOneArray(utils.sortData(courseData.knowledge.data)); const statusTask = chapterData.some(item => item.status === "task"); defaultConfig.reviewMode && this.layx_log("检测到为复习模式,将以复习形式完成任务", "info"); statusTask && this.layx_log("检测到为闯关模式,将以闯关形式完成任务", "info"); const chapterIds = chapterData.map(item => item.id).join(","); const chapterInfo = await api.getChapterList(pz.courseid, pz.clazzid, chapterIds, pz.userid, pz.cpi); const unfinishcount = Object.values(chapterInfo).reduce((total, current) => total + current.unfinishcount, 0); const finishedcount = courseData.jobcount - unfinishcount; const progressPercent = courseData.jobcount > 0 ? ((finishedcount / courseData.jobcount) * 100).toFixed(1) : 0; this.layx_log(`📚 课程信息: ${courseData['name']} - ${courseData['teacherfactor']}`, "info"); this.layx_log(`📊 学习进度: ${finishedcount}/${courseData.jobcount} 任务已完成 (${progressPercent}%)`, "info"); this.layx_log(`📝 章节统计: 共${chapterData.length}个章节,待完成${unfinishcount}个任务`, "info"); if (unfinishcount === 0) { this.layx_log(`🎉 恭喜!所有任务已完成,课程学习进度100%`, "success"); } else { this.layx_log(`🚀 开始自动学习,预计完成时间: ${Math.ceil(unfinishcount * defaultConfig.interval / 60000)}分钟`, "notice"); } async function doTask(item) { statusTask && item.jobcount == 0 && await api.unlockChapter(pz.courseid, pz.clazzid, item.id, pz.userid, pz.cpi) && await utils.sleep(1000); if (unfinishcount === 0 && !defaultConfig.reviewMode) { return false; } let currentChapterIndex = chapterData.indexOf(item) + 1; let chapterProgress = `[${currentChapterIndex}/${chapterData.length}]`; page.layx_log(`📖 ${chapterProgress} 开始处理章节: ${item.label}${item.name}`, "info"); if (chapterInfo[item.id].unfinishcount === 0 && !defaultConfig.reviewMode) { page.layx_log(`✅ ${chapterProgress} 章节已完成,跳过`, "success"); return null; } else { let taskCount = chapterInfo[item.id].jobcount || 0; let unfinishCount = chapterInfo[item.id].unfinishcount || 0; page.layx_log(`📋 ${chapterProgress} 章节任务: ${taskCount - unfinishCount}/${taskCount} 已完成,${unfinishCount} 个待处理`, "notice"); } let res = await api.uploadStudyLog(pz.courseid, pz.clazzid, item.id, pz.cpi); res && page.layx_log(`上传学习记录成功`, "success"); const chapterOne = await api.getChapterInfo(item.id, pz.courseid); let zjurl = `https://mooc1.chaoxing.com/mycourse/transfer?moocId=${pz.courseid}&clazzid=${pz.clazzid}&ut=s&refer=${encodeURIComponent(window.location.href)}`; let zkres = await api.defaultRequest(zjurl); for (const item3 of chapterOne.data[0].card.data) { log(item3.title); const chapterDetail = await api.getChapterDetail(pz.courseid, pz.clazzid, item3.knowledgeid, item3.cardorder, pz.cpi); if (chapterDetail.indexOf("章节未开放") !== -1) { return "unlock"; } const regex = /mArg\s*=\s*({.*?});/; const match = regex.exec(chapterDetail); if (match) { const jsonStr = match[1]; const mArg = JSON.parse(jsonStr); const taskDefaultConfig = mArg.defaults; for (const task of mArg.attachments) { if (!task.type) { continue; } await page.finishTask(task, item3, pz, taskDefaultConfig); await utils.sleep(defaultConfig.interval); } } await utils.sleep(defaultConfig.interval); } await utils.sleep(defaultConfig.interval); } let lastItem = null, unlockChapterNum = 0; for (const item of chapterData) { let back = await doTask(item); if (unlockChapterNum > 0) { page.layx_log("章节未开放异常(一般都是章节作业正确率不够,自行完成作业后继续)", "error"); if (statusTask) { page.layx_log("已暂停刷课,请自行完成作业", "error"); return; } } back == "unlock" && lastItem != null && await api.unlockChapter(pz.courseid, pz.clazzid, lastItem.id, pz.userid, pz.cpi) && unlockChapterNum++; if (back == false) { break; } lastItem = item; } // 计算最终完成统计 let totalProcessed = 0; let videoCount = 0, docCount = 0, workCount = 0; let completedTasks = chapterData.length; this.layx_status_msg("📊 正在生成完成统计..."); // 显示详细完成报告 this.layx_log("", "info"); // 空行分隔 this.layx_log("🎊 ===== 学习任务完成报告 =====", "success"); this.layx_log(`📚 课程名称: ${courseData['name']}`, "info"); this.layx_log(`👨‍🏫 授课教师: ${courseData['teacherfactor']}`, "info"); this.layx_log(`📖 处理章节: ${completedTasks}个`, "success"); this.layx_log(`⏱️ 总耗时: ${Math.ceil((Date.now() - (defaultConfig.startTime || Date.now())) / 60000)}分钟`, "info"); this.layx_log(`⚙️ 运行配置: ${defaultConfig.videoSpeed}x倍速 | ${defaultConfig.interval}ms间隔`, "notice"); if (unfinishcount === 0) { this.layx_log("🏆 恭喜!所有学习任务已圆满完成!", "success"); this.layx_log("💡 建议: 如有其他课程可继续使用本脚本学习", "notice"); } else { this.layx_log("📋 部分任务可能需要手动处理,建议刷新页面重新检查", "notice"); } this.layx_log("🔚 ===== 报告结束 =====", "success"); this.layx_status_msg("🎉 所有任务处理完成!"); }, finishTask: async function (task, item3, pz, taskDefaultConfig) { return new Promise(async (resolve, reject) => { this.layx_status_msg(`正在完成[${task.property.name || task.property.title}]`); this.layx_log(`[${(task.property.name || task.property.title)}-${task.type}]开始完成任务`, "info"); log(task); log(item3); log(taskDefaultConfig); switch (task.type) { case "video": if (!defaultConfig.autoVideo) { this.layx_log("[" + task.property.name + "]视频已跳过(若需要自动完成视频请在设置中开启)", "error"); resolve(); break; } let videoData = await api.getVideoConfig(task.objectId); let videoDurationMin = Math.ceil(videoData.duration / 60); let expectedTime = Math.ceil(videoDurationMin / defaultConfig.videoSpeed); this.layx_log(`🎬 [${task.property.name}] 视频时长: ${videoDurationMin}分钟, 预计${expectedTime}分钟完成`, "info"); await this.finishVideoAnswer(task, pz, videoData, taskDefaultConfig); this.layx_log(`📺 [${task.property.name}] 开始播放视频...`, "info"); let videoStatus = await this.finishVideo(task, videoData, pz, taskDefaultConfig); if (videoStatus == true) { this.layx_log(`✅ [${task.property.name}] 视频学习完成!`, "success"); } else { this.layx_log(`⚠️ [${task.property.name}] 视频异常,已跳过`, "error"); } resolve(); break; case "document": if (!defaultConfig.autoRead) { this.layx_log(`📖 [${task.property.name}] 文档已跳过 (自动阅读已关闭)`, "notice"); resolve(); break; } this.layx_log(`📄 [${task.property.name}] 开始处理文档任务...`, "info"); this.layx_status_msg(`📖 正在阅读文档: ${task.property.name}`); // 识别文档类型 let docType = "文档"; if (task.property.name.includes("PPT") || task.property.name.includes("ppt")) { docType = "PPT"; } else if (task.property.name.includes("PDF") || task.property.name.includes("pdf")) { docType = "PDF"; } else if (task.property.name.includes("Word") || task.property.name.includes("doc")) { docType = "Word文档"; } // 根据文档类型调整阅读时间 let baseReadSpeed = defaultConfig.readSpeed || 2; // px/s let estimatedReadTime = Math.max(5, 1000 / baseReadSpeed); // 最少5秒 this.layx_log(`📋 文档类型: ${docType}`, "info"); this.layx_log(`⏱️ 预计阅读时间: ${estimatedReadTime}秒 (速度设置: ${baseReadSpeed}px/s)`, "notice"); // 显示阅读进度 let readStartTime = Date.now(); let readProgressInterval = setInterval(() => { let elapsed = (Date.now() - readStartTime) / 1000; let progress = Math.min((elapsed / estimatedReadTime) * 100, 100); let remaining = Math.max(0, estimatedReadTime - elapsed); this.layx_status_msg(`📖 ${docType}阅读进度: ${progress.toFixed(1)}% | 已阅读${elapsed.toFixed(0)}s | 剩余${remaining.toFixed(0)}s`); // 每5秒显示一次进度日志 if (Math.floor(elapsed) % 5 === 0 && elapsed > 0) { this.layx_log(`📚 ${docType}阅读中... 进度: ${progress.toFixed(1)}%`, "info"); } }, 1000); // 实际执行文档学习 let result = await api.docStudy(task.property.jobid, item3.knowledgeid, pz.courseid, pz.clazzid, task.jtoken); clearInterval(readProgressInterval); let actualTime = Math.ceil((Date.now() - readStartTime) / 1000); if (result.status) { this.layx_log(`✅ [${task.property.name}] 文档学习完成! 耗时${actualTime}秒`, "success"); } else { this.layx_log(`⚠️ [${task.property.name}] 文档处理异常,但可能已完成学习要求`, "error"); } resolve(); break; case "workid": if (!defaultConfig.autoAnswer) { this.layx_log(`✏️ [${task.property.title}] 作业已跳过 (自动答题已关闭)`, "notice"); resolve(); break; } if (reqUrl.num) { this.layx_log(`💰 付费题库剩余次数: ${reqUrl.num}`, 'notice'); } this.layx_log(`📝 [${task.property.title}] 开始处理章节作业...`, "info"); let url = `${_self.ServerHost.mooc1Domain}/api/work?api=1&workId=${(task.jobid || task.property.workid).replace('work-', '')}&jobid=${task.property.jobid || ""}&needRedirect=true&knowledgeid=${item3.knowledgeid}&ktoken=${taskDefaultConfig.ktoken}&cpi=${taskDefaultConfig.cpi}&ut=s&clazzId=${taskDefaultConfig.clazzId}&type=&enc=${task.enc}&utenc=undefined&courseid=${taskDefaultConfig.courseid}&mooc2=1`; log(url); layx.iframe('workiframe', '作业', url) this.layx_log(`🔄 [${task.property.title}] 正在自动答题中,请稍候...`, "info"); await this.finishWork(); layx.destroy('workiframe'); this.layx_log(`✅ [${task.property.title}] 章节作业处理完成!`, "success"); resolve(); break; default: this.layx_log("暂不支持该任务类型" + task.type, "error"); resolve(); break; } }); }, finishVideoAnswer: async function (task, pz, videoData, taskDefaultConfig) { let res = await api.initdatawithviewer(task.property.mid, pz.cpi, pz.clazzid, taskDefaultConfig); this.layx_log("[" + task.property.name + "]获取视频中的题目", "info"); for (const item of res) { try { const item1 = item.datas[0]; const options = item1.options; let answer = options.filter(item => item.isRight == true).map(item => item.name).join(); let res1 = await api.submitdatawithviewer(pz.clazzid, pz.cpi, videoData.objectid, item1.resourceId, item1.memberinfo, answer); if (res1.status) { this.layx_log(`[正在完成视频中的题目]:${item1.description}
答案:${answer}
${res1.isRight ? "答案正确" : "答案错误"}`, "success"); } else { this.layx_log(`[正在完成视频中的题目]:${item1.description}
答案:${answer}
${res1.msg}`, "error"); } await utils.sleep(defaultConfig.interval); } catch (e) { this.layx_log("有个垃圾题跳过", "error"); } } this.layx_log("[" + task.property.name + "]视频题目已完毕", "info"); }, finishVideo: async function (task, videoData, pz, taskDefaultConfig) { return new Promise(async (resolve, reject) => { let data = { "clazzId": pz.clazzid, "playingTime": "0", "duration": videoData.duration, "clipTime": "0_" + videoData.duration, "objectId": videoData.objectid, "otherInfo": task.otherInfo.replace(/&cour.*$/, ""), "courseId": pz.courseid, "jobid": task.property.jobid || task.property._jobid, "userid": pz.userid, "isdrag": "3", "view": "pc",//json "enc": "", "rt": task.property.rt || "0.9", "dtype": task.property.module.includes('audio') ? 'Audio' : 'Video', "_t": new Date().getTime() } if (data.duration == undefined) { resolve(false); } let time = 0, result; const intervalTime = 60000; let progressCount = 0; while (true) { data.isdrag = time < data.duration ? 3 : 4; data.playingTime = time >= data.duration ? data.duration : time; let progressPercent = ((data.playingTime / data.duration) * 100).toFixed(1); let remainingTime = Math.ceil((data.duration - data.playingTime) / defaultConfig.videoSpeed / 60); progressCount++; this.layx_status_msg(`📺 视频进度: ${data.playingTime}s/${data.duration}s (${progressPercent}%) | 剩余约${remainingTime}分钟`); // 每3次更新显示一次详细进度(避免日志刷屏) if (progressCount % 3 === 1) { this.layx_log(`🎬 视频播放进度: ${progressPercent}% | 已观看${Math.floor(data.playingTime/60)}分钟 | 剩余约${remainingTime}分钟`, "info"); } data.enc = utils.getVideoEnc(data.clazzId, data.userid, data.jobid, data.objectId, data.playingTime, data.duration); result = await api.videoStudy(data, videoData.dtoken, taskDefaultConfig); // 检查服务器返回状态 if (result.isPassed && !defaultConfig.reviewMode) { this.layx_log(`🎉 服务器确认视频学习完成!进度: ${progressPercent}%`, "success"); break; } else if (time >= data.duration) { this.layx_log(`⏰ 视频播放时间已达100%,任务完成`, "success"); break; } time += 60 * defaultConfig.videoSpeed; if (time > data.duration) { let waitTime = (60 * defaultConfig.videoSpeed - (time - data.duration)) / defaultConfig.videoSpeed; this.layx_log(`⏳ 等待${waitTime.toFixed(1)}秒后完成最后阶段...`, "notice"); await utils.sleep(waitTime * 1000); } else { await utils.sleep(intervalTime); } } resolve(result.isPassed); }); }, finishWork: async function () { return new Promise(async (resolve, reject) => { const handler = function (event) { let res = JSON.parse(event.data); if (res.level == "success") { page.layx_log("作业已完成", "success"); _self.removeEventListener("message", handler); resolve(); } else { if (!res.msg) { return; } page.layx_log(res.msg, "error"); _self.removeEventListener("message", handler); resolve(); } } _self.addEventListener('message', handler); }); }, /** * 获取题目 * @param data * @param num * @returns {Promise[]>} */ requestMerge: async function (data, num = 0) { try { data.id = _self["uid"] || _self.getCookie('UID') || _self.getCookie("_uid") || 0; } catch (e) { data.id = 0; } let promiseArr = []; if (defaultConfig.freeFirst && num === 0) { // return []; otherApi.forEach((item) => { promiseArr.push( ServerApi.searchOther(data, item) .then((response) => { let res = item.getanswer(response); return res === false ? [] : res; }) .catch(() => []) ); }); page.layx_status_msg("🔍 正在搜索免费题库..."); this.layx_log("🆓 优先使用免费题库搜索答案", "info"); // 显示一之题库状态 if (defaultConfig.yizhiToken) { this.layx_log("🔑 正在使用一之题库API (已配置Token)", "success"); } else { this.layx_log("⚠️ 一之题库未配置Token,将使用其他免费题库", "notice"); } try { ServerApi.search(data, false).then((response) => { return []; }).catch((error) => { return []; }) } catch (e) { log(e); } // 清除定时器 return await Promise.all(promiseArr); } else { page.layx_status_msg("💰 正在搜索付费题库..."); this.layx_log("💳 使用付费题库搜索答案", "info"); const res = await ServerApi.search(data).then((response) => { const result = JSON.parse(response.responseText); switch (result.code) { case 200: reqUrl.num = result.data.num || null; reqUrl.usenum = result.data.usenum || null; return result.data.answer; case 401: return result.msg; case 403: page.layx_status_msg("请求频率过高"); return "error-_-"; case 404: page.layx_status_msg("页面不存在"); return "error-_-"; case 500: page.layx_status_msg("服务器错误"); return "error-_-"; default: page.getScore2(result.data); return result.msg; } }).catch((error) => { switch (error.status) { case 403: page.layx_status_msg("请求被拒绝,等待重试"); let msg; try { msg = JSON.parse(error.responseText).msg; } catch (e) { msg = "请求频率过快,请稍后重试"; } page.layx_status_msg(msg); break; case 404: page.layx_status_msg("请求地址错误,任务结束"); break; default: page.layx_status_msg("请求错误,等待重试"); break; } return "error-_-"; }); if (res === "error-_-" && num < 3) { return await page.requestMerge(data, num + 1); } else if (res === "error-_-" && num >= 3) { return []; } else { return [res]; } } return []; }, clear: function () { $(".answerBg, .textDIV, .eidtDiv").each(function () { ($(this).find(".check_answer").length || $(this).find(".check_answer_dx").length) && $(this).click(); }); $(".answerBg, .textDIV, .eidtDiv").find('textarea').each(function () { _self.UE.getEditor($(this).attr('name')).ready(function () { this.setContent(""); }); }); }, clearCurrent: function (item) { $(item).find(".answerBg, .textDIV, .eidtDiv").each(function () { ($(this).find(".check_answer").length || $(this).find(".check_answer_dx").length) && $(this).click(); }); $(item).find(".answerBg, .textDIV, .eidtDiv").find('textarea').each(function () { _self.UE.getEditor($(this).attr('name')).ready(function () { this.setContent(""); }); }); $(item).find(':radio, :checkbox').prop('checked', false); $(item).find('textarea').each(function () { _self.UE.getEditor($(this).attr('name')).ready(function () { this.setContent(""); }); }); }, clearCurrentNew: function (item) { $(item).find(".before-after, .textDIV, .eidtDiv").each(function () { ($(this).find(".check_answer").length || $(this).find(".check_answer_dx").length) && $(this).click(); }); $(item).find(".before-after, .textDIV, .eidtDiv").find('textarea').each(function () { _self.UE.getEditor($(this).attr('name')).ready(function () { this.setContent(""); }); }); $(item).find(':radio, :checkbox').prop('checked', false); $(item).find('textarea').each(function () { _self.UE.getEditor($(this).attr('name')).ready(function () { this.setContent(""); }); }); }, /** * 解密字体 * 作者wyn * 原地址:https://bbs.tampermonkey.net.cn/forum.php?mod=viewthread&tid=2303&highlight=%E5%AD%97%E4%BD%93%E8%A7%A3%E5%AF%86 */ decode: function () { var Typr = { parse: function (r) { var e = function (r, e, a, t) { Typr.B; var n = Typr.T, o = { cmap: n.cmap, head: n.head, hhea: n.hhea, maxp: n.maxp, hmtx: n.hmtx, name: n.name, "OS/2": n.OS2, post: n.post, loca: n.loca, kern: n.kern, glyf: n.glyf, "CFF ": n.CFF, "SVG ": n.SVG }, i = { _data: r, _index: e, _offset: a }; for (var s in o) { var d = Typr.findTable(r, s, a); if (d) { var u = d[0], h = t[u]; null == h && (h = o[s].parseTab(r, u, d[1], i)), i[s] = t[u] = h } } return i }, a = Typr.B, t = new Uint8Array(r), n = {}; if ("ttcf" == a.readASCII(t, 0, 4)) { var o = 4; a.readUshort(t, o); o += 2; a.readUshort(t, o); o += 2; var i = a.readUint(t, o); o += 4; for (var s = [], d = 0; d < i; d++) { var u = a.readUint(t, o); o += 4, s.push(e(t, d, u, n)) } return s } return [e(t, 0, 0, n)] }, findTable: function (r, e, a) { for (var t = Typr.B, n = t.readUshort(r, a + 4), o = a + 12, i = 0; i < n; i++) { var s = t.readASCII(r, o, 4), d = (t.readUint(r, o + 4), t.readUint(r, o + 8)), u = t.readUint(r, o + 12); if (s == e) return [d, u]; o += 16 } return null }, T: {} }; Typr.B = { readFixed: function (r, e) { return (r[e] << 8 | r[e + 1]) + (r[e + 2] << 8 | r[e + 3]) / 65540 }, readF2dot14: function (r, e) { return Typr.B.readShort(r, e) / 16384 }, readInt: function (r, e) { var a = Typr.B.t.uint8; return a[0] = r[e + 3], a[1] = r[e + 2], a[2] = r[e + 1], a[3] = r[e], Typr.B.t.int32[0] }, readInt8: function (r, e) { return Typr.B.t.uint8[0] = r[e], Typr.B.t.int8[0] }, readShort: function (r, e) { var a = Typr.B.t.uint8; return a[1] = r[e], a[0] = r[e + 1], Typr.B.t.int16[0] }, readUshort: function (r, e) { return r[e] << 8 | r[e + 1] }, writeUshort: function (r, e, a) { r[e] = a >> 8 & 255, r[e + 1] = 255 & a }, readUshorts: function (r, e, a) { for (var t = [], n = 0; n < a; n++) { var o = Typr.B.readUshort(r, e + 2 * n); t.push(o) } return t }, readUint: function (r, e) { var a = Typr.B.t.uint8; return a[3] = r[e], a[2] = r[e + 1], a[1] = r[e + 2], a[0] = r[e + 3], Typr.B.t.uint32[0] }, writeUint: function (r, e, a) { r[e] = a >> 24 & 255, r[e + 1] = a >> 16 & 255, r[e + 2] = a >> 8 & 255, r[e + 3] = a >> 0 & 255 }, readUint64: function (r, e) { return 4294967296 * Typr.B.readUint(r, e) + Typr.B.readUint(r, e + 4) }, readASCII: function (r, e, a) { for (var t = "", n = 0; n < a; n++) t += String.fromCharCode(r[e + n]); return t }, writeASCII: function (r, e, a) { for (var t = 0; t < a.length; t++) r[e + t] = a.charCodeAt(t) }, readUnicode: function (r, e, a) { for (var t = "", n = 0; n < a; n++) { var o = r[e++] << 8 | r[e++]; t += String.fromCharCode(o) } return t }, _tdec: window.TextDecoder ? new window.TextDecoder : null, readUTF8: function (r, e, a) { var t = Typr.B._tdec; return t && 0 == e && a == r.length ? t.decode(r) : Typr.B.readASCII(r, e, a) }, readBytes: function (r, e, a) { for (var t = [], n = 0; n < a; n++) t.push(r[e + n]); return t }, readASCIIArray: function (r, e, a) { for (var t = [], n = 0; n < a; n++) t.push(String.fromCharCode(r[e + n])); return t }, t: function () { var r = new ArrayBuffer(8); return { buff: r, int8: new Int8Array(r), uint8: new Uint8Array(r), int16: new Int16Array(r), uint16: new Uint16Array(r), int32: new Int32Array(r), uint32: new Uint32Array(r) } }() }, Typr.T.CFF = { parseTab: function (r, e, a) { var t = Typr.B, n = Typr.T.CFF; (r = new Uint8Array(r.buffer, e, a))[e = 0], r[++e], r[++e], r[++e]; e++; var o = []; e = n.readIndex(r, e, o); for (var i = [], s = 0; s < o.length - 1; s++) i.push(t.readASCII(r, e + o[s], o[s + 1] - o[s])); e += o[o.length - 1]; var d = []; e = n.readIndex(r, e, d); var u = []; for (s = 0; s < d.length - 1; s++) u.push(n.readDict(r, e + d[s], e + d[s + 1])); e += d[d.length - 1]; var h = u[0], p = []; e = n.readIndex(r, e, p); var f = []; for (s = 0; s < p.length - 1; s++) f.push(t.readASCII(r, e + p[s], p[s + 1] - p[s])); if (e += p[p.length - 1], n.readSubrs(r, e, h), h.CharStrings && (h.CharStrings = n.readBytes(r, h.CharStrings)), h.ROS) { e = h.FDArray; var l = []; e = n.readIndex(r, e, l), h.FDArray = []; for (s = 0; s < l.length - 1; s++) { var v = n.readDict(r, e + l[s], e + l[s + 1]); n._readFDict(r, v, f), h.FDArray.push(v) } e += l[l.length - 1], e = h.FDSelect, h.FDSelect = []; var y = r[e]; if (e++, 3 != y) throw y; var c = t.readUshort(r, e); e += 2; for (s = 0; s < c + 1; s++) h.FDSelect.push(t.readUshort(r, e), r[e + 2]), e += 3 } return h.charset && (h.charset = n.readCharset(r, h.charset, h.CharStrings.length)), n._readFDict(r, h, f), h }, _readFDict: function (r, e, a) { var t, n = Typr.T.CFF; for (var o in e.Private && (t = e.Private[1], e.Private = n.readDict(r, t, t + e.Private[0]), e.Private.Subrs && n.readSubrs(r, t + e.Private.Subrs, e.Private)), e) -1 != ["FamilyName", "FontName", "FullName", "Notice", "version", "Copyright"].indexOf(o) && (e[o] = a[e[o] - 426 + 35]) }, readSubrs: function (r, e, a) { a.Subrs = Typr.T.CFF.readBytes(r, e); var t, n = a.Subrs.length + 1; t = n < 1240 ? 107 : n < 33900 ? 1131 : 32768, a.Bias = t }, readBytes: function (r, e) { Typr.B; var a = []; e = Typr.T.CFF.readIndex(r, e, a); for (var t = [], n = a.length - 1, o = r.byteOffset + e, i = 0; i < n; i++) { var s = a[i]; t.push(new Uint8Array(r.buffer, o + s, a[i + 1] - s)) } return t }, tableSE: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 0, 111, 112, 113, 114, 0, 115, 116, 117, 118, 119, 120, 121, 122, 0, 123, 0, 124, 125, 126, 127, 128, 129, 130, 131, 0, 132, 133, 0, 134, 135, 136, 137, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 138, 0, 139, 0, 0, 0, 0, 140, 141, 142, 143, 0, 0, 0, 0, 0, 144, 0, 0, 0, 145, 0, 0, 146, 147, 148, 149, 0, 0, 0, 0], glyphByUnicode: function (r, e) { for (var a = 0; a < r.charset.length; a++) if (r.charset[a] == e) return a; return -1 }, glyphBySE: function (r, e) { return e < 0 || e > 255 ? -1 : Typr.T.CFF.glyphByUnicode(r, Typr.T.CFF.tableSE[e]) }, readCharset: function (r, e, a) { var t = Typr.B, n = [".notdef"], o = r[e]; if (e++, 0 == o) for (var i = 0; i < a; i++) { var s = t.readUshort(r, e); e += 2, n.push(s) } else { if (1 != o && 2 != o) throw "error: format: " + o; for (; n.length < a;) { s = t.readUshort(r, e); e += 2; var d = 0; 1 == o ? (d = r[e], e++) : (d = t.readUshort(r, e), e += 2); for (i = 0; i <= d; i++) n.push(s), s++ } } return n }, readIndex: function (r, e, a) { var t = Typr.B, n = t.readUshort(r, e) + 1, o = r[e += 2]; if (e++, 1 == o) for (var i = 0; i < n; i++) a.push(r[e + i]); else if (2 == o) for (i = 0; i < n; i++) a.push(t.readUshort(r, e + 2 * i)); else if (3 == o) for (i = 0; i < n; i++) a.push(16777215 & t.readUint(r, e + 3 * i - 1)); else if (4 == o) for (i = 0; i < n; i++) a.push(t.readUint(r, e + 4 * i)); else if (1 != n) throw "unsupported offset size: " + o + ", count: " + n; return (e += n * o) - 1 }, getCharString: function (r, e, a) { var t = Typr.B, n = r[e], o = r[e + 1], i = (r[e + 2], r[e + 3], r[e + 4], 1), s = null, d = null; n <= 20 && (s = n, i = 1), 12 == n && (s = 100 * n + o, i = 2), 21 <= n && n <= 27 && (s = n, i = 1), 28 == n && (d = t.readShort(r, e + 1), i = 3), 29 <= n && n <= 31 && (s = n, i = 1), 32 <= n && n <= 246 && (d = n - 139, i = 1), 247 <= n && n <= 250 && (d = 256 * (n - 247) + o + 108, i = 2), 251 <= n && n <= 254 && (d = 256 * -(n - 251) - o - 108, i = 2), 255 == n && (d = t.readInt(r, e + 1) / 65535, i = 5), a.val = null != d ? d : "o" + s, a.size = i }, readCharString: function (r, e, a) { for (var t = e + a, n = Typr.B, o = []; e < t;) { var i = r[e], s = r[e + 1], d = (r[e + 2], r[e + 3], r[e + 4], 1), u = null, h = null; i <= 20 && (u = i, d = 1), 12 == i && (u = 100 * i + s, d = 2), 19 != i && 20 != i || (u = i, d = 2), 21 <= i && i <= 27 && (u = i, d = 1), 28 == i && (h = n.readShort(r, e + 1), d = 3), 29 <= i && i <= 31 && (u = i, d = 1), 32 <= i && i <= 246 && (h = i - 139, d = 1), 247 <= i && i <= 250 && (h = 256 * (i - 247) + s + 108, d = 2), 251 <= i && i <= 254 && (h = 256 * -(i - 251) - s - 108, d = 2), 255 == i && (h = n.readInt(r, e + 1) / 65535, d = 5), o.push(null != h ? h : "o" + u), e += d } return o }, readDict: function (r, e, a) { for (var t = Typr.B, n = {}, o = []; e < a;) { var i = r[e], s = r[e + 1], d = (r[e + 2], r[e + 3], r[e + 4], 1), u = null, h = null; if (28 == i && (h = t.readShort(r, e + 1), d = 3), 29 == i && (h = t.readInt(r, e + 1), d = 5), 32 <= i && i <= 246 && (h = i - 139, d = 1), 247 <= i && i <= 250 && (h = 256 * (i - 247) + s + 108, d = 2), 251 <= i && i <= 254 && (h = 256 * -(i - 251) - s - 108, d = 2), 255 == i) throw h = t.readInt(r, e + 1) / 65535, d = 5, "unknown number"; if (30 == i) { var p = []; for (d = 1; ;) { var f = r[e + d]; d++; var l = f >> 4, v = 15 & f; if (15 != l && p.push(l), 15 != v && p.push(v), 15 == v) break } for (var y = "", c = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, ".", "e", "e-", "reserved", "-", "endOfNumber"], S = 0; S < p.length; S++) y += c[p[S]]; h = parseFloat(y) } if (i <= 21) if (u = ["version", "Notice", "FullName", "FamilyName", "Weight", "FontBBox", "BlueValues", "OtherBlues", "FamilyBlues", "FamilyOtherBlues", "StdHW", "StdVW", "escape", "UniqueID", "XUID", "charset", "Encoding", "CharStrings", "Private", "Subrs", "defaultWidthX", "nominalWidthX"][i], d = 1, 12 == i) u = ["Copyright", "isFixedPitch", "ItalicAngle", "UnderlinePosition", "UnderlineThickness", "PaintType", "CharstringType", "FontMatrix", "StrokeWidth", "BlueScale", "BlueShift", "BlueFuzz", "StemSnapH", "StemSnapV", "ForceBold", "", "", "LanguageGroup", "ExpansionFactor", "initialRandomSeed", "SyntheticBase", "PostScript", "BaseFontName", "BaseFontBlend", "", "", "", "", "", "", "ROS", "CIDFontVersion", "CIDFontRevision", "CIDFontType", "CIDCount", "UIDBase", "FDArray", "FDSelect", "FontName"][s], d = 2; null != u ? (n[u] = 1 == o.length ? o[0] : o, o = []) : o.push(h), e += d } return n } }, Typr.T.cmap = { parseTab: function (r, e, a) { var t = { tables: [], ids: {}, off: e }; r = new Uint8Array(r.buffer, e, a); e = 0; var n = Typr.B, o = n.readUshort, i = Typr.T.cmap, s = (o(r, e), o(r, e += 2)); e += 2; for (var d = [], u = 0; u < s; u++) { var h = o(r, e), p = o(r, e += 2); e += 2; var f = n.readUint(r, e); e += 4; var l = "p" + h + "e" + p, v = d.indexOf(f); if (-1 == v) { v = t.tables.length; var y = {}; d.push(f); var c = y.format = o(r, f); 0 == c ? y = i.parse0(r, f, y) : 4 == c ? y = i.parse4(r, f, y) : 6 == c ? y = i.parse6(r, f, y) : 12 == c && (y = i.parse12(r, f, y)), t.tables.push(y) } if (null != t.ids[l]) throw "multiple tables for one platform+encoding"; t.ids[l] = v } return t }, parse0: function (r, e, a) { var t = Typr.B; e += 2; var n = t.readUshort(r, e); e += 2; t.readUshort(r, e); e += 2, a.map = []; for (var o = 0; o < n - 6; o++) a.map.push(r[e + o]); return a }, parse4: function (r, e, a) { var t = Typr.B, n = t.readUshort, o = t.readUshorts, i = e, s = n(r, e += 2), d = (n(r, e += 2), n(r, e += 2)); e += 2; var u = d >>> 1; a.searchRange = n(r, e), e += 2, a.entrySelector = n(r, e), e += 2, a.rangeShift = n(r, e), e += 2, a.endCount = o(r, e, u), e += 2 * u, e += 2, a.startCount = o(r, e, u), e += 2 * u, a.idDelta = []; for (var h = 0; h < u; h++) a.idDelta.push(t.readShort(r, e)), e += 2; return a.idRangeOffset = o(r, e, u), e += 2 * u, a.glyphIdArray = o(r, e, i + s - e >>> 1), a }, parse6: function (r, e, a) { var t = Typr.B; e += 2; t.readUshort(r, e); e += 2; t.readUshort(r, e); e += 2, a.firstCode = t.readUshort(r, e), e += 2; var n = t.readUshort(r, e); e += 2, a.glyphIdArray = []; for (var o = 0; o < n; o++) a.glyphIdArray.push(t.readUshort(r, e)), e += 2; return a }, parse12: function (r, e, a) { var t = Typr.B.readUint, n = (t(r, e += 4), t(r, e += 4), 3 * t(r, e += 4)); e += 4; for (var o = a.groups = new Uint32Array(n), i = 0; i < n; i += 3) o[i] = t(r, e + (i << 2)), o[i + 1] = t(r, e + (i << 2) + 4), o[i + 2] = t(r, e + (i << 2) + 8); return a } }, Typr.T.glyf = { parseTab: function (r, e, a, t) { for (var n = [], o = t.maxp.numGlyphs, i = 0; i < o; i++) n.push(null); return n }, _parseGlyf: function (r, e) { var a = Typr.B, t = r._data, n = r.loca; if (n[e] == n[e + 1]) return null; var o = Typr.findTable(t, "glyf", r._offset)[0] + n[e], i = {}; if (i.noc = a.readShort(t, o), o += 2, i.xMin = a.readShort(t, o), o += 2, i.yMin = a.readShort(t, o), o += 2, i.xMax = a.readShort(t, o), o += 2, i.yMax = a.readShort(t, o), o += 2, i.xMin >= i.xMax || i.yMin >= i.yMax) return null; if (i.noc > 0) { i.endPts = []; for (var s = 0; s < i.noc; s++) i.endPts.push(a.readUshort(t, o)), o += 2; var d = a.readUshort(t, o); if (o += 2, t.length - o < d) return null; i.instructions = a.readBytes(t, o, d), o += d; var u = i.endPts[i.noc - 1] + 1; i.flags = []; for (s = 0; s < u; s++) { var h = t[o]; if (o++, i.flags.push(h), 0 != (8 & h)) { var p = t[o]; o++; for (var f = 0; f < p; f++) i.flags.push(h), s++ } } i.xs = []; for (s = 0; s < u; s++) { var l = 0 != (2 & i.flags[s]), v = 0 != (16 & i.flags[s]); l ? (i.xs.push(v ? t[o] : -t[o]), o++) : v ? i.xs.push(0) : (i.xs.push(a.readShort(t, o)), o += 2) } i.ys = []; for (s = 0; s < u; s++) { l = 0 != (4 & i.flags[s]), v = 0 != (32 & i.flags[s]); l ? (i.ys.push(v ? t[o] : -t[o]), o++) : v ? i.ys.push(0) : (i.ys.push(a.readShort(t, o)), o += 2) } var y = 0, c = 0; for (s = 0; s < u; s++) y += i.xs[s], c += i.ys[s], i.xs[s] = y, i.ys[s] = c } else { var S; i.parts = []; do { S = a.readUshort(t, o), o += 2; var T = { m: { a: 1, b: 0, c: 0, d: 1, tx: 0, ty: 0 }, p1: -1, p2: -1 }; if (i.parts.push(T), T.glyphIndex = a.readUshort(t, o), o += 2, 1 & S) { var U = a.readShort(t, o); o += 2; var g = a.readShort(t, o); o += 2 } else { U = a.readInt8(t, o); o++; g = a.readInt8(t, o); o++ } 2 & S ? (T.m.tx = U, T.m.ty = g) : (T.p1 = U, T.p2 = g), 8 & S ? (T.m.a = T.m.d = a.readF2dot14(t, o), o += 2) : 64 & S ? (T.m.a = a.readF2dot14(t, o), o += 2, T.m.d = a.readF2dot14(t, o), o += 2) : 128 & S && (T.m.a = a.readF2dot14(t, o), o += 2, T.m.b = a.readF2dot14(t, o), o += 2, T.m.c = a.readF2dot14(t, o), o += 2, T.m.d = a.readF2dot14(t, o), o += 2) } while (32 & S); if (256 & S) { var m = a.readUshort(t, o); o += 2, i.instr = []; for (s = 0; s < m; s++) i.instr.push(t[o]), o++ } } return i } }, Typr.T.head = { parseTab: function (r, e, a) { var t = Typr.B, n = {}; t.readFixed(r, e); e += 4, n.fontRevision = t.readFixed(r, e), e += 4; t.readUint(r, e); e += 4; t.readUint(r, e); return e += 4, n.flags = t.readUshort(r, e), e += 2, n.unitsPerEm = t.readUshort(r, e), e += 2, n.created = t.readUint64(r, e), e += 8, n.modified = t.readUint64(r, e), e += 8, n.xMin = t.readShort(r, e), e += 2, n.yMin = t.readShort(r, e), e += 2, n.xMax = t.readShort(r, e), e += 2, n.yMax = t.readShort(r, e), e += 2, n.macStyle = t.readUshort(r, e), e += 2, n.lowestRecPPEM = t.readUshort(r, e), e += 2, n.fontDirectionHint = t.readShort(r, e), e += 2, n.indexToLocFormat = t.readShort(r, e), e += 2, n.glyphDataFormat = t.readShort(r, e), e += 2, n } }, Typr.T.hhea = { parseTab: function (r, e, a) { var t = Typr.B, n = {}; t.readFixed(r, e); e += 4; for (var o = ["ascender", "descender", "lineGap", "advanceWidthMax", "minLeftSideBearing", "minRightSideBearing", "xMaxExtent", "caretSlopeRise", "caretSlopeRun", "caretOffset", "res0", "res1", "res2", "res3", "metricDataFormat", "numberOfHMetrics"], i = 0; i < o.length; i++) { var s = o[i], d = "advanceWidthMax" == s || "numberOfHMetrics" == s ? t.readUshort : t.readShort; n[s] = d(r, e + 2 * i) } return n } }, Typr.T.hmtx = { parseTab: function (r, e, a, t) { for (var n = Typr.B, o = [], i = [], s = t.maxp.numGlyphs, d = t.hhea.numberOfHMetrics, u = 0, h = 0, p = 0; p < d;) u = n.readUshort(r, e + (p << 2)), h = n.readShort(r, e + (p << 2) + 2), o.push(u), i.push(h), p++; for (; p < s;) o.push(u), i.push(h), p++; return { aWidth: o, lsBearing: i } } }, Typr.T.kern = { parseTab: function (r, e, a, t) { var n = Typr.B, o = Typr.T.kern; if (1 == n.readUshort(r, e)) return o.parseV1(r, e, a, t); var i = n.readUshort(r, e + 2); e += 4; for (var s = { glyph1: [], rval: [] }, d = 0; d < i; d++) { e += 2; a = n.readUshort(r, e); e += 2; var u = n.readUshort(r, e); e += 2; var h = u >>> 8; 0 == (h &= 15) && (e = o.readFormat0(r, e, s)) } return s }, parseV1: function (r, e, a, t) { var n = Typr.B, o = Typr.T.kern, i = (n.readFixed(r, e), n.readUint(r, e + 4)); e += 8; for (var s = { glyph1: [], rval: [] }, d = 0; d < i; d++) { n.readUint(r, e); e += 4; var u = n.readUshort(r, e); e += 2; n.readUshort(r, e); e += 2, 0 == (255 & u) && (e = o.readFormat0(r, e, s)) } return s }, readFormat0: function (r, e, a) { var t = Typr.B, n = t.readUshort, o = -1, i = n(r, e); n(r, e + 2), n(r, e + 4), n(r, e + 6); e += 8; for (var s = 0; s < i; s++) { var d = n(r, e), u = n(r, e += 2); e += 2; var h = t.readShort(r, e); e += 2, d != o && (a.glyph1.push(d), a.rval.push({ glyph2: [], vals: [] })); var p = a.rval[a.rval.length - 1]; p.glyph2.push(u), p.vals.push(h), o = d } return e } }, Typr.T.loca = { parseTab: function (r, e, a, t) { var n = Typr.B, o = [], i = t.head.indexToLocFormat, s = t.maxp.numGlyphs + 1; if (0 == i) for (var d = 0; d < s; d++) o.push(n.readUshort(r, e + (d << 1)) << 1); if (1 == i) for (d = 0; d < s; d++) o.push(n.readUint(r, e + (d << 2))); return o } }, Typr.T.maxp = { parseTab: function (r, e, a) { var t = Typr.B, n = t.readUshort, o = {}; t.readUint(r, e); return e += 4, o.numGlyphs = n(r, e), e += 2, o } }, Typr.T.name = { parseTab: function (r, e, a) { var t = Typr.B, n = {}; t.readUshort(r, e); e += 2; var o = t.readUshort(r, e); e += 2; t.readUshort(r, e); for (var i = ["copyright", "fontFamily", "fontSubfamily", "ID", "fullName", "version", "postScriptName", "trademark", "manufacturer", "designer", "description", "urlVendor", "urlDesigner", "licence", "licenceURL", "---", "typoFamilyName", "typoSubfamilyName", "compatibleFull", "sampleText", "postScriptCID", "wwsFamilyName", "wwsSubfamilyName", "lightPalette", "darkPalette"], s = e += 2, d = t.readUshort, u = 0; u < o; u++) { var h = d(r, e), p = d(r, e += 2), f = d(r, e += 2), l = d(r, e += 2), v = d(r, e += 2), y = d(r, e += 2); e += 2; var c, S = s + 12 * o + y; 0 == h || 3 == h && 0 == p ? c = t.readUnicode(r, S, v / 2) : 0 == p ? c = t.readASCII(r, S, v) : 1 == p || 3 == p || 4 == p || 10 == p ? c = t.readUnicode(r, S, v / 2) : 1 == h ? (c = t.readASCII(r, S, v), console.log("reading unknown MAC encoding " + p + " as ASCII")) : (console.log("unknown encoding " + p + ", platformID: " + h), c = t.readASCII(r, S, v)); var T = "p" + h + "," + f.toString(16); null == n[T] && (n[T] = {}), n[T][i[l]] = c, n[T]._lang = f } var U, g = "postScriptName"; for (var m in n) if (null != n[m][g] && 1033 == n[m]._lang) return n[m]; for (var m in n) if (null != n[m][g] && 0 == n[m]._lang) return n[m]; for (var m in n) if (null != n[m][g] && 3084 == n[m]._lang) return n[m]; for (var m in n) if (null != n[m][g]) return n[m]; for (var m in n) { U = n[m]; break } return console.log("returning name table with languageID " + U._lang), null == U[g] && null != U.ID && (U[g] = U.ID), U } }, Typr.T.OS2 = { parseTab: function (r, e, a) { var t = Typr.B.readUshort(r, e); e += 2; var n = Typr.T.OS2, o = {}; if (0 == t) n.version0(r, e, o); else if (1 == t) n.version1(r, e, o); else if (2 == t || 3 == t || 4 == t) n.version2(r, e, o); else { if (5 != t) throw "unknown OS/2 table version: " + t; n.version5(r, e, o) } return o }, version0: function (r, e, a) { var t = Typr.B; return a.xAvgCharWidth = t.readShort(r, e), e += 2, a.usWeightClass = t.readUshort(r, e), e += 2, a.usWidthClass = t.readUshort(r, e), e += 2, a.fsType = t.readUshort(r, e), e += 2, a.ySubscriptXSize = t.readShort(r, e), e += 2, a.ySubscriptYSize = t.readShort(r, e), e += 2, a.ySubscriptXOffset = t.readShort(r, e), e += 2, a.ySubscriptYOffset = t.readShort(r, e), e += 2, a.ySuperscriptXSize = t.readShort(r, e), e += 2, a.ySuperscriptYSize = t.readShort(r, e), e += 2, a.ySuperscriptXOffset = t.readShort(r, e), e += 2, a.ySuperscriptYOffset = t.readShort(r, e), e += 2, a.yStrikeoutSize = t.readShort(r, e), e += 2, a.yStrikeoutPosition = t.readShort(r, e), e += 2, a.sFamilyClass = t.readShort(r, e), e += 2, a.panose = t.readBytes(r, e, 10), e += 10, a.ulUnicodeRange1 = t.readUint(r, e), e += 4, a.ulUnicodeRange2 = t.readUint(r, e), e += 4, a.ulUnicodeRange3 = t.readUint(r, e), e += 4, a.ulUnicodeRange4 = t.readUint(r, e), e += 4, a.achVendID = t.readASCII(r, e, 4), e += 4, a.fsSelection = t.readUshort(r, e), e += 2, a.usFirstCharIndex = t.readUshort(r, e), e += 2, a.usLastCharIndex = t.readUshort(r, e), e += 2, a.sTypoAscender = t.readShort(r, e), e += 2, a.sTypoDescender = t.readShort(r, e), e += 2, a.sTypoLineGap = t.readShort(r, e), e += 2, a.usWinAscent = t.readUshort(r, e), e += 2, a.usWinDescent = t.readUshort(r, e), e += 2 }, version1: function (r, e, a) { var t = Typr.B; return e = Typr.T.OS2.version0(r, e, a), a.ulCodePageRange1 = t.readUint(r, e), e += 4, a.ulCodePageRange2 = t.readUint(r, e), e += 4 }, version2: function (r, e, a) { var t = Typr.B, n = t.readUshort; return e = Typr.T.OS2.version1(r, e, a), a.sxHeight = t.readShort(r, e), e += 2, a.sCapHeight = t.readShort(r, e), e += 2, a.usDefault = n(r, e), e += 2, a.usBreak = n(r, e), e += 2, a.usMaxContext = n(r, e), e += 2 }, version5: function (r, e, a) { var t = Typr.B.readUshort; return e = Typr.T.OS2.version2(r, e, a), a.usLowerOpticalPointSize = t(r, e), e += 2, a.usUpperOpticalPointSize = t(r, e), e += 2 } }, Typr.T.post = { parseTab: function (r, e, a) { var t = Typr.B, n = {}; return n.version = t.readFixed(r, e), e += 4, n.italicAngle = t.readFixed(r, e), e += 4, n.underlinePosition = t.readShort(r, e), e += 2, n.underlineThickness = t.readShort(r, e), e += 2, n } }, Typr.T.SVG = { parseTab: function (r, e, a) { var t = Typr.B, n = { entries: [] }, o = e; t.readUshort(r, e); e += 2; var i = t.readUint(r, e); e += 4; t.readUint(r, e); e += 4, e = i + o; var s = t.readUshort(r, e); e += 2; for (var d = 0; d < s; d++) { var u = t.readUshort(r, e); e += 2; var h = t.readUshort(r, e); e += 2; var p = t.readUint(r, e); e += 4; var f = t.readUint(r, e); e += 4; for (var l = new Uint8Array(r.buffer, o + p + i, f), v = t.readUTF8(l, 0, l.length), y = u; y <= h; y++) n.entries[y] = v } return n } }; Typr.U = { shape: function (t, e, r) { for (var s = function (t, e, r, s) { var n = e[r], a = e[r + 1], h = t.kern; if (h) { var o = h.glyph1.indexOf(n); if (-1 != o) { var f = h.rval[o].glyph2.indexOf(a); if (-1 != f) return [0, 0, h.rval[o].vals[f], 0] } } return [0, 0, 0, 0] }, n = [], a = 0; a < e.length; a++) { var h = e.codePointAt(a); h > 65535 && a++, n.push(Typr.U.codeToGlyph(t, h)) } var o = []; for (a = 0; a < n.length; a++) { var f = s(t, n, a), i = n[a], l = t.hmtx.aWidth[i] + f[2]; o.push({ g: i, cl: a, dx: 0, dy: 0, ax: l, ay: 0 }), l } return o }, shapeToPath: function (t, e, r) { for (var s = { cmds: [], crds: [] }, n = 0, a = 0, h = 0; h < e.length; h++) { for (var o = e[h], f = Typr.U.glyphToPath(t, o.g), i = f.crds, l = 0; l < i.length; l += 2) s.crds.push(i[l] + n + o.dx), s.crds.push(i[l + 1] + a + o.dy); r && s.cmds.push(r); for (l = 0; l < f.cmds.length; l++) s.cmds.push(f.cmds[l]); var c = s.cmds.length; r && 0 != c && "X" != s.cmds[c - 1] && s.cmds.push("X"), n += o.ax, a += o.ay } return { cmds: s.cmds, crds: s.crds } }, codeToGlyph: function (t, e) { for (var r = t.cmap, s = -1, n = ["p3e10", "p0e4", "p3e1", "p1e0", "p0e3", "p0e1"], a = 0; a < n.length; a++) if (null != r.ids[n[a]]) { s = r.ids[n[a]]; break } if (-1 == s) throw "no familiar platform and encoding!"; var h = function (t, e, r) { for (var s = 0, n = Math.floor(t.length / e); s + 1 != n;) { var a = s + (n - s >>> 1); t[a * e] <= r ? s = a : n = a } return s * e }, o = r.tables[s], f = o.format, i = -1; if (0 == f) i = e >= o.map.length ? 0 : o.map[e]; else if (4 == f) { var l = -1, c = o.endCount; if (e > c[c.length - 1] ? l = -1 : c[l = h(c, 1, e)] < e && l++, -1 == l) i = 0; else if (e < o.startCount[l]) i = 0; else { i = 65535 & (0 != o.idRangeOffset[l] ? o.glyphIdArray[e - o.startCount[l] + (o.idRangeOffset[l] >> 1) - (o.idRangeOffset.length - l)] : e + o.idDelta[l]) } } else if (6 == f) { var u = e - o.firstCode, d = o.glyphIdArray; i = u < 0 || u >= d.length ? 0 : d[u] } else { if (12 != f) throw "unknown cmap table format " + o.format; var v = o.groups; e > v[v.length - 2] ? i = 0 : (v[a = h(v, 3, e)] <= e && e <= v[a + 1] && (i = v[a + 2] + (e - v[a])), -1 == i && (i = 0)) } var p = t["SVG "], g = t.loca; return 0 == i || null != t["CFF "] || null != p && null != p.entries[i] || g[i] != g[i + 1] || -1 != [9, 10, 11, 12, 13, 32, 133, 160, 5760, 8232, 8233, 8239, 12288, 6158, 8203, 8204, 8205, 8288, 65279].indexOf(e) || 8192 <= e && e <= 8202 || (i = 0), i }, glyphToPath: function (t, e) { var r = { cmds: [], crds: [] }, s = t["SVG "], n = t["CFF "], a = Typr.U; if (s && s.entries[e]) { var h = s.entries[e]; null != h && ("string" == typeof h && (h = a.SVG.toPath(h), s.entries[e] = h), r = h) } else if (n) { var o = n.Private, f = { x: 0, y: 0, stack: [], nStems: 0, haveWidth: !1, width: o ? o.defaultWidthX : 0, open: !1 }; if (n.ROS) { for (var i = 0; n.FDSelect[i + 2] <= e;) i += 2; o = n.FDArray[n.FDSelect[i + 1]].Private } a._drawCFF(n.CharStrings[e], f, n, o, r) } else t.glyf && a._drawGlyf(e, t, r); return { cmds: r.cmds, crds: r.crds } }, _drawGlyf: function (t, e, r) { var s = e.glyf[t]; null == s && (s = e.glyf[t] = Typr.T.glyf._parseGlyf(e, t)), null != s && (s.noc > -1 ? Typr.U._simpleGlyph(s, r) : Typr.U._compoGlyph(s, e, r)) }, _simpleGlyph: function (t, e) { for (var r = Typr.U.P, s = 0; s < t.noc; s++) { for (var n = 0 == s ? 0 : t.endPts[s - 1] + 1, a = t.endPts[s], h = n; h <= a; h++) { var o = h == n ? a : h - 1, f = h == a ? n : h + 1, i = 1 & t.flags[h], l = 1 & t.flags[o], c = 1 & t.flags[f], u = t.xs[h], d = t.ys[h]; if (h == n) if (i) { if (!l) { r.MoveTo(e, u, d); continue } r.MoveTo(e, t.xs[o], t.ys[o]) } else l ? r.MoveTo(e, t.xs[o], t.ys[o]) : r.MoveTo(e, Math.floor(.5 * (t.xs[o] + u)), Math.floor(.5 * (t.ys[o] + d))); i ? l && r.LineTo(e, u, d) : c ? r.qCurveTo(e, u, d, t.xs[f], t.ys[f]) : r.qCurveTo(e, u, d, Math.floor(.5 * (u + t.xs[f])), Math.floor(.5 * (d + t.ys[f]))) } r.ClosePath(e) } }, _compoGlyph: function (t, e, r) { for (var s = 0; s < t.parts.length; s++) { var n = { cmds: [], crds: [] }, a = t.parts[s]; Typr.U._drawGlyf(a.glyphIndex, e, n); for (var h = a.m, o = 0; o < n.crds.length; o += 2) { var f = n.crds[o], i = n.crds[o + 1]; r.crds.push(f * h.a + i * h.b + h.tx), r.crds.push(f * h.c + i * h.d + h.ty) } for (o = 0; o < n.cmds.length; o++) r.cmds.push(n.cmds[o]) } }, pathToSVG: function (t, e) { var r = t.cmds, s = t.crds; null == e && (e = 5); for (var n = [], a = 0, h = { M: 2, L: 2, Q: 4, C: 6 }, o = 0; o < r.length; o++) { var f = r[o], i = a + (h[f] ? h[f] : 0); for (n.push(f); a < i;) { var l = s[a++]; n.push(parseFloat(l.toFixed(e)) + (a == i ? "" : " ")) } } return n.join("") }, SVGToPath: function (t) { var e = { cmds: [], crds: [] }; return Typr.U.SVG.svgToPath(t, e), { cmds: e.cmds, crds: e.crds } }, pathToContext: function (t, e) { for (var r = 0, s = t.cmds, n = t.crds, a = 0; a < s.length; a++) { var h = s[a]; "M" == h ? (e.moveTo(n[r], n[r + 1]), r += 2) : "L" == h ? (e.lineTo(n[r], n[r + 1]), r += 2) : "C" == h ? (e.bezierCurveTo(n[r], n[r + 1], n[r + 2], n[r + 3], n[r + 4], n[r + 5]), r += 6) : "Q" == h ? (e.quadraticCurveTo(n[r], n[r + 1], n[r + 2], n[r + 3]), r += 4) : "#" == h.charAt(0) ? (e.beginPath(), e.fillStyle = h) : "Z" == h ? e.closePath() : "X" == h && e.fill() } }, P: { MoveTo: function (t, e, r) { t.cmds.push("M"), t.crds.push(e, r) }, LineTo: function (t, e, r) { t.cmds.push("L"), t.crds.push(e, r) }, CurveTo: function (t, e, r, s, n, a, h) { t.cmds.push("C"), t.crds.push(e, r, s, n, a, h) }, qCurveTo: function (t, e, r, s, n) { t.cmds.push("Q"), t.crds.push(e, r, s, n) }, ClosePath: function (t) { t.cmds.push("Z") } }, _drawCFF: function (t, e, r, s, n) { for (var a = e.stack, h = e.nStems, o = e.haveWidth, f = e.width, i = e.open, l = 0, c = e.x, u = e.y, d = 0, v = 0, p = 0, g = 0, m = 0, y = 0, T = 0, C = 0, b = 0, _ = 0, M = Typr.T.CFF, x = Typr.U.P, P = s.nominalWidthX, w = { val: 0, size: 0 }; l < t.length;) { M.getCharString(t, l, w); var S = w.val; if (l += w.size, "o1" == S || "o18" == S) a.length % 2 != 0 && !o && (f = a.shift() + P), h += a.length >> 1, a.length = 0, o = !0; else if ("o3" == S || "o23" == S) { a.length % 2 != 0 && !o && (f = a.shift() + P), h += a.length >> 1, a.length = 0, o = !0 } else if ("o4" == S) a.length > 1 && !o && (f = a.shift() + P, o = !0), i && x.ClosePath(n), u += a.pop(), x.MoveTo(n, c, u), i = !0; else if ("o5" == S) for (; a.length > 0;) c += a.shift(), u += a.shift(), x.LineTo(n, c, u); else if ("o6" == S || "o7" == S) for (var F = a.length, A = "o6" == S, U = 0; U < F; U++) { var G = a.shift(); A ? c += G : u += G, A = !A, x.LineTo(n, c, u) } else if ("o8" == S || "o24" == S) { F = a.length; for (var L = 0; L + 6 <= F;) d = c + a.shift(), v = u + a.shift(), p = d + a.shift(), g = v + a.shift(), c = p + a.shift(), u = g + a.shift(), x.CurveTo(n, d, v, p, g, c, u), L += 6; "o24" == S && (c += a.shift(), u += a.shift(), x.LineTo(n, c, u)) } else { if ("o11" == S) break; if ("o1234" == S || "o1235" == S || "o1236" == S || "o1237" == S) "o1234" == S && (v = u, p = (d = c + a.shift()) + a.shift(), _ = g = v + a.shift(), y = g, C = u, c = (T = (m = (b = p + a.shift()) + a.shift()) + a.shift()) + a.shift(), x.CurveTo(n, d, v, p, g, b, _), x.CurveTo(n, m, y, T, C, c, u)), "o1235" == S && (d = c + a.shift(), v = u + a.shift(), p = d + a.shift(), g = v + a.shift(), b = p + a.shift(), _ = g + a.shift(), m = b + a.shift(), y = _ + a.shift(), T = m + a.shift(), C = y + a.shift(), c = T + a.shift(), u = C + a.shift(), a.shift(), x.CurveTo(n, d, v, p, g, b, _), x.CurveTo(n, m, y, T, C, c, u)), "o1236" == S && (d = c + a.shift(), v = u + a.shift(), p = d + a.shift(), _ = g = v + a.shift(), y = g, T = (m = (b = p + a.shift()) + a.shift()) + a.shift(), C = y + a.shift(), c = T + a.shift(), x.CurveTo(n, d, v, p, g, b, _), x.CurveTo(n, m, y, T, C, c, u)), "o1237" == S && (d = c + a.shift(), v = u + a.shift(), p = d + a.shift(), g = v + a.shift(), b = p + a.shift(), _ = g + a.shift(), m = b + a.shift(), y = _ + a.shift(), T = m + a.shift(), C = y + a.shift(), Math.abs(T - c) > Math.abs(C - u) ? c = T + a.shift() : u = C + a.shift(), x.CurveTo(n, d, v, p, g, b, _), x.CurveTo(n, m, y, T, C, c, u)); else if ("o14" == S) { if (a.length > 0 && !o && (f = a.shift() + r.nominalWidthX, o = !0), 4 == a.length) { var k = a.shift(), O = a.shift(), V = a.shift(), W = a.shift(), B = M.glyphBySE(r, V), I = M.glyphBySE(r, W); Typr.U._drawCFF(r.CharStrings[B], e, r, s, n), e.x = k, e.y = O, Typr.U._drawCFF(r.CharStrings[I], e, r, s, n) } i && (x.ClosePath(n), i = !1) } else if ("o19" == S || "o20" == S) { a.length % 2 != 0 && !o && (f = a.shift() + P), h += a.length >> 1, a.length = 0, o = !0, l += h + 7 >> 3 } else if ("o21" == S) a.length > 2 && !o && (f = a.shift() + P, o = !0), u += a.pop(), c += a.pop(), i && x.ClosePath(n), x.MoveTo(n, c, u), i = !0; else if ("o22" == S) a.length > 1 && !o && (f = a.shift() + P, o = !0), c += a.pop(), i && x.ClosePath(n), x.MoveTo(n, c, u), i = !0; else if ("o25" == S) { for (; a.length > 6;) c += a.shift(), u += a.shift(), x.LineTo(n, c, u); d = c + a.shift(), v = u + a.shift(), p = d + a.shift(), g = v + a.shift(), c = p + a.shift(), u = g + a.shift(), x.CurveTo(n, d, v, p, g, c, u) } else if ("o26" == S) for (a.length % 2 && (c += a.shift()); a.length > 0;) d = c, v = u + a.shift(), c = p = d + a.shift(), u = (g = v + a.shift()) + a.shift(), x.CurveTo(n, d, v, p, g, c, u); else if ("o27" == S) for (a.length % 2 && (u += a.shift()); a.length > 0;) v = u, p = (d = c + a.shift()) + a.shift(), g = v + a.shift(), c = p + a.shift(), u = g, x.CurveTo(n, d, v, p, g, c, u); else if ("o10" == S || "o29" == S) { var q = "o10" == S ? s : r; if (0 == a.length) console.log("error: empty stack"); else { var Q = a.pop(), X = q.Subrs[Q + q.Bias]; e.x = c, e.y = u, e.nStems = h, e.haveWidth = o, e.width = f, e.open = i, Typr.U._drawCFF(X, e, r, s, n), c = e.x, u = e.y, h = e.nStems, o = e.haveWidth, f = e.width, i = e.open } } else if ("o30" == S || "o31" == S) { var D = a.length, E = (L = 0, "o31" == S); for (L += D - (F = -3 & D); L < F;) E ? (v = u, p = (d = c + a.shift()) + a.shift(), u = (g = v + a.shift()) + a.shift(), F - L == 5 ? (c = p + a.shift(), L++) : c = p, E = !1) : (d = c, v = u + a.shift(), p = d + a.shift(), g = v + a.shift(), c = p + a.shift(), F - L == 5 ? (u = g + a.shift(), L++) : u = g, E = !0), x.CurveTo(n, d, v, p, g, c, u), L += 4 } else { if ("o" == (S + "").charAt(0)) throw console.log("Unknown operation: " + S, t), S; a.push(S) } } } e.x = c, e.y = u, e.nStems = h, e.haveWidth = o, e.width = f, e.open = i }, SVG: function () { var t = { getScale: function (t) { return Math.sqrt(Math.abs(t[0] * t[3] - t[1] * t[2])) }, translate: function (e, r, s) { t.concat(e, [1, 0, 0, 1, r, s]) }, rotate: function (e, r) { t.concat(e, [Math.cos(r), -Math.sin(r), Math.sin(r), Math.cos(r), 0, 0]) }, scale: function (e, r, s) { t.concat(e, [r, 0, 0, s, 0, 0]) }, concat: function (t, e) { var r = t[0], s = t[1], n = t[2], a = t[3], h = t[4], o = t[5]; t[0] = r * e[0] + s * e[2], t[1] = r * e[1] + s * e[3], t[2] = n * e[0] + a * e[2], t[3] = n * e[1] + a * e[3], t[4] = h * e[0] + o * e[2] + e[4], t[5] = h * e[1] + o * e[3] + e[5] }, invert: function (t) { var e = t[0], r = t[1], s = t[2], n = t[3], a = t[4], h = t[5], o = e * n - r * s; t[0] = n / o, t[1] = -r / o, t[2] = -s / o, t[3] = e / o, t[4] = (s * h - n * a) / o, t[5] = (r * a - e * h) / o }, multPoint: function (t, e) { var r = e[0], s = e[1]; return [r * t[0] + s * t[2] + t[4], r * t[1] + s * t[3] + t[5]] }, multArray: function (t, e) { for (var r = 0; r < e.length; r += 2) { var s = e[r], n = e[r + 1]; e[r] = s * t[0] + n * t[2] + t[4], e[r + 1] = s * t[1] + n * t[3] + t[5] } } }; function e(t, e, r) { for (var s = [], n = 0, a = 0, h = 0; ;) { var o = t.indexOf(e, a), f = t.indexOf(r, a); if (-1 == o && -1 == f) break; -1 == f || -1 != o && o < f ? (0 == h && (s.push(t.slice(n, o).trim()), n = o + 1), h++, a = o + 1) : (-1 == o || -1 != f && f < o) && (0 == --h && (s.push(t.slice(n, f).trim()), n = f + 1), a = f + 1) } return s } function r(r) { for (var n = e(r, "(", ")"), a = [1, 0, 0, 1, 0, 0], h = 0; h < n.length; h += 2) { var o = a; a = s(n[h], n[h + 1]), t.concat(a, o) } return a } function s(e, r) { for (var s = [1, 0, 0, 1, 0, 0], n = !0, a = 0; a < r.length; a++) { var h = r.charAt(a); "," == h || " " == h ? n = !0 : "." == h ? (n || (r = r.slice(0, a) + "," + r.slice(a), a++), n = !1) : "-" == h && a > 0 && "e" != r[a - 1] && (r = r.slice(0, a) + " " + r.slice(a), a++, n = !0) } if (r = r.split(/\s*[\s,]\s*/).map(parseFloat), "translate" == e) 1 == r.length ? t.translate(s, r[0], 0) : t.translate(s, r[0], r[1]); else if ("scale" == e) 1 == r.length ? t.scale(s, r[0], r[0]) : t.scale(s, r[0], r[1]); else if ("rotate" == e) { var o = 0, f = 0; 1 != r.length && (o = r[1], f = r[2]), t.translate(s, -o, -f), t.rotate(s, -Math.PI * r[0] / 180), t.translate(s, o, f) } else "matrix" == e ? s = r : console.log("unknown transform: ", e); return s } function n(e, s, a) { for (var o = 0; o < e.length; o++) { var f = e[o], i = f.tagName, l = f.getAttribute("fill"); if (null == l && (l = a), "g" == i) { var c = { crds: [], cmds: [] }; n(f.children, c, l); var u = f.getAttribute("transform"); if (u) { var d = r(u); t.multArray(d, c.crds) } s.crds = s.crds.concat(c.crds), s.cmds = s.cmds.concat(c.cmds) } else if ("path" == i || "circle" == i || "ellipse" == i) { var v; if (s.cmds.push(l || "#000000"), "path" == i && (v = f.getAttribute("d")), "circle" == i || "ellipse" == i) { for (var p = [0, 0, 0, 0], g = ["cx", "cy", "rx", "ry", "r"], m = 0; m < 5; m++) { var y = f.getAttribute(g[m]); y && (y = parseFloat(y), m < 4 ? p[m] = y : p[2] = p[3] = y) } var T = p[0], C = p[1], b = p[2], _ = p[3]; v = ["M", T - b, C, "a", b, _, 0, 1, 0, 2 * b, 0, "a", b, _, 0, 1, 0, 2 * -b, 0].join(" ") } h(v, s), s.cmds.push("X") } else "defs" == i || console.log(i, f) } } function a(t, e, r) { for (var s = e; s < t.length && "string" != typeof t[s];) s += r; return (s - e) / r } function h(t, e) { for (var r = function (t) { for (var e = [], r = 0, s = !1, n = "", a = ""; r < t.length;) { var h = t.charCodeAt(r), o = t.charAt(r); r++; var f = 48 <= h && h <= 57 || "." == o || "-" == o || "e" == o || "E" == o; s ? "-" == o && "e" != a || "." == o && -1 != n.indexOf(".") ? (e.push(parseFloat(n)), n = o) : f ? n += o : (e.push(parseFloat(n)), "," != o && " " != o && e.push(o), s = !1) : f ? (n = o, s = !0) : "," != o && " " != o && e.push(o), a = o } return s && e.push(parseFloat(n)), e }(t), s = 0, n = 0, h = 0, o = 0, f = 0, i = e.crds.length, l = { M: 2, L: 2, H: 1, V: 1, T: 2, S: 4, A: 7, Q: 4, C: 6 }, c = e.cmds, u = e.crds; s < r.length;) { var d = r[s]; s++; var v = d.toUpperCase(); if ("Z" == v) c.push("Z"), n = o, h = f; else for (var p = a(r, s, l[v]), g = 0; g < p; g++) { 1 == g && "M" == v && (d = d == v ? "L" : "l", v = "L"); var m = 0, y = 0; if (d != v && (m = n, y = h), "M" == v) n = m + r[s++], h = y + r[s++], c.push("M"), u.push(n, h), o = n, f = h; else if ("L" == v) n = m + r[s++], h = y + r[s++], c.push("L"), u.push(n, h); else if ("H" == v) n = m + r[s++], c.push("L"), u.push(n, h); else if ("V" == v) h = y + r[s++], c.push("L"), u.push(n, h); else if ("Q" == v) { var T = m + r[s++], C = y + r[s++], b = m + r[s++], _ = y + r[s++]; c.push("Q"), u.push(T, C, b, _), n = b, h = _ } else if ("T" == v) { T = n + n - u[P = Math.max(u.length - 2, i)], C = h + h - u[P + 1], b = m + r[s++], _ = y + r[s++]; c.push("Q"), u.push(T, C, b, _), n = b, h = _ } else if ("C" == v) { T = m + r[s++], C = y + r[s++], b = m + r[s++], _ = y + r[s++]; var M = m + r[s++], x = y + r[s++]; c.push("C"), u.push(T, C, b, _, M, x), n = M, h = x } else if ("S" == v) { var P; T = n + n - u[P = Math.max(u.length - ("C" == c[c.length - 1] ? 4 : 2), i)], C = h + h - u[P + 1], b = m + r[s++], _ = y + r[s++], M = m + r[s++], x = y + r[s++]; c.push("C"), u.push(T, C, b, _, M, x), n = M, h = x } else if ("A" == v) { T = n, C = h; var w = r[s++], S = r[s++], F = r[s++] * (Math.PI / 180), A = r[s++], U = r[s++]; b = m + r[s++], _ = y + r[s++]; if (b == n && _ == h && 0 == w && 0 == S) continue; var G = (T - b) / 2, L = (C - _) / 2, k = Math.cos(F), O = Math.sin(F), V = k * G + O * L, W = -O * G + k * L, B = w * w, I = S * S, q = V * V, Q = W * W, X = (B * I - B * Q - I * q) / (B * Q + I * q), D = (A != U ? 1 : -1) * Math.sqrt(Math.max(X, 0)), E = D * (w * W) / S, H = S * V * -D / w, R = k * E - O * H + (T + b) / 2, Z = O * E + k * H + (C + _) / 2, z = function (t, e, r, s) { var n = (t * r + e * s) / (Math.sqrt(t * t + e * e) * Math.sqrt(r * r + s * s)); return (t * s - e * r >= 0 ? 1 : -1) * Math.acos(Math.max(-1, Math.min(1, n))) }, N = (V - E) / w, j = (W - H) / S, J = z(1, 0, N, j), K = z(N, j, (-V - E) / w, (-W - H) / S); !function (t, e, r, s, n, a, h) { var o = function (t, e) { var r = Math.sin(e), s = Math.cos(e), n = (e = t[0], t[1]), a = t[2], h = t[3]; t[0] = e * s + n * r, t[1] = -e * r + n * s, t[2] = a * s + h * r, t[3] = -a * r + h * s }, f = function (t, e) { for (var r = 0; r < e.length; r += 2) { var s = e[r], n = e[r + 1]; e[r] = t[0] * s + t[2] * n + t[4], e[r + 1] = t[1] * s + t[3] * n + t[5] } }, i = function (t, e) { for (var r = 0; r < e.length; r++) t.push(e[r]) }; if (h) for (; a > n;) a -= 2 * Math.PI; else for (; a < n;) a += 2 * Math.PI; var l = (a - n) / 4, c = Math.cos(l / 2), u = -Math.sin(l / 2), d = (4 - c) / 3, v = 0 == u ? u : (1 - c) * (3 - c) / (3 * u), p = [d, v, d, -v, c, -u], g = { cmds: ["C", "C", "C", "C"], crds: p.slice(0) }, m = [1, 0, 0, 1, 0, 0]; o(m, -l); for (var y = 0; y < 3; y++) f(m, p), i(g.crds, p); o(m, l / 2 - n), m[0] *= s, m[1] *= s, m[2] *= s, m[3] *= s, m[4] = e, m[5] = r, f(m, g.crds), f(t.ctm, g.crds), function (t, e) { i(t.cmds, e.cmds), i(t.crds, e.crds) }(t.pth, g) }({ pth: e, ctm: [w * k, w * O, -S * O, S * k, R, Z] }, 0, 0, 1, J, J + (K %= 2 * Math.PI), 0 == U), n = b, h = _ } else console.log("Unknown SVG command " + d) } } } return { cssMap: function (t) { for (var r = e(t, "{", "}"), s = {}, n = 0; n < r.length; n += 2) for (var a = r[n].split(","), h = 0; h < a.length; h++) { var o = a[h].trim(); null == s[o] && (s[o] = ""), s[o] += r[n + 1] } return s }, readTrnf: r, svgToPath: h, toPath: function (t) { var e = { cmds: [], crds: [] }; if (null == t) return e; var r = (new DOMParser).parseFromString(t, "image/svg+xml").getElementsByTagName("svg")[0], s = r.getAttribute("viewBox"); s = s ? s.trim().split(" ").map(parseFloat) : [0, 0, 1e3, 1e3], n(r.children, e); for (var a = 0; a < e.crds.length; a += 2) { var h = e.crds[a], o = e.crds[a + 1]; h -= s[0], o = -(o -= s[1]), e.crds[a] = h, e.crds[a + 1] = o } return e } } }(), initHB: function (t, e) { var r = function (t) { var e = 0; return 0 == (4294967168 & t) ? e = 1 : 0 == (4294965248 & t) ? e = 2 : 0 == (4294901760 & t) ? e = 3 : 0 == (4292870144 & t) && (e = 4), e }, s = new window.TextEncoder("utf8"); fetch(t).then((function (t) { return t.arrayBuffer() })).then((function (t) { return WebAssembly.instantiate(t) })).then((function (t) { console.log("HB ready"); var n = t.instance.exports, a = n.memory; a.grow(700); var h, o, f, i, l, c = new Uint8Array(a.buffer), u = new Uint32Array(a.buffer), d = new Int32Array(a.buffer); Typr.U.shapeHB = function (t, e, a) { var v = t._data, p = t.name.postScriptName; h != p && (null != o && (n.hb_blob_destroy(o), n.free(f), n.hb_face_destroy(i), n.hb_font_destroy(l)), f = n.malloc(v.byteLength), c.set(v, f), o = n.hb_blob_create(f, v.byteLength, 2, 0, 0), i = n.hb_face_create(o, 0), l = n.hb_font_create(i), h = p); var g = n.hb_buffer_create(), m = s.encode(e), y = m.length, T = n.malloc(y); c.set(m, T), n.hb_buffer_add_utf8(g, T, y, 0, y), n.free(T), n.hb_buffer_set_direction(g, a ? 4 : 5), n.hb_buffer_guess_segment_properties(g), n.hb_shape(l, g, 0, 0); var C = function (t) { for (var e = n.hb_buffer_get_length(t), r = [], s = n.hb_buffer_get_glyph_infos(t, 0) >>> 2, a = n.hb_buffer_get_glyph_positions(t, 0) >>> 2, h = 0; h < e; ++h) { var o = s + 5 * h, f = a + 5 * h; r.push({ g: u[o + 0], cl: u[o + 2], ax: d[f + 0], ay: d[f + 1], dx: d[f + 2], dy: d[f + 3] }) } return r }(g); n.hb_buffer_destroy(g); var b = C.slice(0); a || b.reverse(); for (var _ = 0, M = 0, x = 1; x < b.length; x++) { for (var P = b[x], w = P.cl; ;) { var S = e.codePointAt(_), F = r(S); if (!(M + F <= w)) break; M += F, _ += S <= 65535 ? 1 : 2 } P.cl = _ } return C }, e() })) } }; var $tip = $('style:contains(font-cxsecret)'); if (!$tip.length) return; var font = $tip.text().match(/base64,([\w\W]+?)'/)[1]; font = Typr.parse(this.base64ToUint8Array(font))[0]; const ttflist = ["ttf1", "ttf2", "ttf3"] for (let i = 0; i < ttflist.length; i++) { try { var table = JSON.parse(GM_getResourceText(ttflist[i])); break; } catch (e) { continue; } } // var table = JSON.parse(GM_getResourceText('ttf')); var match = {}; for (var i = 19968; i < 40870; i++) { $tip = Typr.U.codeToGlyph(font, i); if (!$tip) continue; $tip = Typr.U.glyphToPath(font, $tip); $tip = md5(JSON.stringify($tip)).slice(24); match[i] = table[$tip]; } $('.font-cxsecret').html(function (index, html) { $.each(match, function (key, value) { key = String.fromCharCode(key); key = new RegExp(key, 'g'); value = String.fromCharCode(value); html = html.replace(key, value); }); return html; }).removeClass('font-cxsecret'); }, base64ToUint8Array(base64) { var data = window.atob(base64); var buffer = new Uint8Array(data.length); for (var i = 0; i < data.length; ++i) { buffer[i] = data.charCodeAt(i); } return buffer; }, getQuestion: function (type, html = '') { let questionHtml, questionText, questionType, questionTypeId, optionHtml, tokenHtml, workType, optionText, index; switch (type) { case '1': workType = "zj" questionHtml = $(html).find(".clearfix .fontLabel"); questionText = utils.removeHtml(questionHtml[0].innerHTML).cl(); questionTypeId = $(html).find("input[name^=answertype]:eq(0)").val(); optionHtml = $(html).find('ul:eq(0) li .after'); tokenHtml = html.innerHTML; optionText = []; optionHtml.each(function (index, item) { optionText.push(utils.removeHtml(item.innerHTML)); }); break; case '2': workType = "zy" questionHtml = $(html).find(".mark_name"); index = questionHtml[0].innerHTML.indexOf(''); questionText = utils.removeHtml(questionHtml[0].innerHTML.substring(index + 7)).cl(); questionType = questionHtml[0].getElementsByTagName('span')[0].innerHTML.replace('(', '').replace(')', '').split(',')[0]; questionTypeId = $(html).find("input[name^=answertype]:eq(0)").val(); optionHtml = $(html).find(".answer_p"); tokenHtml = html.innerHTML; optionText = []; for (let i = 0; i < optionHtml.length; i++) { optionText.push(utils.removeHtml(optionHtml[i].innerHTML)); } break; case '3': workType = "ks" questionHtml = document.getElementsByClassName('mark_name colorDeep'); index = questionHtml[0].innerHTML.indexOf(''); questionText = utils.removeHtml(questionHtml[0].innerHTML.substring(index + 7)).cl(); questionType = questionHtml[0].getElementsByTagName('span')[0].innerHTML.replace('(', '').replace(')', '').split(',')[0]; questionTypeId = $("input[name^=type]:eq(1)").val(); optionHtml = document.getElementsByClassName('answer_p'); tokenHtml = document.getElementsByClassName('mark_table')[0].innerHTML; optionText = []; for (let i = 0; i < optionHtml.length; i++) { optionText.push(utils.removeHtml(optionHtml[i].innerHTML)); } if (!defaultConfig.hidden) { let layx_content = document.getElementById('layx_content'); layx_content.innerHTML = '
' + questionType + '' + questionText + '
答案正在获取中
'; let option = document.getElementsByClassName('option')[0]; for (let i = 0; i < optionText.length; i++) { option.innerHTML += '
' + String.fromCharCode(65 + i) + '、' + optionText[i] + '
'; } let answer = document.getElementsByClassName('answer')[0]; answer.innerHTML = '答案正在获取中'; } break; } return { "question": questionText, "options": optionText, "type": questionTypeId, "questionData": tokenHtml, "workType": workType } }, answerFormat: function (answer) { //如果是数组 if (answer instanceof Array) { //去除null answer = answer.filter(function (item) { return item !== null; }); for (let i = 0; i < answer.length; i++) { answer[i] = utils.removeHtml(answer[i]); } } else if (typeof answer === 'string') { answer = answer.cl(); } return answer; }, setAnswer: function (type, options, answer) { answer = this.answerFormat(answer); switch (type) { case '0':// 单选 case '1':// 多选 this.clear(); var matchArr = utils.matchIndex(options, answer); for (var i = 0; i < matchArr.length; i++) { $(".answerBg").eq(matchArr[i]).click(); $(".option_item").eq(matchArr[i]).css("color", "green").css("font-weight", "bold"); } return matchArr.length > 0; case '3':// 判断 answer = answer[0]; answer && this.clear(); $(".answerBg").each(function () { if ($(this).find(".num_option").attr("data") == "true") { answer.match(/(^|,)(True|true|正确|是|对|√|T|ri)(,|$)/) && $(this).click() } else { answer.match(/(^|,)(False|false|错误|否|错|×|F|wr)(,|$)/) && $(this).click() } }); return ($(".answerBg").find(".check_answer").length > 0 || $(".answerBg").find(".check_answer_dx").length > 0); case '2':// 填空 case '9':// 程序填空 case '4':// 简答 case '5': case '6': case '7': var blankNum = $(".answerBg, .textDIV, .eidtDiv").find('textarea').length; if (blankNum != answer.length) { return false; } this.clear(); $(".answerBg, .textDIV, .eidtDiv").find('textarea').each(function (index) { _self.UE.getEditor($(this).attr('name')).ready(function () { this.setContent(answer[index].replace(/第.空:/g, "")); }); }); return true; default: return false; } }, setWorkAnswer: function (type, options, answer, inx) { answer = this.answerFormat(answer); let item = $(".questionLi").eq(inx); switch (type) { case '0':// 单选 case '1':// 多选 this.clearCurrent(item); var matchArr = utils.matchIndex(options, answer); for (var i = 0; i < matchArr.length; i++) { item.find(".answerBg").eq(matchArr[i]).click(); $(".option_item").eq(matchArr[i]).css("color", "green").css("font-weight", "bold"); } return matchArr.length > 0 && answer; case '3':// 判断 answer = answer[0]; answer && this.clearCurrent(item); item.find(".answerBg").each(function () { if ($(this).find(".num_option").attr("data") == "true") { answer.match(/(^|,)(True|true|正确|是|对|√|T|ri)(,|$)/) && $(this).click() } else { answer.match(/(^|,)(False|false|错误|否|错|×|F|wr)(,|$)/) && $(this).click() } }); return ($(".answerBg").find(".check_answer").length > 0 || $(".answerBg").find(".check_answer_dx").length > 0) && answer; case '2':// 填空 case '9':// 程序填空 case '4':// 简答 case '5': case '6': case '7': var blankNum = item.find('textarea').length; if (blankNum != answer.length) { return false; } page.clearCurrent(item); item.find('textarea').each(function (index) { _self.UE.getEditor($(this).attr('name')).ready(function () { this.setContent(answer[index]); }); }); return answer; default: return false; } }, setChapterAnswer: function (type, options, answer, inx) { if (location.href.includes('mooc2=1')) { return this.setChapterAnswerNew(type, options, answer, inx); } answer = this.answerFormat(answer); let item = $(".TiMu").eq(inx); switch (type) { case '0':// 单选 case '1':// 多选 page.clearCurrent(item); var matchArr = utils.matchIndex(options, answer); if (matchArr.length > 0) { for (var i = 0; i < matchArr.length; i++) { item.find('ul:eq(0) li :radio,:checkbox,textarea').eq(matchArr[i]).click(); $(".option_item").eq(matchArr[i]).css("color", "green").css("font-weight", "bold"); } return answer; } else { matchArr = utils.fuzzyMatchIndex(options, answer); for (var i = 0; i < matchArr.length; i++) { item.find('ul:eq(0) li :radio,:checkbox,textarea').eq(matchArr[i]).click(); $(".option_item").eq(matchArr[i]).css("color", "green").css("font-weight", "bold"); } if (!matchArr.length) { var random = Math.floor(Math.random() * options.length); item.find('ul:eq(0) li :radio,:checkbox,textarea').eq(random).click(); return false; } return matchArr.length > 0; } case '3':// 判断 answer = answer[0]; answer && page.clearCurrent(item); item.find('ul:eq(0) li :radio,:checkbox,textarea').each(function () { if ($(this).val() == "true") { answer.match(/(^|,)(True|true|正确|是|对|√|T|ri)(,|$)/) && $(this).click() } else { answer.match(/(^|,)(False|false|错误|否|错|×|F|wr)(,|$)/) && $(this).click() } }); let isCheck = item.find('ul:eq(0) li :radio,:checkbox,textarea').is(':checked'); if (!isCheck) { var random = Math.floor(Math.random() * 2); item.find('ul:eq(0) li :radio,:checkbox,textarea').eq(random).click(); } return isCheck && answer; case '2':// 填空 case '9':// 程序填空 case '4':// 简答 case '5': case '6': case '7': var blankNum = item.find('textarea').length; if (blankNum != answer.length) { return false; } page.clearCurrent(item); item.find('textarea').each(function (index) { _self.UE.getEditor($(this).attr('name')).ready(function () { this.setContent(answer[index]); }); }); return answer; default: return false; } }, setChapterAnswerNew: function (type, options, answer, inx) { answer = this.answerFormat(answer); let item = $(".TiMu").eq(inx); switch (type) { case '0':// 单选 case '1':// 多选 page.clearCurrentNew(item); var matchArr = utils.matchIndex(options, answer); if (matchArr.length > 0) { for (var i = 0; i < matchArr.length; i++) { item.find('ul:eq(0) li,:checkbox,textarea').eq(matchArr[i]).click(); $(".option_item").eq(matchArr[i]).css("color", "green").css("font-weight", "bold"); } return answer; } else { matchArr = utils.fuzzyMatchIndex(options, answer); for (var i = 0; i < matchArr.length; i++) { item.find('ul:eq(0) li,:checkbox,textarea').eq(matchArr[i]).click(); $(".option_item").eq(matchArr[i]).css("color", "green").css("font-weight", "bold"); } if (!matchArr.length) { var random = Math.floor(Math.random() * options.length); item.find('ul:eq(0) li,:checkbox,textarea').eq(random).click(); return false; } return matchArr.length > 0; } case '3':// 判断 answer = answer[0]; answer && page.clearCurrentNew(item); item.find('ul:eq(0) li,:checkbox,textarea').each(function () { if ($(this).attr('aria-label').includes('对')) { answer.match(/(^|,)(True|true|正确|是|对|√|T|ri)(,|$)/) && $(this).click() } else { answer.match(/(^|,)(False|false|错误|否|错|×|F|wr)(,|$)/) && $(this).click() } }); // let isCheck = item.find('ul:eq(0) li,:checkbox,textarea').is(':checked'); let isCheck = item.find('ul:eq(0) li,:checkbox,textarea').filter(function () { return $(this).attr('aria-checked') == 'true'; }).length > 0; if (!isCheck) { var random = Math.floor(Math.random() * 2); item.find('ul:eq(0) li,:checkbox,textarea').eq(random).click(); } return isCheck && answer; case '2':// 填空 case '9':// 程序填空 case '4':// 简答 case '5': case '6': case '7': var blankNum = item.find('textarea').length; if (blankNum != answer.length) { return false; } page.clearCurrent(item); item.find('textarea').each(function (index) { _self.UE.getEditor($(this).attr('name')).ready(function () { this.setContent(answer[index]); }); }); return answer; default: return false; } }, randomChapterAnswer: function (type, options, inx) { let item = $(".TiMu").eq(inx); switch (type) { case '0':// 单选 case '1':// 多选 var random = Math.floor(Math.random() * options.length); item.find('ul:eq(0) li :radio,:checkbox,textarea').eq(random).click(); return true; case '3':// 判断 var random = Math.floor(Math.random() * 2); item.find('ul:eq(0) li :radio,:checkbox,textarea').eq(random).click(); return true; default: return false; } } , startAsk: async function (data) { const answer = document.getElementsByClassName('answer')[0]; let answerArr = await page.requestMerge(data); let validAnswer = answerArr.find(item => Array.isArray(item) && item.length > 0 && page.setAnswer(data.type, data.options, item)); if (!validAnswer && defaultConfig.freeFirst) { answerArr = await page.requestMerge(data, 1); validAnswer = answerArr.find(item => Array.isArray(item) && item.length > 0 && page.setAnswer(data.type, data.options, item)); } if (validAnswer) { answer.innerHTML = '答案:
' + validAnswer.join('
'); answer.style.color = 'green'; this.layx_status_msg(`已答题,等待切换 剩余次数:${reqUrl.num || '暂未获取'}`); } else { answer.innerHTML = answerArr.find(item => !Array.isArray(item) && item.length > 0 && item) || '暂无答案'; this.layx_status_msg("答案匹配失败,等待切换"); } await utils.sleep(defaultConfig.interval); defaultConfig.autoSwitch && $('.nextDiv .jb_btn:contains("下一题")').click(); !$('.nextDiv .jb_btn:contains("下一题")') && this.layx_status_msg("答题已完成"); }, startWork: async function () { let layx_content = $("#layx_content"), questionList = $(".questionLi"), tableHTML = `
题号 题目 答案
`; layx_content.html(tableHTML); async function startWorkTask(workinx) { let data = page.getQuestion("2", questionList[workinx]); let tr = $('').css("border-bottom", "1px solid #ddd"); let td1 = $('').html(`${parseInt(workinx) + 1}`); let td2 = $('').html(`${data.question}`); let td3 = $(''); tr.append(td1, td2, td3); let answerArr = await page.requestMerge(data); let validAnswer = answerArr.find(item => Array.isArray(item) && item.length > 0 && page.setWorkAnswer(data.type, data.options, item, workinx)); if (!validAnswer && defaultConfig.freeFirst) { answerArr = await page.requestMerge(data, 1); validAnswer = answerArr.find(item => Array.isArray(item) && item.length > 0 && page.setWorkAnswer(data.type, data.options, item, workinx)); } if (validAnswer) { td3.html(validAnswer.join('
')); tr.css("color", "green"); defaultConfig.succ++; } else { let answerText = answerArr.find(item => !Array.isArray(item) && item.length > 0 && item) || '暂无答案'; // 检查是否包含"点我购买",如果包含则替换为激活按钮 if (answerText.includes('点我购买')) { let modifiedText = answerText.replace('点我购买', ''); td3.html(modifiedText); let activateBtn = $('