您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Greasy Fork is available in English.
1.自动进行课件播放时,因为菜所以进行时最好别点跳转或者切换,可能会导致任务停止2.自动回复默认取讨论区第一条。3.反对任何形式牟利,祝各位同学学业有成。
当前为
// ==UserScript== // @name cqooc重庆高等教育智慧教育平台学习助手 // @namespace http://tampermonkey.net/ // @version 2.6 // @description 1.自动进行课件播放时,因为菜所以进行时最好别点跳转或者切换,可能会导致任务停止2.自动回复默认取讨论区第一条。3.反对任何形式牟利,祝各位同学学业有成。 // @author Abstract // @include https://*.cqooc.com/* // @grant none // @run-at document-end // @require https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js // @require https://cdn.jsdelivr.net/npm/[email protected]/examples/js/controls/OrbitControls.js // @license MIT // ==/UserScript== (function() { 'use strict'; // ******************** 全局变量和函数定义 ******************** // 全局变量 let currentTimeout = null; let currentInterval = null; let pageInitialized = false; let pptTimeoutId = null; let currentPlayingVideo = null; let coursewareQueue = []; let isProcessing = false; // 定义课件完成状态的Base64编码,包括“未完成”、“半完成”和“已完成” const completionStatuses = { '未完成': 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAABGdBTUEAALGPC/xhBQAACklpQ0NQc1JHQiBJRUM2MTk2Ni0yLjEAAEiJnVN3WJP3Fj7f92UPVkLY8LGXbIEAIiOsCMgQWaIQkgBhhBASQMWFiApWFBURnEhVxILVCkidiOKgKLhnQYqIWotVXDjuH9yntX167+3t+9f7vOec5/zOec8PgBESJpHmomoAOVKFPDrYH49PSMTJvYACFUjgBCAQ5svCZwXFAADwA3l4fnSwP/wBr28AAgBw1S4kEsfh/4O6UCZXACCRAOAiEucLAZBSAMguVMgUAMgYALBTs2QKAJQAAGx5fEIiAKoNAOz0ST4FANipk9wXANiiHKkIAI0BAJkoRyQCQLsAYFWBUiwCwMIAoKxAIi4EwK4BgFm2MkcCgL0FAHaOWJAPQGAAgJlCLMwAIDgCAEMeE80DIEwDoDDSv+CpX3CFuEgBAMDLlc2XS9IzFLiV0Bp38vDg4iHiwmyxQmEXKRBmCeQinJebIxNI5wNMzgwAABr50cH+OD+Q5+bk4eZm52zv9MWi/mvwbyI+IfHf/ryMAgQAEE7P79pf5eXWA3DHAbB1v2upWwDaVgBo3/ldM9sJoFoK0Hr5i3k4/EAenqFQyDwdHAoLC+0lYqG9MOOLPv8z4W/gi372/EAe/tt68ABxmkCZrcCjg/1xYW52rlKO58sEQjFu9+cj/seFf/2OKdHiNLFcLBWK8ViJuFAiTcd5uVKRRCHJleIS6X8y8R+W/QmTdw0ArIZPwE62B7XLbMB+7gECiw5Y0nYAQH7zLYwaC5EAEGc0Mnn3AACTv/mPQCsBAM2XpOMAALzoGFyolBdMxggAAESggSqwQQcMwRSswA6cwR28wBcCYQZEQAwkwDwQQgbkgBwKoRiWQRlUwDrYBLWwAxqgEZrhELTBMTgN5+ASXIHrcBcGYBiewhi8hgkEQcgIE2EhOogRYo7YIs4IF5mOBCJhSDSSgKQg6YgUUSLFyHKkAqlCapFdSCPyLXIUOY1cQPqQ28ggMor8irxHMZSBslED1AJ1QLmoHxqKxqBz0XQ0D12AlqJr0Rq0Hj2AtqKn0UvodXQAfYqOY4DRMQ5mjNlhXIyHRWCJWBomxxZj5Vg1Vo81Yx1YN3YVG8CeYe8IJAKLgBPsCF6EEMJsgpCQR1hMWEOoJewjtBK6CFcJg4Qxwicik6hPtCV6EvnEeGI6sZBYRqwm7iEeIZ4lXicOE1+TSCQOyZLkTgohJZAySQtJa0jbSC2kU6Q+0hBpnEwm65Btyd7kCLKArCCXkbeQD5BPkvvJw+S3FDrFiOJMCaIkUqSUEko1ZT/lBKWfMkKZoKpRzame1AiqiDqfWkltoHZQL1OHqRM0dZolzZsWQ8ukLaPV0JppZ2n3aC/pdLoJ3YMeRZfQl9Jr6Afp5+mD9HcMDYYNg8dIYigZaxl7GacYtxkvmUymBdOXmchUMNcyG5lnmA+Yb1VYKvYqfBWRyhKVOpVWlX6V56pUVXNVP9V5qgtUq1UPq15WfaZGVbNQ46kJ1Bar1akdVbupNq7OUndSj1DPUV+jvl/9gvpjDbKGhUaghkijVGO3xhmNIRbGMmXxWELWclYD6yxrmE1iW7L57Ex2Bfsbdi97TFNDc6pmrGaRZp3mcc0BDsax4PA52ZxKziHODc57LQMtPy2x1mqtZq1+rTfaetq+2mLtcu0W7eva73VwnUCdLJ31Om0693UJuja6UbqFutt1z+o+02PreekJ9cr1Dund0Uf1bfSj9Rfq79bv0R83MDQINpAZbDE4Y/DMkGPoa5hpuNHwhOGoEctoupHEaKPRSaMnuCbuh2fjNXgXPmasbxxirDTeZdxrPGFiaTLbpMSkxeS+Kc2Ua5pmutG003TMzMgs3KzYrMnsjjnVnGueYb7ZvNv8jYWlRZzFSos2i8eW2pZ8ywWWTZb3rJhWPlZ5VvVW16xJ1lzrLOtt1ldsUBtXmwybOpvLtqitm63Edptt3xTiFI8p0in1U27aMez87ArsmuwG7Tn2YfYl9m32zx3MHBId1jt0O3xydHXMdmxwvOuk4TTDqcSpw+lXZxtnoXOd8zUXpkuQyxKXdpcXU22niqdun3rLleUa7rrStdP1o5u7m9yt2W3U3cw9xX2r+00umxvJXcM970H08PdY4nHM452nm6fC85DnL152Xlle+70eT7OcJp7WMG3I28Rb4L3Le2A6Pj1l+s7pAz7GPgKfep+Hvqa+It89viN+1n6Zfgf8nvs7+sv9j/i/4XnyFvFOBWABwQHlAb2BGoGzA2sDHwSZBKUHNQWNBbsGLww+FUIMCQ1ZH3KTb8AX8hv5YzPcZyya0RXKCJ0VWhv6MMwmTB7WEY6GzwjfEH5vpvlM6cy2CIjgR2yIuB9pGZkX+X0UKSoyqi7qUbRTdHF09yzWrORZ+2e9jvGPqYy5O9tqtnJ2Z6xqbFJsY+ybuIC4qriBeIf4RfGXEnQTJAntieTE2MQ9ieNzAudsmjOc5JpUlnRjruXcorkX5unOy553PFk1WZB8OIWYEpeyP+WDIEJQLxhP5aduTR0T8oSbhU9FvqKNolGxt7hKPJLmnVaV9jjdO31D+miGT0Z1xjMJT1IreZEZkrkj801WRNberM/ZcdktOZSclJyjUg1plrQr1zC3KLdPZisrkw3keeZtyhuTh8r35CP5c/PbFWyFTNGjtFKuUA4WTC+oK3hbGFt4uEi9SFrUM99m/ur5IwuCFny9kLBQuLCz2Lh4WfHgIr9FuxYji1MXdy4xXVK6ZHhp8NJ9y2jLspb9UOJYUlXyannc8o5Sg9KlpUMrglc0lamUycturvRauWMVYZVkVe9ql9VbVn8qF5VfrHCsqK74sEa45uJXTl/VfPV5bdra3kq3yu3rSOuk626s91m/r0q9akHV0IbwDa0b8Y3lG19tSt50oXpq9Y7NtM3KzQM1YTXtW8y2rNvyoTaj9nqdf13LVv2tq7e+2Sba1r/dd3vzDoMdFTve75TsvLUreFdrvUV99W7S7oLdjxpiG7q/5n7duEd3T8Wej3ulewf2Re/ranRvbNyvv7+yCW1SNo0eSDpw5ZuAb9qb7Zp3tXBaKg7CQeXBJ9+mfHvjUOihzsPcw83fmX+39QjrSHkr0jq/dawto22gPaG97+iMo50dXh1Hvrf/fu8x42N1xzWPV56gnSg98fnkgpPjp2Snnp1OPz3Umdx590z8mWtdUV29Z0PPnj8XdO5Mt1/3yfPe549d8Lxw9CL3Ytslt0utPa49R35w/eFIr1tv62X3y+1XPK509E3rO9Hv03/6asDVc9f41y5dn3m978bsG7duJt0cuCW69fh29u0XdwruTNxdeo94r/y+2v3qB/oP6n+0/rFlwG3g+GDAYM/DWQ/vDgmHnv6U/9OH4dJHzEfVI0YjjY+dHx8bDRq98mTOk+GnsqcTz8p+Vv9563Or59/94vtLz1j82PAL+YvPv655qfNy76uprzrHI8cfvM55PfGm/K3O233vuO+638e9H5ko/ED+UPPR+mPHp9BP9z7nfP78L/eE8/stRzjPAAAAIGNIUk0AAHomAACAhAAA+gAAAIDoAAB1MAAA6mAAADqYAAAXcJy6UTwAAAAJcEhZcwAACxMAAAsTAQCanBgAAADXSURBVBiVjZA7agJRAEXPewHRZViMC5AYZGxN5Sc7mPRJESJoO2JjYdDO2YidWEgI5qMbkIC7mFFHvTYTCBohp7yc5h4jCYBcu3QHPBljbgAkfQL9ZfttRDLg+G63Fnh6/f5QvIsV72JNlzNVh54c3+1IAsd36/XgXuEm0inhJlIt8OT4bsUCjdbtI5lUmlMyqTTN8gPAs72ytlDM5s+kH4rZPMaYawvoogUkX7H7w2E+Wy0uiu+rBZLmFuj3xkOi7fpMCrcRL5MAYPDvPOaP4IWk79fv4Eft841qprSDGwAAAABJRU5ErkJggg==', '半完成': 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAbVJREFUSEu9ls8rRFEUx7/nzsjvjWQxSSTPJE1Zv0nUjEiIhRQbxQKTUiSr914pK6mJFWUjlqL8ysbCrJWVIWUh/wBF4R3d18w0zMwzi7nztu/7zuee7zn3nEdweQJGV/2H+BqCzf0gNAPwJeQvYDxC0EmZ7T26ta6ec4WhbC9aDd3HBIsZkwB73A4B0DcRdolhxK3Yy19tBqDV0AcZ2GNwtVd4EPJ3IuzvRLvPj7rqWnSshbPyCPRKwETcih2nC34BWszgPGBvgCFk0OWeOTTU1P8KqJl67oQINiAWHszraFKUAsiT28SHBBKLoRlM6+NZA7kC5BcEWzANJzNxAI7nwJ20ZSk8mzO41P4LcBiOXX5ZEwegmfo2M09JW7bG1lxrmg/ASYRo596MTZNsxXd8PnmF8JxH9jM8/0vLFyC7qxwljaRZwTm27c3etm5ER1fdOzJPi1IFFiJCmqGfMrhvfcTAQKCnsADQGWmmHmdm7SJygKbahsICiO4l4JWZq25WLlFZWlFowFtRAIotUl5k1W2q/KIpHxVFGXYJiLpxnbxdShdOEqJ0ZaZB1C399GFUiN+WH16q+w/WuLNCAAAAAElFTkSuQmCC', '已完成': 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABgAAAAYCAYAAADgdz34AAAAAXNSR0IArs4c6QAAAfhJREFUSEu9lj1oE2EYx//PqaDYDJHaQlCoH7k4dVYuUMFFERSHQIeCUcxiih/QpXS4u9Gp9MNJwSWC4CAKKgiClgSLg4hkMIkBISFrhwhKPu4p7zWXz7vLXWjMmPd5/r/3+XyP4PKbVS+e+Cc1rsPgqyCcARBqmVfAKEKit4eNg69/6J/KTjJkdxBRlRATdGbcAviA2yUAahLhGTHUnJ6p9NsOACKqco2BFIMD7sK9pwSqErCQ0zNvuk96AGEteg8wVsGQ/Ii3bQkGID0saOl16782QNzcIH41snhH0ZCYbliRmAAz58BPv2lxLqyZrnOiJiZA1pQnzHxnpLQ4OBHR07yWSZBoxb+o/x7eLX7x1DyCQzMk69EkG8amX3cv9iRJiySryjsGX/Hi0G8zHZhEeOo00sWvtu4Eek+ypuSYWfYLOHv8FFLxDRw7GsSltRhKOwMzBiLKC0CVmSf8ALrFPxe+IPF8yT4Coj+ugNsX5vGtlMX3crYt0C9+98Uy6s26K8A2RSeDIXy8/xK1Rg1CZOvXNvyIC+JeilyKvHL5AW6ej5mQRx8eIzkXN3Mu0uJ2885QiyIPaVMLYjl5FTcjEG3qZdAsiB9xscbNQfO6KkRN7FrRcR9Zq+K/LLsWZHzr2gpzrA+OBRnrk9kFGd+j390V+/HZsgvSIhcecicecAAAAABJRU5ErkJggg==' }; const MAIN_PAGE_HOST = 'www.cqooc.com'; const IFRAME_PAGE_HOST = 'preview.cqooc.com'; // 模拟点击事件 function simulateClick(element) { if (!element) return; const event = new MouseEvent('click', { view: window, bubbles: true, cancelable: true }); element.dispatchEvent(event); } // 递归展开所有父级内容 async function expandAllParentsAsync(element) { const parents = []; let parent = element.parentElement; // 收集所有父级需要展开的元素 while (parent && parent !== document.body) { if (parent.classList.contains('second-level-inner-box') || parent.classList.contains('first-level-inner-box')) { parents.push(parent); } parent = parent.parentElement; } parents.reverse(); // 从最外层开始展开 for (const parent of parents) { const toggleButton = parent.previousElementSibling.querySelector('.right-icon > i.anticon-down'); if (toggleButton) { // 检查当前是否已展开(通过检查内盒的高度) const innerBox = parent; const height = window.getComputedStyle(innerBox).height; if (height === '0px') { console.log('点击展开按钮:', toggleButton); toggleButton.click(); // 等待展开动画完成 await new Promise(resolve => setTimeout(resolve, 500)); } else { console.log('内容已展开,无需点击:', toggleButton); } } else { console.warn('未找到展开按钮,无法展开父级内容。'); } } } function waitForElement(selector, timeout) { return new Promise(resolve => { const startTime = Date.now(); const interval = setInterval(() => { const element = document.querySelector(selector); if (element) { clearInterval(interval); resolve(element); } else if (Date.now() - startTime > timeout) { clearInterval(interval); resolve(null); } }, 100); }); } // 批量自动回复 async function performBatchAutoReply(data, progressLabel) { let repliedCount = 0; for (const item of data.items) { try { await performAutoReply(item); repliedCount++; updateReplyProgress(data, progressLabel, repliedCount); } catch (error) { console.error('一键回复失败:', error); } } } // 单个自动回复 async function performAutoReply(itemData) { try { await jumpToContentItem(itemData.originalElement); const discussionArea = await waitForElement('.course-courseQaDiscussion-qa', 5000); if (!discussionArea) return; const replyButton = discussionArea.querySelector('.conv-option .reply'); if (!replyButton) return; replyButton.click(); const replyInput = await waitForElement('.course-courseQaDiscussion-reply textarea.ant-input', 2000); const submitButton = await waitForElement('.course-courseQaDiscussion-reply .ant-btn-primary', 2000); const firstReply = discussionArea.querySelector('.conv-subtitle'); if (replyInput && submitButton && firstReply) { replyInput.value = firstReply.textContent.trim(); replyInput.dispatchEvent(new Event('input', { bubbles: true })); submitButton.click(); // 更新状态为已回复 itemData.replyStatus = '已回复'; itemData.replyStatusElement.textContent = '已回复'; itemData.replyStatusElement.style.color = 'green'; console.log('自动回复完成'); } } catch (error) { console.error('自动回复失败:', error); } } // 更新回复进度 function updateReplyProgress(data, progressLabel, repliedCount = null) { if (repliedCount === null) { repliedCount = data.items.filter(item => item.replyStatus === '已回复').length; } progressLabel.textContent = `已回复:${repliedCount}/${data.items.length}`; } // 跳转到具体的内容项 async function jumpToContentItem(originalElement) { return new Promise(async (resolve, reject) => { try { console.log('准备跳转到内容项:', originalElement); // 重要:检查元素是否还存在于DOM中,如果不存在则重新查找 let targetElement = originalElement; if (!document.body.contains(originalElement)) { // 通过标题重新查找元素 const title = originalElement.querySelector('p.title')?.textContent.trim(); if (title) { targetElement = Array.from(document.querySelectorAll('.third-level-inner-box')) .find(el => el.querySelector('p.title')?.textContent.trim() === title); } if (!targetElement) { throw new Error('找不到目标元素'); } } // 确保父级展开 await expandAllParentsAsync(targetElement); // 查找可点击元素 const clickable = targetElement.querySelector('a') || targetElement.querySelector('p.title') || targetElement; if (!clickable) { throw new Error('未找到可点击的元素'); } // 滚动并点击 clickable.scrollIntoView({ behavior: 'smooth', block: 'center' }); setTimeout(() => { simulateClick(clickable); resolve(); }, 500); } catch (error) { console.error('跳转失败:', error); reject(error); } }); } function markCoursewareCompleted(coursewareElement) { if (!coursewareElement) { console.warn('[状态更新] 无效的课件元素'); return; } // 仅设置数据标记 coursewareElement.dataset.completed = 'true'; // 更新面板显示 updateCategoryPanelAfterCompletion(coursewareElement); console.log('[状态更新] 面板状态更新完成'); } // 监控任务完成状态 function monitorTaskCompletion(courseware) { return new Promise((resolve) => { if (!courseware || !courseware.element) { console.warn('[任务监控] 无效的课件对象'); resolve(); return; } const pageUrl = window.location.href; const checkInterval = 3000; let retries = 0; const maxRetries = 40; let lastProgress = -1; // 检查是否为空课件 const titleElement = courseware.element.querySelector('p.title'); if (titleElement && titleElement.textContent.includes('_swf')) { console.log('[任务监控] 检测到空课件,直接标记为完成'); markCoursewareAsCompleted(courseware.element); resolve(); return; } currentInterval = setInterval(() => { if (window.location.href !== pageUrl) { console.log('[任务监控] 检测到页面切换,停止监控'); clearInterval(currentInterval); resolve(); return; } retries++; console.log(`[任务监控] 第${retries}次检查任务状态`); // 获取当前进度 const video = document.querySelector('#dplayer video'); let currentProgress = 0; if (video) { currentProgress = (video.currentTime / video.duration) * 100; const progressChanged = Math.abs(currentProgress - lastProgress) > 1; if (!progressChanged && retries > 5) { console.log('[任务监控] 检测到任务可能卡住,尝试恢复'); clearInterval(currentInterval); resolve(); return; } lastProgress = currentProgress; } const videoCompleted = isVideoCompleted(courseware.element); const pptCompleted = isPptCompleted(courseware.element); if (videoCompleted || pptCompleted) { console.log('[任务监控] 任务完成'); markCoursewareAsCompleted(courseware.element); clearInterval(currentInterval); resolve(); return; } if (retries >= maxRetries) { console.log('[任务监控] 达到最大重试次数'); clearInterval(currentInterval); resolve(); } }, checkInterval); currentTimeout = setTimeout(() => { console.log('[任务监控] 任务超时'); clearInterval(currentInterval); resolve(); }, 1000 * 60); }); } // 修改 resetTaskState 函数,确保完全重置所有状态 function resetTaskState() { console.log('[任务状态] 开始重置任务状态'); if (currentTimeout) { clearTimeout(currentTimeout); currentTimeout = null; } if (currentInterval) { clearInterval(currentInterval); currentInterval = null; } isProcessing = false; console.log('[任务状态] 任务状态已重置'); } // 检查视频是否完成 function isVideoCompleted(coursewareElement) { // 1. 首先尝试在当前元素中查找 let video = coursewareElement.querySelector('video'); // 2. 如果找不到,尝试在整个文档中查找 if (!video) { video = document.querySelector('#dplayer video'); } // 3. 如果还是找不到,再尝试其他可能的选择器 if (!video) { video = document.querySelector('video'); } if (video) { const progress = (video.currentTime / video.duration) * 100; console.log("检查视频完成状态 - 当前进度: " + progress); console.log("视频当前时间:", video.currentTime); console.log("视频总时长:", video.duration); return progress >= 100; } // 添加更多调试信息 console.log("未找到视频元素,coursewareElement:", coursewareElement); console.log("coursewareElement的HTML:", coursewareElement.innerHTML); return false; } // 检查PPT是否完成 function isPptCompleted(coursewareElement) { if (!coursewareElement) { console.warn('[PPT状态检查] 无效的课件元素'); return false; } // 检查数据标记 if (coursewareElement.dataset.pptCompleted === 'true') { console.log('[PPT状态检查] 检测到完成标记'); return true; } // 检查完成图标 const completeIcon = coursewareElement.querySelector('img.file-complete'); if (completeIcon) { const src = completeIcon.getAttribute('src'); const isCompleted = src.includes(completionStatuses['已完成']); console.log(`[PPT状态检查] 图标状态检查结果: ${isCompleted}`); return isCompleted; } console.log('[PPT状态检查] 未找到完成状态标记'); return false; } // 标记课件为完成状态 function markCoursewareAsCompleted(coursewareElement) { if (!coursewareElement) { console.warn('[状态更新] 无效的课件元素'); return; } console.log('[状态更新] 开始更新课件状态'); try { // 更新数据标记 coursewareElement.dataset.completed = 'true'; coursewareElement.dataset.pptCompleted = 'true'; // 查找或创建状态图标 let statusIcon = coursewareElement.querySelector('img.file-complete'); if (!statusIcon) { // 如果找不到图标,尝试在正确的位置创建一个 const completeIconContainer = coursewareElement.querySelector('.complate-icon'); if (completeIconContainer) { statusIcon = document.createElement('img'); statusIcon.className = 'file-complete'; statusIcon.alt = '完成状态'; completeIconContainer.appendChild(statusIcon); } } if (statusIcon) { statusIcon.src = completionStatuses['已完成']; console.log('[状态更新] 已更新状态图标'); } else { console.warn('[状态更新] 未找到状态图标元素'); } // 触发自定义事件 document.dispatchEvent(new CustomEvent('coursewareCompleted', { detail: { element: coursewareElement } })); console.log('[状态更新] 课件状态更新完成'); // 更新分类面板的统计信息 updateCategoryPanelAfterCompletion(coursewareElement); } catch (error) { console.error('[状态更新] 更新状态时出错:', error); } } function debounce(func, wait) { let timeout; return function(...args) { const context = this; clearTimeout(timeout); timeout = setTimeout(() => func.apply(context, args), wait); }; } // 定义 hasPPT 和 hasVideo 函数 function hasPPT(element) { // 根据实际页面结构判断是否包含PPT return !!element.querySelector('.slide-img-container'); } function hasVideo(element) { // 根据实际页面结构判断是否包含视频 return !!element.querySelector('#dplayer') || !!element.querySelector('video'); } // 定义处理队列的函数 function processQueue() { if (isProcessing || !coursewareQueue || coursewareQueue.length === 0) { console.log('[队列处理] 队列为空或正在处理中'); return; } // 检查当前页面是否可见 if (document.hidden) { console.log('[队列处理] 页面不可见,暂停处理'); return; } isProcessing = true; const currentCourseware = coursewareQueue[0]; console.log('[队列处理] 开始处理课件:', currentCourseware); // 验证课件元素是否存在 if (!currentCourseware || !currentCourseware.element || !document.body.contains(currentCourseware.element)) { console.log('[队列处理] 当前课件元素已不存在,跳过'); coursewareQueue.shift(); isProcessing = false; setTimeout(processQueue, 2000); return; } // 触发课件的执行 jumpToContentItem(currentCourseware.element) .then(() => { return monitorTaskCompletion(currentCourseware); }) .then(() => { // 任务完成,处理下一个任务 coursewareQueue.shift(); isProcessing = false; setTimeout(processQueue, 2000); }) .catch(error => { console.error('[队列处理] 处理任务时出错:', error); coursewareQueue.shift(); isProcessing = false; setTimeout(processQueue, 2000); }); } // ******************** 主页面与iframe页面检测 ******************** if (window.location.hostname === MAIN_PAGE_HOST) { window.addEventListener('message', async function(event) { if (!event.data || event.data.type !== 'pptCompleted') return; console.log('[主页面] 收到PPT完成消息:', event.data); if (event.data.status === 'completed' && coursewareQueue.length > 0) { console.log('[主页面] 当前课件队列:', coursewareQueue); const currentCourseware = coursewareQueue[0]; if (!currentCourseware) { console.warn('[主页面] 未找到当前处理的课件'); return; } try { const currentCourseware = coursewareQueue[0]; if (!currentCourseware) { console.warn('[主页面] 未找到当前处理的课件'); return; } console.log('[主页面] 更新课件状态:', currentCourseware); // 标记完成 markCoursewareAsCompleted(currentCourseware.element); // 重置状态 resetTaskState(); // 处理队列 coursewareQueue.shift(); isProcessing = false; // 延迟处理下一个任务 setTimeout(processQueue, 2000); } catch (error) { console.error('[主页面] 处理PPT完成消息时出错:', error); resetTaskState(); } } }); // 初始化主页面功能 initCourseContentClassification(); initVideoAutoPlayAndMonitor(); } else if (window.location.hostname === IFRAME_PAGE_HOST) { initPptAutoPaging(); } function addUserInteractionListeners() { const itemSelector = '.third-level-inner-box'; // 确保这是正确的选择器 document.querySelectorAll(itemSelector).forEach(item => { const clickableElements = item.querySelectorAll('a, p.title, button'); clickableElements.forEach(element => { element.addEventListener('click', () => { console.log('[用户交互] 检测到用户点击了课件或跳转按钮'); handleUserInteraction(item); }); }); }); } function handleUserInteraction(coursewareElement) { // 如果当前正在处理的任务是这个课件,则标记为完成并继续队列 if (coursewareQueue.length > 0 && coursewareQueue[0].element === coursewareElement) { console.log('[用户交互] 当前任务与用户操作的课件匹配,标记为完成'); markCoursewareAsCompleted(coursewareElement); resetTaskState(); coursewareQueue.shift(); isProcessing = false; setTimeout(processQueue, 2000); // 延迟以确保下一个任务的处理 } else { console.log('[用户交互] 用户操作的课件不在当前处理的队列中,可能是其他任务'); } } // 初始化课程内容分类功能 function initCourseContentClassification() { // 添加用户交互检测 addUserInteractionListeners(); // ********** 课程内容分类配置 ********** // 定义分类关键词,确保“测验”优先匹配,避免被错误分类到“课件” const categoryKeywords = { '测验': ['测验', '测试'], '课件': ['课件', '小节', '视频'], '作业': ['作业'], '讨论': ['讨论', '答疑'], '考试': ['考试', '期末测试', '补考'], '其他': [] }; // 页面元素的选择器,根据实际页面进行调整 const itemSelector = '.third-level-inner-box'; // 每个内容项的选择器 const titleSelector = 'p.title, p.title-big'; // 内容项标题的选择器 // 存储已处理的内容项,防止重复处理 const processedItems = new Set(); // 创建展示面板 createDisplayPanel(); // 使用 MutationObserver 或等待内容加载 waitForContentLoaded(() => { extractAndCategorizeContent(); processQueue(); // 启动队列处理 }); // 提取并分类内容 function extractAndCategorizeContent() { // 获取所有内容项 const items = Array.from(document.querySelectorAll(itemSelector)); console.log('找到的内容项数量:', items.length); // 分类内容项 const categories = categorizeItems(items); // 获取面板内容容器 const panelContent = document.querySelector('#custom-display-container .panel-content'); if (!panelContent) { console.warn('未找到面板内容容器。'); return; } // 清空已有内容(避免重复添加) panelContent.innerHTML = ''; // 添加分类内容 for (const [categoryName, data] of Object.entries(categories)) { const categoryPanel = createCategoryPanel(categoryName, data); panelContent.appendChild(categoryPanel); } // 添加拖拽排序功能 addDragAndDrop(panelContent); } // 根据标题和完成状态分类内容项 function categorizeItems(items) { const categories = {}; items.forEach(item => { if (processedItems.has(item)) return; // 跳过已处理的项 const titleElement = item.querySelector(titleSelector); if (!titleElement) { console.warn('未找到标题元素,跳过该内容项。'); return; } const titleText = titleElement.textContent.trim(); console.log('找到的标题:', titleText); // 判断所属分类 let matchedCategory = '其他'; for (const [category, keywords] of Object.entries(categoryKeywords)) { if (keywords.some(keyword => titleText.includes(keyword))) { matchedCategory = category; break; } } // 特殊处理“课件”类别,统计完成状态 if (matchedCategory === '课件') { let status = '未完成'; // 默认状态为“未完成” const img = item.querySelector('img.file-complete'); if (img) { const src = img.getAttribute('src'); // 使用 includes 以确保匹配,即使 src 有参数或路径前缀 if (src.includes(completionStatuses['已完成'])) { status = '已完成'; } else if (src.includes(completionStatuses['半完成'])) { status = '半完成'; } else if (src.includes(completionStatuses['未完成'])) { status = '未完成'; } else { // 如果图片不匹配任何已知状态,默认归为“未完成” status = '未完成'; } } // 组合类别名,例如“课件” const fullCategory = '课件'; if (!categories[fullCategory]) { categories[fullCategory] = { items: [], completed: 0, halfCompleted: 0, total: 0 }; } categories[fullCategory].items.push({ element: item.cloneNode(true), status: status, originalElement: item // 存储主页面元素引用 }); // 克隆节点,避免影响原页面 categories[fullCategory].total += 1; if (status === '已完成') { categories[fullCategory].completed += 1; } else if (status === '半完成') { categories[fullCategory].halfCompleted += 1; } // 如果课件未完成或半完成,加入队列 if (status === '未完成' || status === '半完成') { coursewareQueue.push({ element: item, status: status }); } } else { // 其他类别按原方式处理,不添加状态图标 if (!categories[matchedCategory]) { categories[matchedCategory] = { items: [] }; } categories[matchedCategory].items.push({ element: item.cloneNode(true), originalElement: item // 存储主页面元素引用 }); // 克隆节点,避免影响原页面 } processedItems.add(item); // 标记为已处理 }); return categories; } // 创建可折叠的分类面板,并添加跳转按钮 function createCategoryPanel(categoryName, data) { // 创建面板容器 const panel = document.createElement('div'); panel.className = 'category-panel'; panel.style.border = '1px solid #ccc'; panel.style.margin = '10px 0'; panel.style.borderRadius = '5px'; panel.style.overflow = 'hidden'; // 创建标题容器 const headerContainer = document.createElement('div'); headerContainer.style.display = 'flex'; headerContainer.style.justifyContent = 'space-between'; headerContainer.style.alignItems = 'center'; headerContainer.style.background = '#f0f0f0'; headerContainer.style.padding = '10px'; headerContainer.style.cursor = 'pointer'; headerContainer.style.fontWeight = 'bold'; headerContainer.style.fontSize = '14px'; // 创建标题文本 const header = document.createElement('div'); if (categoryName === '课件') { const progress = `${data.completed}/${data.total}`; const halfProgress = data.halfCompleted; header.textContent = `课件 (已完成: ${progress}, 半完成: ${halfProgress})`; } else if (categoryName === '讨论') { // 初始化已回复计数 data.repliedCount = 0; header.textContent = `${categoryName} (${data.items.length})`; } else if (categoryName === '测验') { header.textContent = `${categoryName} (${data.items.length})`; } else { header.textContent = `${categoryName} (${data.items.length})`; } headerContainer.appendChild(header); // 创建内容容器 const content = document.createElement('div'); content.className = 'category-content'; content.style.display = 'none'; content.style.padding = '10px'; // 如果是“课件”类别,首先添加视频速度调节器 if (categoryName === '课件') { const speedControlContainer = document.createElement('div'); speedControlContainer.style.marginTop = '10px'; speedControlContainer.style.display = 'flex'; speedControlContainer.style.alignItems = 'center'; const speedLabel = document.createElement('label'); speedLabel.textContent = '视频速度: '; speedLabel.style.marginRight = '10px'; speedLabel.style.fontSize = '14px'; const speedSelect = document.createElement('select'); speedSelect.style.padding = '2px 5px'; speedSelect.style.fontSize = '14px'; // 从 localStorage 中获取存储的倍速值,默认值为 1 const storedSpeed = parseFloat(localStorage.getItem('videoPlaybackSpeed')) || 1; const speeds = [0.75, 1, 1.5, 2, 3]; speeds.forEach(speed => { const option = document.createElement('option'); option.value = speed; option.textContent = `${speed}x`; if (speed === storedSpeed) option.selected = true; // 根据存储的倍速值选中对应选项 speedSelect.appendChild(option); }); // 绑定改变事件,更新倍速 speedSelect.addEventListener('change', () => { const selectedSpeed = parseFloat(speedSelect.value); setVideoPlaybackSpeed(selectedSpeed); }); speedControlContainer.appendChild(speedLabel); speedControlContainer.appendChild(speedSelect); content.insertBefore(speedControlContainer, content.firstChild); // 添加在内容最前 } // 如果是“讨论”类别,添加“一键回复”按钮和进度显示 if (categoryName === '讨论') { const progressContainer = document.createElement('div'); progressContainer.style.marginTop = '10px'; progressContainer.style.display = 'flex'; progressContainer.style.justifyContent = 'space-between'; progressContainer.style.alignItems = 'center'; const progressLabel = document.createElement('span'); progressLabel.textContent = `已回复:0/${data.items.length}`; progressLabel.style.fontSize = '14px'; progressLabel.id = `reply-progress-${categoryName}`; progressContainer.appendChild(progressLabel); const replyAllButton = document.createElement('button'); replyAllButton.textContent = '一键回复'; replyAllButton.style.padding = '5px 10px'; replyAllButton.style.fontSize = '12px'; replyAllButton.style.cursor = 'pointer'; replyAllButton.style.backgroundColor = '#4caf50'; replyAllButton.style.color = '#fff'; replyAllButton.style.border = 'none'; replyAllButton.style.borderRadius = '3px'; replyAllButton.addEventListener('click', () => { performBatchAutoReply(data, progressLabel); }); progressContainer.appendChild(replyAllButton); content.insertBefore(progressContainer, content.firstChild); // 添加在内容最前 } // 如果是“测验”类别,添加“获取作答信息”按钮和进度显示 if (categoryName === '测验') { const testInfoContainer = document.createElement('div'); testInfoContainer.style.marginBottom = '10px'; testInfoContainer.style.display = 'flex'; testInfoContainer.style.justifyContent = 'space-between'; testInfoContainer.style.alignItems = 'center'; const progressLabel = document.createElement('span'); progressLabel.textContent = `已获取:0/${data.items.length}`; progressLabel.style.fontSize = '14px'; progressLabel.id = `test-info-progress-${categoryName}`; testInfoContainer.appendChild(progressLabel); const getInfoButton = document.createElement('button'); getInfoButton.textContent = '获取作答信息'; getInfoButton.style.padding = '5px 10px'; getInfoButton.style.fontSize = '12px'; getInfoButton.style.cursor = 'pointer'; getInfoButton.style.backgroundColor = '#4caf50'; getInfoButton.style.color = '#fff'; getInfoButton.style.border = 'none'; getInfoButton.style.borderRadius = '3px'; getInfoButton.addEventListener('click', () => { collectTestAttempts(data, progressLabel); }); testInfoContainer.appendChild(getInfoButton); content.appendChild(testInfoContainer); // 添加到折叠内容区域的顶部 } // 如果是“作业”类别,添加“获取作业信息”按钮和进度显示 if (categoryName === '作业') { const assignmentInfoContainer = document.createElement('div'); assignmentInfoContainer.style.marginBottom = '10px'; assignmentInfoContainer.style.display = 'flex'; assignmentInfoContainer.style.justifyContent = 'space-between'; assignmentInfoContainer.style.alignItems = 'center'; const progressLabel = document.createElement('span'); progressLabel.textContent = `已获取:0/${data.items.length}`; progressLabel.style.fontSize = '14px'; progressLabel.id = `assignment-info-progress-${categoryName}`; assignmentInfoContainer.appendChild(progressLabel); const getInfoButton = document.createElement('button'); getInfoButton.textContent = '获取作业信息'; getInfoButton.style.padding = '5px 10px'; getInfoButton.style.fontSize = '12px'; getInfoButton.style.cursor = 'pointer'; getInfoButton.style.backgroundColor = '#4caf50'; getInfoButton.style.color = '#fff'; getInfoButton.style.border = 'none'; getInfoButton.style.borderRadius = '3px'; getInfoButton.addEventListener('click', () => { collectAssignmentInfo(data, progressLabel); }); assignmentInfoContainer.appendChild(getInfoButton); content.appendChild(assignmentInfoContainer); } // 添加内容项到内容容器 data.items.forEach(itemData => { const taskItem = document.createElement('div'); taskItem.className = 'task-item'; taskItem.style.marginBottom = '5px'; taskItem.style.display = 'flex'; taskItem.style.alignItems = 'center'; taskItem.style.justifyContent = 'space-between'; const leftContent = document.createElement('div'); leftContent.style.display = 'flex'; leftContent.style.alignItems = 'center'; leftContent.style.flex = '1'; // Add completion status icon for courseware if (categoryName === '课件') { const statusIcon = document.createElement('img'); statusIcon.style.width = '16px'; statusIcon.style.height = '16px'; statusIcon.style.marginRight = '10px'; statusIcon.src = completionStatuses[itemData.status || '未完成']; leftContent.appendChild(statusIcon); } const taskName = document.createElement('span'); taskName.textContent = itemData.element.querySelector('p.title, p.title-big')?.textContent.trim() || '无标题'; leftContent.appendChild(taskName); // 存储 taskName 元素引用,以便后续更新 itemData.taskNameElement = taskName; // 如果是讨论项,添加回复状态标签 if (categoryName === '讨论') { const statusLabel = document.createElement('span'); statusLabel.textContent = '未回复'; statusLabel.style.marginLeft = '10px'; statusLabel.style.color = 'red'; statusLabel.className = 'reply-status'; itemData.replyStatusElement = statusLabel; // 保存引用以便更新 leftContent.appendChild(statusLabel); } const buttonsContainer = document.createElement('div'); buttonsContainer.style.display = 'flex'; buttonsContainer.style.gap = '5px'; // 添加跳转按钮 const itemJumpButton = createButton('跳转', '#007bff'); itemJumpButton.addEventListener('click', async (e) => { e.stopPropagation(); resetTaskState(); coursewareQueue = []; try { await jumpToContentItem(itemData.originalElement); } catch (error) { console.error('跳转失败:', error); } }); // 自动回复按钮 if (categoryName === '讨论') { const itemReplyButton = createButton('自动回复', '#4caf50'); itemReplyButton.addEventListener('click', async (e) => { e.stopPropagation(); try { await performAutoReply(itemData, data); } catch (error) { console.error('自动回复失败:', error); } }); buttonsContainer.appendChild(itemReplyButton); } buttonsContainer.appendChild(itemJumpButton); taskItem.appendChild(leftContent); taskItem.appendChild(buttonsContainer); content.appendChild(taskItem); }); function createButton(text, bgColor, icon = '') { const button = document.createElement('button'); button.innerHTML = `${icon} ${text}`; // 添加图标 button.style.padding = '6px 12px'; button.style.fontSize = '14px'; button.style.cursor = 'pointer'; button.style.border = 'none'; button.style.borderRadius = '5px'; button.style.backgroundColor = bgColor; button.style.color = '#fff'; button.style.transition = 'background-color 0.3s ease, transform 0.2s ease'; // 添加悬停动画 button.addEventListener('mouseenter', () => { button.style.backgroundColor = darkenColor(bgColor, 20); button.style.transform = 'translateY(-2px)'; }); button.addEventListener('mouseleave', () => { button.style.backgroundColor = bgColor; button.style.transform = 'translateY(0)'; }); return button; } // 辅助函数:加深颜色 function darkenColor(hex, percent) { // 移除# hex = hex.replace('#', ''); // 将缩写形式转换为完整形式 if (hex.length === 3) { hex = hex.split('').map(char => char + char).join(''); } const num = parseInt(hex, 16); let r = (num >> 16) - Math.round(255 * (percent / 100)); let g = ((num >> 8) & 0x00FF) - Math.round(255 * (percent / 100)); let b = (num & 0x0000FF) - Math.round(255 * (percent / 100)); r = r < 0 ? 0 : r; g = g < 0 ? 0 : g; b = b < 0 ? 0 : b; return `#${(r << 16 | g << 8 | b).toString(16).padStart(6, '0')}`; } headerContainer.addEventListener('click', () => { content.style.display = content.style.display === 'none' ? 'block' : 'none'; }); panel.appendChild(headerContainer); panel.appendChild(content); return panel; } async function collectAssignmentInfo(data, progressLabel) { let processedCount = 0; for (const itemData of data.items) { try { // 跳转到作业项 await jumpToContentItem(itemData.originalElement); // 等待信息加载并获取作答次数和时间信息 const attemptInfo = await getAssignmentAttemptInfo(); const timeInfo = await getAssignmentTimeInfo(); // 更新面板中的作业项 updateAssignmentItemWithInfo(itemData, attemptInfo, timeInfo); processedCount++; progressLabel.textContent = `已获取:${processedCount}/${data.items.length}`; await new Promise(resolve => setTimeout(resolve, 100)); } catch (error) { console.error('获取作业信息失败:', error); } } } async function getAssignmentAttemptInfo() { return new Promise((resolve, reject) => { const timeout = 3000; const startTime = Date.now(); const interval = setInterval(() => { const attemptElement = document.querySelector('.list-content-text p span'); if (attemptElement) { clearInterval(interval); resolve(attemptElement.textContent.trim()); } if (Date.now() - startTime > timeout) { clearInterval(interval); reject('获取作答次数超时'); } }, 100); }); } async function getAssignmentTimeInfo() { return new Promise((resolve, reject) => { const timeout = 3000; const startTime = Date.now(); const interval = setInterval(() => { const timeElement = Array.from(document.querySelectorAll('.list-content-text p')) .find(p => p.textContent.includes('开始至截止时间:'))?.querySelector('span'); if (timeElement) { clearInterval(interval); resolve(timeElement.textContent.trim()); } if (Date.now() - startTime > timeout) { clearInterval(interval); reject('获取开始至截止时间超时'); } }, 100); }); } function updateAssignmentItemWithInfo(itemData, attemptInfo, timeInfo) { if (itemData.taskNameElement) { const infoContainer = document.createElement('div'); infoContainer.style.display = 'flex'; infoContainer.style.flexDirection = 'column'; infoContainer.style.marginLeft = '10px'; const attemptLabel = document.createElement('span'); attemptLabel.textContent = `作答信息:${attemptInfo}`; attemptLabel.style.color = 'blue'; infoContainer.appendChild(attemptLabel); const timeLabel = document.createElement('span'); timeLabel.textContent = `时间:${timeInfo}`; timeLabel.style.color = 'green'; infoContainer.appendChild(timeLabel); itemData.taskNameElement.parentElement.appendChild(infoContainer); } } async function collectTestAttempts(data, progressLabel) { let processedCount = 0; for (const itemData of data.items) { try { // 跳转到测验项 await jumpToContentItem(itemData.originalElement); // 等待信息加载并获取“已作答”信息和“开始至截止时间” const attemptInfo = await getTestAttemptInfo(); const timeInfo = await getTestTimeInfo(); // 更新面板中的测验项 updateTestItemWithAttemptInfo(itemData, attemptInfo, timeInfo); processedCount++; progressLabel.textContent = `已获取:${processedCount}/${data.items.length}`; // 为了加快速度,可在获取信息后立即返回,不必等待页面完全加载 await new Promise(resolve => setTimeout(resolve, 500)); } catch (error) { console.error('获取测验信息失败:', error); } } } async function getTestTimeInfo() { return new Promise((resolve, reject) => { const timeout = 3000; // 3秒超时 const startTime = Date.now(); const interval = setInterval(() => { // 根据实际页面结构调整选择器 const timeElements = document.querySelectorAll('.list-content-text p'); for (const p of timeElements) { if (p.textContent.includes('开始至截止时间:')) { const span = p.querySelector('span'); if (span) { clearInterval(interval); resolve(span.textContent.trim()); return; } } } if (Date.now() - startTime > timeout) { clearInterval(interval); reject('获取开始至截止时间超时'); } }, 100); }); } async function getTestAttemptInfo() { return new Promise((resolve, reject) => { const timeout = 3000; // 3秒超时 const startTime = Date.now(); const interval = setInterval(() => { // 根据实际页面结构调整选择器 const attemptElements = document.querySelectorAll('.list-content-text p'); for (const p of attemptElements) { if (p.textContent.includes('已作答/可作答次数')) { const span = p.querySelector('span'); if (span) { clearInterval(interval); resolve(span.textContent.trim()); return; } } } if (Date.now() - startTime > timeout) { clearInterval(interval); reject('获取作答信息超时'); } }, 100); }); } function updateTestItemWithAttemptInfo(itemData, attemptInfo, timeInfo) { if (itemData.taskNameElement) { const infoContainer = document.createElement('div'); infoContainer.style.display = 'flex'; infoContainer.style.flexDirection = 'column'; infoContainer.style.marginLeft = '10px'; const attemptLabel = document.createElement('span'); attemptLabel.textContent = `作答信息:${attemptInfo}`; attemptLabel.style.color = 'blue'; infoContainer.appendChild(attemptLabel); const timeLabel = document.createElement('span'); timeLabel.textContent = `时间:${timeInfo}`; timeLabel.style.color = 'green'; infoContainer.appendChild(timeLabel); itemData.taskNameElement.parentElement.appendChild(infoContainer); } } // 设置视频播放速度 function setVideoPlaybackSpeed(speed) { // 将选中的倍速值存储到 localStorage localStorage.setItem('videoPlaybackSpeed', speed); // 将倍速应用到所有视频元素 const videoPlayers = document.querySelectorAll('#dplayer video'); videoPlayers.forEach(video => { video.playbackRate = speed; console.log(`[视频速度调节器] 设置视频播放速度为 ${speed}x`); }); } // 添加拖拽排序功能 function addDragAndDrop(container) { // 引入Sortable库 if (typeof Sortable === 'undefined') { const script = document.createElement('script'); script.src = 'https://cdn.jsdelivr.net/npm/[email protected]/Sortable.min.js'; script.onload = () => { initializeSortable(container); }; document.head.appendChild(script); } else { initializeSortable(container); } } function initializeSortable(container) { const categoryContents = container.querySelectorAll('.category-content'); categoryContents.forEach(content => { new Sortable(content, { animation: 150, ghostClass: 'sortable-ghost' }); }); } // ********** 创建展示面板 ********** function createDisplayPanel() { // 检查是否已经存在展示面板,避免重复创建 if (document.getElementById('custom-display-container')) { console.log('展示面板已存在,跳过创建。'); return; } // 创建展示容器 const displayContainer = document.createElement('div'); displayContainer.id = 'custom-display-container'; displayContainer.style.position = 'fixed'; displayContainer.style.top = '10%'; displayContainer.style.left = '10%'; displayContainer.style.width = '500px'; // 增加宽度以容纳更多内容 displayContainer.style.height = '600px'; displayContainer.style.overflow = 'auto'; // 设置玻璃效果背景 displayContainer.style.background = 'rgba(255, 255, 255, 0.1)'; displayContainer.style.backdropFilter = 'blur(10px)'; displayContainer.style.borderRadius = '15px'; // 增加圆角 displayContainer.style.boxShadow = '0 8px 32px 0 rgba(31, 38, 135, 0.37)'; displayContainer.style.border = '1px solid rgba(255, 255, 255, 0.18)'; displayContainer.style.zIndex = '10000'; displayContainer.style.display = 'block'; displayContainer.style.transform = 'scale(1)'; displayContainer.style.transition = 'transform 0.3s ease, opacity 0.3s ease'; displayContainer.style.opacity = '1'; // 创建面板头部 const panelHeader = document.createElement('div'); panelHeader.className = 'panel-header'; panelHeader.style.display = 'flex'; panelHeader.style.justifyContent = 'space-between'; panelHeader.style.alignItems = 'center'; panelHeader.style.background = 'rgba(0, 0, 0, 0.5)'; // 半透明背景 panelHeader.style.color = '#fff'; panelHeader.style.padding = '15px'; panelHeader.style.cursor = 'move'; panelHeader.style.fontSize = '18px'; panelHeader.style.fontWeight = 'bold'; panelHeader.style.borderTopLeftRadius = '15px'; panelHeader.style.borderTopRightRadius = '15px'; panelHeader.textContent = '📚 反馈群:1006332809 || 本人菜卡了请刷新'; // 添加图标 // 创建按钮容器 const buttonContainer = document.createElement('div'); // 创建最小化按钮 const minimizeButton = document.createElement('button'); minimizeButton.innerHTML = '🗕'; // 最小化图标 minimizeButton.title = '最小化'; minimizeButton.style.background = 'transparent'; minimizeButton.style.border = 'none'; minimizeButton.style.color = '#fff'; minimizeButton.style.fontSize = '20px'; minimizeButton.style.cursor = 'pointer'; minimizeButton.style.marginLeft = '10px'; minimizeButton.style.transition = 'transform 0.2s ease'; // 添加悬停动画 minimizeButton.addEventListener('mouseenter', () => { minimizeButton.style.transform = 'scale(1.2)'; }); minimizeButton.addEventListener('mouseleave', () => { minimizeButton.style.transform = 'scale(1)'; }); // 绑定最小化事件 minimizeButton.addEventListener('click', () => { displayContainer.style.transform = 'scale(0.8)'; displayContainer.style.opacity = '0'; setTimeout(() => { displayContainer.style.display = 'none'; restoreButton.style.display = 'block'; }, 300); // 匹配transition时间 }); buttonContainer.appendChild(minimizeButton); panelHeader.appendChild(buttonContainer); // 创建面板内容容器 const panelContent = document.createElement('div'); panelContent.className = 'panel-content'; panelContent.style.padding = '20px'; panelContent.style.height = '550px'; panelContent.style.overflowY = 'auto'; panelContent.style.fontFamily = "'Segoe UI', Tahoma, Geneva, Verdana, sans-serif"; panelContent.style.color = '#333'; // 将头部和内容添加到展示容器 displayContainer.appendChild(panelHeader); displayContainer.appendChild(panelContent); // 将展示容器添加到页面 document.body.appendChild(displayContainer); // 创建恢复按钮(最小化后显示) const restoreButton = document.createElement('button'); restoreButton.id = 'restore-button'; restoreButton.innerHTML = '📖 课程内容分类'; restoreButton.style.position = 'fixed'; restoreButton.style.bottom = '20px'; restoreButton.style.left = '20px'; restoreButton.style.zIndex = '10000'; restoreButton.style.padding = '10px 20px'; restoreButton.style.backgroundColor = 'rgba(0, 123, 255, 0.8)'; restoreButton.style.color = '#fff'; restoreButton.style.border = 'none'; restoreButton.style.borderRadius = '8px'; restoreButton.style.cursor = 'pointer'; restoreButton.style.boxShadow = '0 4px 6px rgba(0,0,0,0.1)'; restoreButton.style.display = 'none'; restoreButton.style.transition = 'opacity 0.3s ease, transform 0.3s ease'; restoreButton.style.opacity = '1'; // 添加悬停动画 restoreButton.addEventListener('mouseenter', () => { restoreButton.style.transform = 'scale(1.05)'; restoreButton.style.opacity = '0.9'; }); restoreButton.addEventListener('mouseleave', () => { restoreButton.style.transform = 'scale(1)'; restoreButton.style.opacity = '1'; }); restoreButton.addEventListener('click', () => { displayContainer.style.display = 'block'; displayContainer.style.transform = 'scale(1)'; displayContainer.style.opacity = '1'; restoreButton.style.display = 'none'; }); document.body.appendChild(restoreButton); // 添加拖拽功能 makeElementDraggable(displayContainer); } // 使元素可拖动,并限制在视口内 function makeElementDraggable(elmnt) { let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0; const header = elmnt.querySelector(".panel-header"); if (header) { // 在标题栏上触发拖动 header.style.cursor = 'move'; header.onmousedown = dragMouseDown; } else { // 否则,在元素内部任意位置触发拖动 elmnt.onmousedown = dragMouseDown; } function dragMouseDown(e) { e = e || window.event; e.preventDefault(); // 获取鼠标初始位置 pos3 = e.clientX; pos4 = e.clientY; document.onmouseup = closeDragElement; // 当鼠标移动时调用的函数 document.onmousemove = elementDrag; } function elementDrag(e) { e = e || window.event; e.preventDefault(); // 计算鼠标移动后的位置 pos1 = pos3 - e.clientX; pos2 = pos4 - e.clientY; pos3 = e.clientX; pos4 = e.clientY; // 设置元素的新位置 let newTop = elmnt.offsetTop - pos2; let newLeft = elmnt.offsetLeft - pos1; // 获取窗口尺寸 const windowWidth = window.innerWidth; const windowHeight = window.innerHeight; // 获取面板尺寸 const panelWidth = elmnt.offsetWidth; const panelHeight = elmnt.offsetHeight; // 限制面板在视口内 if (newTop < 0) newTop = 0; if (newLeft < 0) newLeft = 0; if (newTop + panelHeight > windowHeight) newTop = windowHeight - panelHeight; if (newLeft + panelWidth > windowWidth) newLeft = windowWidth - panelWidth; elmnt.style.top = newTop + "px"; elmnt.style.left = newLeft + "px"; } function closeDragElement() { // 当鼠标松开时,停止移动 document.onmouseup = null; document.onmousemove = null; } } // 添加自定义样式 const style = document.createElement('style'); style.textContent = ` .category-panel { box-shadow: 0 2px 5px rgba(0,0,0,0.1); } .category-header { font-weight: bold; font-size: 16px; } .sortable-ghost { opacity: 0.4; } /* 隐藏滚动条,但可以滚动 */ #custom-display-container::-webkit-scrollbar { width: 8px; } #custom-display-container::-webkit-scrollbar-track { background: rgba(255, 255, 255, 0.1); border-radius: 4px; } #custom-display-container::-webkit-scrollbar-thumb { background: rgba(0, 123, 255, 0.5); border-radius: 4px; } /* 调整恢复按钮的样式 */ #restore-button:hover { background-color: rgba(0, 123, 255, 0.9); transform: scale(1.05); } /* 调整最小化按钮的样式 */ .panel-header button:hover { background-color: rgba(255, 255, 255, 0.3); } /* 任务项样式 */ .task-item { display: flex; align-items: center; justify-content: space-between; padding: 8px 0; border-bottom: 1px solid rgba(0, 0, 0, 0.05); } .task-item:last-child { border-bottom: none; } /* 跳转按钮样式 */ .category-panel button { background-color: #007bff; color: #fff; border: none; border-radius: 5px; padding: 5px 10px; cursor: pointer; transition: background-color 0.3s ease, transform 0.2s ease; } .category-panel button:hover { background-color: #0056b3; transform: translateY(-2px); } /* 动态渐变动画 */ @keyframes gradientAnimation { 0% { background-position: 0% 50%; } 50% { background-position: 100% 50%; } 100% { background-position: 0% 50%; } } /* 玻璃效果 */ #custom-display-container { background: rgba(255, 255, 255, 0.1); backdrop-filter: blur(10px); -webkit-backdrop-filter: blur(10px); border: 1px solid rgba(255, 255, 255, 0.2); } `; document.head.appendChild(style); // ******************** 辅助函数 ******************** function showNotification(message) { const notification = document.createElement('div'); notification.textContent = message; notification.style.position = 'fixed'; notification.style.bottom = '20px'; notification.style.right = '20px'; notification.style.backgroundColor = '#4caf50'; notification.style.color = 'white'; notification.style.padding = '10px 20px'; notification.style.borderRadius = '4px'; notification.style.boxShadow = '0 2px 4px rgba(0,0,0,0.2)'; notification.style.zIndex = '10000'; notification.style.fontSize = '14px'; document.body.appendChild(notification); setTimeout(() => notification.remove(), 3000); } // 在全局作用域定义 function performAutoReply(element) { setTimeout(async () => { const discussionArea = await waitForElement('.course-courseQaDiscussion-qa', 5000); if (!discussionArea) return; const replyButton = discussionArea.querySelector('.conv-option .reply'); if (!replyButton) return; replyButton.click(); const waitForControls = setInterval(() => { const replyInput = document.querySelector('.course-courseQaDiscussion-reply textarea.ant-input'); const submitButton = document.querySelector('.course-courseQaDiscussion-reply .ant-btn-primary'); const firstReply = discussionArea.querySelector('.conv-subtitle'); if (replyInput && submitButton && firstReply) { clearInterval(waitForControls); replyInput.value = firstReply.textContent.trim(); replyInput.dispatchEvent(new Event('input', { bubbles: true })); setTimeout(() => { submitButton.click(); showNotification('自动回复已提交'); }, 1000); } }, 500); }, 2000); } // 等待元素出现的辅助函数 /* function waitForElement(selector, timeout) { return new Promise(resolve => { const startTime = Date.now(); const interval = setInterval(() => { const element = document.querySelector(selector); if (element) { clearInterval(interval); resolve(element); } else if (Date.now() - startTime > timeout) { clearInterval(interval); resolve(null); } }, 100); }); } */ // 等待页面加载完成或动态内容加载完成 function waitForContentLoaded(callback) { let maxRetries = 40; // 延长重试次数以适应更慢的加载 const interval = setInterval(() => { const contentItems = document.querySelectorAll(itemSelector); console.log(`检测到的内容项数量:${contentItems.length}`); if (contentItems.length > 0 || maxRetries <= 0) { clearInterval(interval); callback(); } maxRetries--; }, 500); } // 添加页面可见性检测 document.addEventListener('visibilitychange', () => { if (document.hidden) { console.log('[页面状态] 页面隐藏,暂停任务处理'); resetTaskState(); } else { console.log('[页面状态] 页面可见,继续任务处理'); processQueue(); } }); // 添加页面卸载事件监听 window.addEventListener('beforeunload', () => { console.log('[页面状态] 页面即将卸载,重置任务状态'); resetTaskState(); }); } function autoPlayVideos(videoPlayer) { // 尝试找到视频元素 const video = videoPlayer.querySelector('video'); if (video) { // 静音视频以绕过浏览器自动播放限制 video.muted = true; // 确保视频准备就绪 if (video.readyState >= 2) { // HAVE_CURRENT_DATA playVideo(video); } else { // 等待视频元数据加载完毕 video.addEventListener('loadedmetadata', () => { playVideo(video); }); } } else { console.log('[视频自动播放] 未找到video元素。'); const statusElement = document.getElementById('video-status'); if (statusElement) { statusElement.textContent = '状态: 未找到video元素'; } } // 检查用户是否手动暂停 video.addEventListener('pause', () => { console.log('[视频自动播放] 用户暂停了视频,暂停自动任务'); resetTaskState(); }); // 检查用户是否更改了视频进度 video.addEventListener('seeked', () => { console.log('[视频自动播放] 用户更改了视频进度,暂停自动任务'); resetTaskState(); }); } // 初始化视频自动播放与进度监控功能 function initVideoAutoPlayAndMonitor() { // 创建视频进度显示面板 createVideoProgressPanel(); // 使用 MutationObserver 持续监听视频播放器的添加 setupVideoMutationObserver(); } function createVideoProgressPanel() { // 检查是否已经存在视频进度面板,避免重复创建 if (document.getElementById('video-progress-panel')) return; // 创建展示容器 const videoPanel = document.createElement('div'); videoPanel.id = 'video-progress-panel'; videoPanel.style.position = 'fixed'; videoPanel.style.bottom = '20px'; videoPanel.style.right = '20px'; videoPanel.style.width = '250px'; videoPanel.style.padding = '10px'; videoPanel.style.backgroundColor = 'rgba(0, 123, 255, 0.9)'; videoPanel.style.color = '#fff'; videoPanel.style.borderRadius = '8px'; videoPanel.style.boxShadow = '0 2px 8px rgba(0,0,0,0.2)'; videoPanel.style.zIndex = '10001'; videoPanel.style.fontFamily = 'Arial, sans-serif'; videoPanel.style.fontSize = '14px'; videoPanel.style.maxHeight = '150px'; videoPanel.style.overflowY = 'auto'; videoPanel.innerHTML = ` <h4 style="margin-top: 0;">视频自动播放与进度监控</h4> <p id="video-status">状态: 未检测</p> <p id="video-progress">进度: 0%</p> `; document.body.appendChild(videoPanel); } function setupVideoMutationObserver() { // 防止重复初始化观察器 if (window._videoObserverInitialized) return; window._videoObserverInitialized = true; const observer = new MutationObserver((mutations) => { mutations.forEach((mutation) => { mutation.addedNodes.forEach((node) => { if (node.nodeType === 1) { // ELEMENT_NODE const videoPlayer = node.id === 'dplayer' ? node : node.querySelector('#dplayer'); if (videoPlayer && !videoPlayer.dataset.autoplayInitialized) { console.log('[视频自动播放] 检测到新的视频播放器'); // 确保当前没有其他视频在播放 if (currentPlayingVideo) { currentPlayingVideo.pause(); if (currentPlayingVideo.updateProgress) { currentPlayingVideo.removeEventListener('timeupdate', currentPlayingVideo.updateProgress); } if (currentPlayingVideo.endedHandler) { currentPlayingVideo.removeEventListener('ended', currentPlayingVideo.endedHandler); } currentPlayingVideo = null; } videoPlayer.dataset.autoplayInitialized = 'true'; autoPlayVideos(videoPlayer); monitorVideoProgress(videoPlayer); } } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); // 检查现有视频播放器 const existingVideoPlayer = document.querySelector('#dplayer'); if (existingVideoPlayer && !existingVideoPlayer.dataset.autoplayInitialized) { existingVideoPlayer.dataset.autoplayInitialized = 'true'; autoPlayVideos(existingVideoPlayer); monitorVideoProgress(existingVideoPlayer); } } // 播放视频并监控进度 function playVideo(video) { // 先移除所有已存在的事件监听器 if (video.updateProgress) { video.removeEventListener('timeupdate', video.updateProgress); } if (video.endedHandler) { video.removeEventListener('ended', video.endedHandler); } // 如果有正在播放的其他视频,先停止它 if (currentPlayingVideo && currentPlayingVideo !== video) { if (currentPlayingVideo.updateProgress) { currentPlayingVideo.removeEventListener('timeupdate', currentPlayingVideo.updateProgress); } if (currentPlayingVideo.endedHandler) { currentPlayingVideo.removeEventListener('ended', currentPlayingVideo.endedHandler); } currentPlayingVideo.pause(); } // 设置当前播放的视频 currentPlayingVideo = video; // 应用保存的倍速值 const storedSpeed = parseFloat(localStorage.getItem('videoPlaybackSpeed')) || 1; video.playbackRate = storedSpeed; // 修改更新进度的函数 function updateProgress() { if (!video.duration || isNaN(video.duration)) return; const progress = (video.currentTime / video.duration) * 100; const progressElement = document.getElementById('video-progress'); if (progressElement) { progressElement.textContent = `进度: ${progress.toFixed(2)}%`; } // 在视频完成时的处理 if (progress >= 99.9) { console.log('[视频进度监控] 视频已完成播放。'); const statusElement = document.getElementById('video-status'); if (statusElement) { statusElement.textContent = '状态: 视频已完成'; } // 标记任务为完成 const parentTaskElement = findParentTaskElement(video); if (parentTaskElement) { parentTaskElement.dataset.taskCompleted = 'true'; markCoursewareAsCompleted(parentTaskElement); updateCategoryPanelAfterCompletion(parentTaskElement); } // 清理事件监听器和播放状态 video.removeEventListener('timeupdate', updateProgress); video.removeEventListener('ended', endedHandler); currentPlayingVideo = null; // 重要:处理队列中的下一个任务 setTimeout(() => { isProcessing = false; processQueue(); }, 2000); } } // 定义视频结束的处理函数 function endedHandler() { console.log('[视频自动播放] 视频播放结束。'); video.removeEventListener('timeupdate', updateProgress); video.removeEventListener('ended', endedHandler); currentPlayingVideo = null; } // 存储函数引用以便后续移除 video.updateProgress = updateProgress; video.endedHandler = endedHandler; // 添加事件监听器 video.addEventListener('timeupdate', updateProgress); video.addEventListener('ended', endedHandler); // 开始播放 video.play().then(() => { console.log('[视频自动播放] 视频开始播放'); const statusElement = document.getElementById('video-status'); if (statusElement) { statusElement.textContent = '状态: 正在播放'; } }).catch(err => { console.warn('[视频自动播放] 播放失败:', err); const statusElement = document.getElementById('video-status'); if (statusElement) { statusElement.textContent = '状态: 播放失败'; } }); } // 寻找视频所属的任务元素 function findParentTaskElement(video) { let parent = video.parentElement; while (parent && parent !== document.body) { if (parent.classList.contains('third-level-inner-box')) { return parent; } parent = parent.parentElement; } return null; } // 更新分类面板中的“课件”统计 function updateCategoryPanelAfterCompletion(coursewareElement) { const panelContent = document.querySelector('#custom-display-container .panel-content'); if (!panelContent) return; const categories = panelContent.querySelectorAll('.category-panel'); categories.forEach(panel => { const header = panel.querySelector('.panel-header div'); if (header && header.textContent.startsWith('课件')) { const completedMatch = header.textContent.match(/已完成: (\d+)\/(\d+)/); if (completedMatch) { let completed = parseInt(completedMatch[1]); let total = parseInt(completedMatch[2]); let halfCompletedMatch = header.textContent.match(/半完成: (\d+)/); let halfCompleted = halfCompletedMatch ? parseInt(halfCompletedMatch[1]) : 0; // 根据当前课件的状态调整统计 if (coursewareElement.dataset.pptCompleted === 'true') { completed += 1; } else { halfCompleted += 1; } header.textContent = `课件 (已完成: ${completed}/${total}, 半完成: ${halfCompleted})`; } } }); } function updateTaskItemStatus(panel, coursewareElement) { const taskItems = panel.querySelectorAll('.task-item'); const targetTitle = coursewareElement.querySelector('p.title')?.textContent.trim(); taskItems.forEach(item => { const itemTitle = item.querySelector('span')?.textContent.trim(); if (itemTitle === targetTitle) { const statusIcon = item.querySelector('img.file-complete'); if (statusIcon) { statusIcon.src = completionStatuses['已完成']; } } }); } function monitorVideoProgress(videoPlayer) { const video = videoPlayer.querySelector('video'); if (!video) { console.log('[视频进度监控] 未找到video元素。'); const progressElement = document.getElementById('video-progress'); if (progressElement) { progressElement.textContent = '进度: 未检测到视频元素'; } return; } // 定义一个函数来更新进度 const updateProgress = () => { if (video.duration > 0) { const progress = (video.currentTime / video.duration) * 100; const progressElement = document.getElementById('video-progress'); if (progressElement) { progressElement.textContent = `进度: ${progress.toFixed(2)}%`; } console.log(`[视频进度监控] 视频进度:${progress.toFixed(2)}%`); // 如果进度达到100%,更新状态 if (progress >= 100) { console.log('[视频进度监控] 视频已完成播放。'); const statusElement = document.getElementById('video-status'); const progressEl = document.getElementById('video-progress'); if (statusElement) { statusElement.textContent = '状态: 视频已完成'; } if (progressEl) { progressEl.textContent = '进度: 100%'; } // 标记任务为完成,防止持续提示“任务尚未完成” const parentTaskElement = findParentTaskElement(video); if (parentTaskElement) { parentTaskElement.dataset.taskCompleted = 'true'; updateCategoryPanelAfterCompletion(parentTaskElement); } // 移除事件监听器 video.removeEventListener('timeupdate', updateProgress); } } else { console.log('[视频进度监控] 无法获取视频时长。'); } }; // 使用事件监听器实时监控进度 video.addEventListener('timeupdate', updateProgress); } // 初始化PPT自动检测与翻页功能 function initPptAutoPaging() { const progressBarSelector = '.bottom-paging-progress .bar'; const nextPageButtonSelector = '.slide-img-container.context-menu-disabled .ppt-turn-right-mask'; const checkInterval = 1000; let pptIntervalId = null; let hasReportedCompletion = false; // 添加标记,避免重复报告完成状态 // 添加模拟点击事件的函数 function simulateClick(element) { if (!element) return; try { // 创建鼠标事件 const mousedown = new MouseEvent('mousedown', { view: window, bubbles: true, cancelable: true }); const mouseup = new MouseEvent('mouseup', { view: window, bubbles: true, cancelable: true }); const click = new MouseEvent('click', { view: window, bubbles: true, cancelable: true }); // 按顺序触发事件 element.dispatchEvent(mousedown); element.dispatchEvent(mouseup); element.dispatchEvent(click); console.log('[PPT 自动检测] 成功触发点击事件'); } catch (error) { console.error('[PPT 自动检测] 触发点击事件失败:', error); } } function checkProgressAndAct() { try { const pptBar = document.querySelector(progressBarSelector); const nextButton = document.querySelector(nextPageButtonSelector); if (pptBar) { let width = parseFloat(pptBar.style.width); if (isNaN(width)) { const widthStyle = pptBar.style.width; const match = widthStyle.match(/(\d+(\.\d+)?)%/); if (match) { width = parseFloat(match[1]); } } if (!isNaN(width)) { console.log(`[PPT 自动检测] 检测到 PPT 进度:${width}%`); if (width >= 100 && !hasReportedCompletion) { console.log('[PPT 自动检测] PPT已完成'); hasReportedCompletion = true; if (pptIntervalId) { clearInterval(pptIntervalId); pptIntervalId = null; } // 确保消息只发送一次 console.log('[PPT 自动检测] PPT已完成,发送消息到父页面'); window.parent.postMessage({ type: 'pptCompleted', status: 'completed', timestamp: Date.now() }, '*'); return; } // 添加更多的调试信息 if (width < 100) { if (nextButton) { console.log('[PPT 自动检测] 尝试点击下一页按钮'); simulateClick(nextButton); } else { console.log('[PPT 自动检测] 未找到下一页按钮'); } } } } else { console.log('[PPT 自动检测] 未找到进度条'); } // 重置超时计时器 clearTimeout(pptTimeoutId); pptTimeoutId = setTimeout(() => { console.log('[PPT 自动检测] 60秒内未检测到进度条,将当前任务标记为完成'); hasReportedCompletion = true; if (pptIntervalId) { clearInterval(pptIntervalId); pptIntervalId = null; } // 发送消息通知主页面任务完成 window.parent.postMessage({ type: 'pptCompleted', status: 'completed', timestamp: Date.now() }, '*'); // 处理下一个任务 isProcessing = false; processQueue(); }, 60000); // 60秒超时 } catch (error) { console.error('[PPT 自动检测] 检查过程出错:', error); } } // 初始化PPT检测 function init() { console.log('[PPT 自动检测] 开始初始化...'); // 重置状态 hasReportedCompletion = false; // 设置定时检查 if (!pptIntervalId) { pptIntervalId = setInterval(checkProgressAndAct, checkInterval); console.log('[PPT 自动检测] 已设置自动检查定时器'); } // 立即执行一次检查 checkProgressAndAct(); clearTimeout(pptTimeoutId); } // 开始执行 init(); // 添加清理函数 return function cleanup() { if (pptIntervalId) { clearInterval(pptIntervalId); pptIntervalId = null; console.log('[PPT 自动检测] 清理完成'); } }; } })(); /**********************************************/ (function() { 'use strict'; // 确保脚本只运行一次 if (window.asciiThreeInitialized) return; window.asciiThreeInitialized = true; // ASCII 艺术内容(请替换为您的ASCII艺术) const asciiArt = ` .......... ...... ..... ............................:::::::..::......:::::::::::::::::::::::::::::::::::::-::::::::::::::::::::::::::::::::::::::::::::::::::::::+=+++=:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::....:::::::::::+=+ .......... ..... ... ............................................::::::::::::::::::::::::::::::::::::::--::::::::::::::::::::::::::::::::::::::::::::::::::::-=+-+-::::::::::::::::--:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::+ ............ ............. .. ................::..........:::::::::..::::::::::::::::::::::::::::::::::::::::---::::::::::::::::::::::::::::::::::::::::::::::::::::+#*=::::::::::::::::*#+:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::+ .............................. .. ................::::........:::::::::::::::::::::::::::::::::::::::::::::::::::::--::::::::::::::::::::::::::::::::::::::::::::::=+-:=-+#*:::::::::::::::*#@*+::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::: ................................. ................:::.............:::::::::::::::::::::::::::::::::::::::::::::::::---------------:::::::::::::::::::::::::::::::-+#*+=-*=#+-::::::::::::::-##%+:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::-##+:::: ................................... .............. ..................................:::::::::.:::::::::::::::::::::::::::::::::::------------------------::::::---::::::::::::::-+****=--:#==:==:::::::::::=*#::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::-+#*::: ............................................ .. ............................::::::::..:::::::::::::::::::::::::::::::::-------------------------:::::::-*##=:::::::::::::-##%#*-==#:=-#=:+:::::::::=*-:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::--#*-: ................................................... ................................::::::....:::::::::::::::::::::::::::::---------------------------::::::::+##=-::::::::++-:++##+--=+*=-**=+-:::-+-:::*-:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::=#%#= ..........................................................................................:.........:::::::::::::::::::::::::::::----------------------------:::-:--*+=*::::::+=:=*=+#%%#*#=**==*++:*=:::-=-:**::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::#*+::::::::::::::::::::=#%% :....................................::.........................................................................::::::::::::::::::::::-:::-----------------:::::::::-++**-:::::+-:-%*#%%++**+*:++##*-:::::+-##*:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::=+=*:::::::::::::::::::::**# ::::......:::::::::....::::::........::........................................................... ...............:::::::::::::::::::::::::::::::::::::::::::::::----=##*=::::-+:::**###+-::+*=++*-:::::=:::#%=::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::+##=:::::::::::::::::::::*= :::::::::::::::::::::::::::.........................................................................................:::::::::::::::::::::::::::::::::::::::::::::::--=-#%*::::=-=++#%%%%+:::-**-=+*---++=:::#+-::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::-:-::%-::::::::::::::+=-+:: ::::::::::::::::::::::::::::.................::........................:::...::...........:.............................:::::::::::::::::::::::::::::::::::::::::::::::*%#+::::+::-+%%##%*#=-**::++:.-%=::++#+:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::+=++%+*%#.:::::::::::::::=+%%%# :::::::::::::::::::::::::::::::::....::.::::::::..............................................................................:::::::::::::::::::::::::::::::::::::::::++**::+-*+=:-**#+###::*:-:=+-=*%+=-#%-:::::::::::::::::::-=:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::#%=*%%::::::::::::::::::=%% ::::::::::::::::::::::::::::::::::::::::::::::::::::::::.................................................::......................::::::::::::::::::::::::::::::::::::::::*#-=--+=-:****###+::*::=#%%##*#++*%*-:::::::::::::::::=*-:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::++::::+=::::::::::::::-*# :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::.......................................:::::.........................::::::::::::::::::::::::::::::::+-::=-=#*-=::=+===##+#%=:*::=*#*+#-=#%%%*-:::::::::::::::-++-::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::--:::::::::::::::::::::::::::::::-+=:-*-:::::::::::.::+*= ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::.....................................::::::.............................:::::::::::::::::::::::::::=*+==**-*#*+*-==-:-##=+*::*==+-=*:+#**#*%#-::::::::::::::::+*+=::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::-::::::::::::::::::::::::::::::::::*+:-*-::::::::::=*=-+*# :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::.......................................................................::::::..::::::::::-=:::::::=+==+*-=*#=++::=+*==+#*#-:*=-=+*#=#%#%##%%*::::::::::::::::--:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::--:::-:::::::::::::::::::::::::::::*%*##+-:::::::::=+#%#*#% :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::.........................................................................:......:::::::-+-::::::::-=-*-:*++=::::-=+++*=**:*-%*#%#*%#-+#%##*-*#-::::::::::=-*=--:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::--::-:::::::::::::::::::::::::::::-:+%##-:::::::::::==%%%%% ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::..............................................................:::::::...:..::::::::::::#*+**-:::::==#+++###+::::::=-+-*++*=+*#*#--*==###%**+:::::::::::-##=-++:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::=+::+:-::::::::-::::::::::=--::::::***%%#%=:::::::::::::.:*%%%@ ...:::...:.::::::::::::::::::::::::::::::::::::::::::::::::::::::.....................................................:::::::::::::::::::::::::::::::::::::-##%+::::::-+--:-+:++-::=*-+=++++*%+-+##%#++=+%###::-++::::::::===#+#+::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::---==-::-::::-=:::::::::::-*#=:::::+*+#%**%*+-::::::::.::=-*#%% ..............:::::::::::::::::::::::::::::::::::::::::::::::::.....................................................:::::::::::::::::::::::::::::::::::::===+*+-:::+=-:+**=:::=*=+++::=:+#==:#-+=+###+##%%%#:-+=::::::::::==+#***:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::=::=:::::-=-:::::::::::::=:=-:::::::=*%#*#%%=::::::::.::..-=## ............................:::::::::::::::::::::::::::::::::::...................................................::::::::::::::::::::::::::::::::::::::::=*=-=*+:::--=+=#=::::=%%*=:+++-**#+#=.=*#%*-=*#####=+::::::::::::=#*=::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::--:::::---=:::----:::::::::::::::##*::::::==-+##%%%#::::::::.:.:..::: .............................:::::::::::::::::::::::::::::::::..................................................:::::::::::::::::::::::::::::::::::::::::::-*##+-:::=#:::=::::::*#+::=+--:+#*#+:.*#%%+#%#+-**=:::-:::::::::***=::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::-:::::::-:::::=:=:----:::::::::::::::::::=+-::::##+++*#%%*::::::=-**==+*+=- ................................:::::::::::::::::::::::::::::......................................................:::::::::::::::::::::::::::::::::::+-:::==*%#+=:*##+::*+::::-=+-+=:-:++*=*#+**%+:#=%*++**--*=*+::::::::*-::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::-=:::-::-+-:::::::::=::-:===:::=-::::::-:::::::=:-*--+:++::-=-+++##-:::::-:=-.:*+*## ...................................:::::::::::::::::::::::............ .. . ............. .............::::::::::::::::::::::::::::::::::-+::::#%%*+:=*#*+-:#*-.-#-.=-:-----=**#*-+=*-=#*#**#*+#*+++:::::::-*#=:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::-=-:::::-:-:::::::::::=:*:::::=:::::=:::::::--:::-#%+=*:.::::::=%**#:.:.:::::::.*+# ::::...:::::::::......................:::::::::::::::........................ ...................... .............:::::::::::::::::::::::::::::::::::#=-::=+%##*##::++*%+=+:.::.*..=*+:+##-#**=-.:#%*#%*=+*##.:::::::-**=:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::--+=::::::=-:::::::::-:+=::::=*=:-::::::::=+:::::+*%-::::::::::=+%%##:.:::::::.-#: :::::::::::::::::::::...................:::::::::::::..............................................................:::::::::::::::::::::::::::::::::::::+#-:-*%##%*+*::::+*+=::.-##%*-*#+.:+*#+:=-.:##%#+=%=::::::::::::-##::.:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::-::::::::==::::::::=+:+:=#=-+-::::::::=::::::::**=.::::::::-=*:##%=.::::::::::: ::::::::::::::::::::::::..............:::::::::::::::..:..........................................................:::::::::::::::::::::::::::::::::::::::#*:::###+*--::::::#+:--=#-+-::#+:.+-%%#*..:=**=**==#::::::.:.=+#+::....::.::..::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::-::::::::::+::-::::::-:::::::=+.:-=+=*--==:::::+-:::::::::#=::==-::-=*=*:*%#%+:::::::::.= :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::.......................................:::::::::::::::::::::::::::::::::::::::::::+##---=+=:::::::::-*=+####++:=%*+=--*-***=.***=*++*=:::.:..:+*+:...::::::::::..:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::=-::::::::::=--:::::::--:::=--*:-::+---:-::::-=:::::--:::+#%:*:#==####::::=*+*:::::::::=: ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::........::::::::..::::::::::::::::::::::::::::::=*==-:-=::::::::::--+---=##*=#=+-.:#:.-.+*#=:++:.:.:.+*+..+*-=-..+#+.:.:...........:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::=:::::::::::---::-:--::------*=-::=+*-::::-+-::::::::::=++#*++*#%*-:::-:::=#%:::=+*::::: :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::..........::::......::::::::::::::::::::::::::::-*+=+==-:::::::::=--::::-==-+::+-:#.-=:-##=*+:.....-#%**+::+:**++..:............::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::=-:::::::::::--==:==-::-::::+::===#---=-:==:::::::::-+-.:=-=#*+--:=-:::-+-*=:::#+-::-+= ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::..........::::::.:::::::::::::::::::::::::::::::-=+=:+::::::::::=:::::::+%+=+:=*+#-.-:+*#=-+-......*%#*-=-*+%%+*+...............::..::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::-:-:::--:::::--:-*=-=:-::::*-:::=#*:=--+-:::::::::==:::::=-+=:::+=#**-::-*#-:+##-:::=- :::::::::::::.....:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::...::.........::::::::::::::::::::::::::::::::::::==*-:::::::::-=::::.:=#=:*+---#:=*-##*--=--+**##*#*####*+%#*:......................:::::::........::::::::::::::::::::::::::::::::::::::::::::::::::::::::::+=:::::-=-=:::--:++=+*=:==*-::-*--==--::::::::::-+=::::::*##::::=+++++-.:=+===#-:::.: ::::::::::::..::.......:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::.........:::::::::::::::......::::::::::::::+-::::=::::::::::+:::::::*#:*--=*#*#**%+*::##**##-+:+#=+*+.:=++*:......-*-.=:..........................::::::::::::::::::::::::::::::::::::::::::::::---=:-*:::--=::::---=*-::=+-=+=*+:=-+=:-*+=-:=--::::::::::+-:::---+==**::-:--:++*--:=:+=+=.:..: :::::::::::::::::.............:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::..:::::::::::::::::::..............::::::.*#%*-+:=::::::::*:=--++=--##-=*+#==+#**%++-:.:-*=::##=.*+=:=+:+..-....**=+#:..........................::::::::::::::::::::::::::::::::::::::::::::::-+-=+**=+:::--:::::::====--+*+:-=-:=*-=+=*:===-::::::--::-::::::+-:::+-.-=:-::=:-+=+*%%#+-:::.: ...:::::::::::......:......:..:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::...:...............:++=:=++#%**=#**::::=+-::::::*==##+=#%##*#==+**#=::-=+#%+=-*:.+=+=+==*+*:..*#=-..............................:::::::::::::::::::::::::::::::::::::::::::::-+-+++--:::=+++-:::-:--::==:-+#+**##**-:*-::::::::::==#*-.::::+-.::.=%%***-=-:-=:.=**%%*+:::.: :::::.::::::::::::::::::::..::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::...--:.......::.:::::::++==*-=-*:.::::*-+--:::.:::::-*:=+%**%:-*=-*=+=---=*#.-#-:.:#+:::-=*:..-#-+-*..............................::::::::::::::::::::::::::::::::::::::::::::::=-=--:=:--::++--==-=-::=--=+=**+*#:==:*-:.::..::.:===-+#*::-=:...:++##%=:=:..-:#*#*#%%+::-%+ ::::::::::::::::::::::::::::.:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::+-:::::.:::::::::::::::-####::.::::.-=++++====--+##+##=%:=+*:.*::..:-=+*-+..-***#*#+::.....#+#=:............................:::::::::::::::::::::::::::::::::::::::::::::::::-===-:-:::=:=+=--===::-=:.:-==:+*:::-:-*=....:..-=...+#=-+::....:::+#-*:.....*#%######+:*=: :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::**+:::::::::::::::::::::+:=#:::::::::+::::::::::+=%%%#+=##*::+:==:-*+:-+-=-:#%%%+.=:....:**=-............:::::::..::::.....:.................::::::::::::::::::::::::::::::::--::=:::::-.=+::::==::=*+==+:=#*...-=::....:.:+:.....=###:..::.:#=*+***:..:.:+.##=:+#%*--. ::::::::::::::::::::::::::.:::::::..........:::::::::::::::......::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::=%%++-:-::::::::::::::::=#+=+::+**=::-+:::.:.::.-+-*%-+.:*==#%%%%*#*=*#%++:.-+-.::=.....:#*--:........:::::::::::....................................:::::::::::::::::::-::::-+-.:+:...::=:+==::-=-..:-++=*-=::=+-:-:::*+=--:..:*#+*:=*%:..:+=%=*+#%**-=+*:=:=#+-#%%%++ ::::::::::::::::::-=:::::::-:::::::............:::::::::::::::........:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::-:=*#+-=:::::::::::::::::+---=#%--*:::=:::...:-*-#:+%--.:+.:+-=:::*=+**.::=+.-:=#=-*%=...=::::......:::.....:::::.:...................................:::.....:::::::::::::::::+**:=....:-=+=**+==-..-===::==--=:....:==.-.....+#-*++=*%+:.::=-.#*#+#=-=-#**#%#-.-=%#%+ ::::::::::::-::-:::-::::::-:::::::::......................::::::.........::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::+%%%=+:==+-:::::::::::::==:+-.::::=+-#::..:=::.#:+%++===..=.+++=+#%%*--=.:+*%++*++:=*-=#*:::::::::::...::::::::::.................................:..................:::::::::*+.:+-:.:=-=:.-.:-==::-::=+++-=-:-:--+:.......*+.:=:..:=+.:==...::*#%=-++.:-+*#*:.:##%- ::::::::::::=-:::-:--:::::::::::::::::::::::::::.............::.::::......:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::=-*#*:::=-::::::::::::---.+#+...::--+:..:.:.:###%#-.===:+*-*=*=-#+=*+===-++.:.=-::*=#+=-::::::::::::::::::::::::...........................::....::........................:-+=:+#-:.----.--=:..+=...*=+---.:=--........:=-:-:.....:==+=-=:....:+%==-:-=:.=*#=+#+** ::::::::::::-=+::::--::::-::::::::::::::::::::::::::::::...::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::===*+*-.:=:::::::.:::::-=..*:.::.:::+-::......++%*=+#-..+....--*-###-.==:..:..:-*=+#*=::::::::::::::::::::::::.............................:..................................-+=:*=:-::-===::*--::-=*+#*+-:.........-*%=:=#+....-+#**=*-=+*=-...=*===*--::=%%#*=++ :::::::=:::::-=*-::-=:::-::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::==#*#-*=:=+-:-=--::::::.--::+-:..==::*:::.....**%+..#.-.#=+-==##*#:..::=:..=:--=:-++:::::::::::::::::::::::::.................................:::.............:................-=-:*=::::--*++-==::::-*%+-==-:....::-%=.....=#.:-=+*+-=#*#%+==:...-*=::-==+**+*=#+= ::::::-:=::::=:-=:::-::-::=-:::::::::::::::::::::::::::::..::::::::::::::::::::::::::::::::::::::::.::::::::::::::::::::::::::::::::::::::::::::=*#**:-++++=:::::::::-*#*+*=:++=::==:......+%%+.+*=-=+=-:=*-*#+::.:+.-+-=-+*+*++-:::.::::::::::::::::::::::..................................:............:=:................-++**=-::---+=-.:+:--:=#:......-=-+*#=.......+%:+#*:+*:.:#%+-..:==+%#=.....:**#%%%* ::::::=::=::::::::--*-=::-:::::::::::::::::::::::::::::::.........::::::::::::::::::::::::::::::::...::.....:::::::::::::::::::::::::::::::::::::=*###+-***+*:::::::--:-.::+-..::.:=-:...--=%#%:+*++#:.=++.:#**#%-=-=::....-=+=-::::::::::::::::::::::::::::::::::.....................................:---=-................:.=+:=-::.-=::.:::+...+#-:--..---=-:%:......-:%--#*#=.....*@::+#+*%%%##=..:==+#%%%: :=::=.=:::--:=:.:..=+-::.:::::........::::.............................................::::::......................:::::::::::::::::::::::::::::::::=%*:=+::::-:..::.=-==:::+-..:.-:+:.:++-=%%*.+..:#-+*#=###**..=-........-*+::::::::::::::::::::::::::::::::::::::.:::::::::::::::::::::::::............:-+:..............::.::**+*-::-.:-.:--+::*#:::--:.==..-%...:=+-..**-=*%......-+%%%%+#*:.-***=..==+#%%# ::-:-:--=--=--.....:+=::--:::..::.:.:.:.:......................................................:-...................................::::::::::::::::.=%**=*:==....::::::+-.:.+=*#+.-:*:....:##=+*.:-=.-+::-+#..=-..:.::+-:.*=*:::::::::::::::::::::::::::::::::::...:::::::::::::::::::::::::::::::::::.*-..-#-...........:++:..:.-+===--=..:::..+#*#=+=+-+:....=%.:+*-::-+=*-.*+:......:%=#+*-.....:*+....*#+%% ...:==-=:*:.=..:.::=+===:..:=::.:::-:.:::::::::::..............................................-=.........................................::::::::::.::%#-:=+:.:.::+::==*=++-:*-:.:-=-#+-::*#%--=:.-:=+...-*=:*:.:::::-+::=::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::.---:.::...=-.:=...:-=:-:....==+=--+....:=-:#%-+#+:.....+#%#-.:*-*+:=*=-#-.......:****##==--+=+++*+*+-*#% ....-##--:=-.-=+-==+#::++::=::.::::-.-::::::::::::::::............................:.:...........+........................................::::::::::::::.=++=#:..:--:::....-::..+::.:-.=:.:::%%##*+-+-*:..:-*-+::.::#**=+==.:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::.....::=+.:....:-**=---+:.....---=#*+::=-=:=+=-#%-.......-+%%%%*..=::::*%%@%:......++%#:::#%%:...+#%%%%#+=:- .....:=**-.--==..--+#:..--=-.::.:.-+==:..:-.::::::::::.............................-::=::#%@%-.:=-+:=..:............................::....:::::::::::::::-+===:+--::..:.::=++-.*#=:::=-#:..-%#+%=.:#*.-::*%=-::::::=*##*:::::::-*=-::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::........-#*#-.-....:-+#+..:+:.......:-+%+=+%*==--:+#:.:.--:--*#####-++-...*%%%%:.......=##+++++#%#.....=#%%*:.. .....=--+-..+-:---:.*:=+=-+-...:.:---:.:.:-+=.:::::::::::........................:.=%*:#+:..*+%=::**-:=+-.............................::::..::::::::::::::*#-=-::.:::.::.-#+++-:.***=::-+..:##=#+==%%##*#*#*#::.::.:+*-:-##*:::++-::::::::::::::::::::::::::::::::::::::::::::::::::::::..............:-.-#+=-=:=:.....::-..:*:.:...:.::::*:+*-=:-*##=--:...=-......:+*:.:=%%@@%....-==+*#%*.=.=*#%%*#+++==#%#*- .......-#**:-=::+:--*:.+*=:.-**=*===:::::.-=:::::::::::.............................=-%=#=..===%%-:...*##+*%=................:::::::::::::..:::::.::::::.::+###-..:.:::.:.::.:+=:.+-....+=+*###+::#+*=+::#-::::..:+**-++*#*#=:--:::::::::::::::::::::::::::::::::::::::::::::::::.................::==-+:++*-+*.=+=.:...=-=+:-*=+::.:.:.:=+##++=.=##%+#%=*+=-......:+++-===%%@@%.==..===%%%%--#%###%%#**#+.:.+%# ........-+-+-=+:..--#===.:...:+--=*=::..:-*#=-::::::::..............................-=%+:****+--%-...*%#++...#-...............:::::::::::::.......:::::==....-#+.==*=....:...::--:.*=....+-:###:=**-*##*#-=***%+*#*::::*#+-.:=+::::::::::::::::::::::::::::::::::::::::::::::::.........::::::::::::..-+.-==-::+*%#-.:::::::=*=---::---==-:-**=###**#--*=:==:....:...:**+=:#%%%#..:=..-***##*.==##===+#%%%**===# .....::-=*=+#**-.:-=#:.=...-.==..+:..-:..=-::.:::::::::.:........................::=++##=***+--:*+.:*%*==::-:.*-.......:::::::..::::::::::::...........:-++=:.:*-:...........::.:+-.+-....+#%%%#-:=.+=-+*=#%*+*+++--.:.:-=:=+#-::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::=:::==*=:..::=%*#*::.:-==:-**+=:.:::-::--=-*::+#%%#=-+*:....=:.....=*+..#%%##.+*:.--.......-+#%%++-=*##%%#++# ......::-=++::**+===#:-....-+--++*+-...-++-.....................................:.-==##+-..=#*=.=*.:*#-+-.....:%.........::::::::::::::::....................--*##::-:=:..:-:::.:-==-*+--::=%%#:-+-=-++#=+-=*++..:*:-+-===++*+-:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::-:-+-.:::+::.::=#=-**+:=+-:::::=-=====+-==:----**-##%=:+-:...+-......:---++*%%=*+-=:-:......:*+-***+=*+#=-#%%%%* ........:-*++*#*....+:-::--+...:*=......=-.......................................:-=#%@%+:--=-+:#%+#**:+--:....#:..:......::::.................................-*##+:...::-+:-:::-*+=-+#=:=+%#++-%:.+--#+#*::........:-==*+=*-:::::::::::::::::::::::::::::::::::::...:::.:::::::::::::::::::::=:=+--::::-:::::-#+:-++#+==*+--=+-+=+-:..:::-+-:.:***#+:+:.:=-.....--+++--***@%**:..........::....:....-+##%%%%%# ........:-+*-=#=#*+=#+-:-=-:...==:::-:-=-:.......................................==+%%%%-++:.===*#%@%%#-.......#-:+-...........................................::#+=*-..-+-::*:-:::.=:.-+..-##+-+%=--:%-+:---:::::==-:::-=+-:::::-+::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::-:+:-=::::=:::::=#++*=-+##**=-==::--.-=:-::::=-----###+-+**--....::-+*+==-+-#%%%+.......:+=-.....:--...:+*#*=+*#* :.:....:--:*+*-++-=-%+=:..::===---:...=:..-+:............................+-.....:-+###%%%-+...:-#*%@##+**:=:..-%*%:........................................:.::=++*+:+*++-:..=::::..:+:++#++##=***+*-*=+-++*#****+=:::::=#*-=::.:*=:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::-:=#+::::-=-....-##:--.=+==**:.::.==...-=+=::-+=-:::*#%#%#:...::...:---+:.:++*#%+=#+:...:+==::-:=-:--:.....:::-+=* =:.........+=..:=-.=%......:==::-=+*:-:===*:..........................:=-:=......-+%%###%##%.::.#*@@*#:......:%@@*+...................................:::::::-##*-:+:::=:.::-=:::::::-*+**%*#%*.*:=+***##-..:::.:::--=::=+===.-+=.::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::=::#+-=*+=*-=-::--=:-:.-*:-=#*+:-:*+-==+#=.=-:=---.-#%%#:+.:::--:=::-.-:.:+*-:*%=+%#*+=-=-.:=-+==..-=+=:.......... ::.......=--+*.==--=%:.....=*:..-.+=-=-::--............................:..:-.:.....+#**=:.-+##%+%%%@#*::=....*%%@%...............................::::::::::::..:-#*-=*=#*-.::+:::.=#*-=-:=-%@%@%%=:=*#=-:-::::::::::=-+.-*--=*=+=:::.:::::::::::::::::::::::::::::::::::::::::::::::::::::::==*:::*:-*=-+===:-**:-=+=*::.-##:=-=+::..:::.:=+**==::-###=*+=-:::--*-..:..+#-:+*%-..:+%###:............-........... -+::-+=.-:..=:=-==+-#.....=.--:++-.-=.-:.=..............................:+++:......==::+++-:-.=###@@%+*=-:*%%%##%%#=:...........................:::::::::.......:**=*#*=..**+**=*=-.-**=*:-*%%##*.:**=...=+-::...-+=-##*+*=..-+:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::-:::+:.:=:++*-*-.::--:.===*::::--+#---*:..::::==*-=-=**+-###:+...:.=-***::+*+=+=::*%%--:=#%#*-+*=::=:....:+-.......... ..:-:-......-#%*==:+#...:=....:=:.==:---*:.............................-=#::-...--.....+*....=.-%#@%+=:=.--+%+*-................................................+%+=-:=:.::-*=:.....:...:*=*%%#++*-=:.+-=:=-**-:..---##=:+---::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::+-:-:=:+:-=-:==#-:---::---+:....:..:=-..=-....:....-++=:..*%#:+-:.:::=:.-*-#==..:-###-+*%%#=.=.#%+*=.===:+*#=*......... ....-=**==..:-#*=#%*%:==.-:--:===*=::.-+:.-:.-:.-....................:...+#=+:........:*+-.:+:-:#%@%%%+*%=:+=+:..........:.....................................:+..=+#*+-:.:-*:....-:-+++:+###%#=.-*:...........:.:+--*:.=+:::::::::::::::::::::::::::::::::::::::::...............::.....+:-:===+=+-.::+..:=--.+==-........:-.=--.=###*::..:+:.::=##*.=:+-:=#:-.:+--.::----#%:-:=#%*#::*=%*=--++-*....=::...... =.:=.==++++:..-:+:-*%+.....-::+-..:...-:...::=::.....................::.-=:==+...=-::...*+:=:.:+%#@%::++-.:-=-..--+==-.--...................................::--:==*:-+**+..-.+-..-*::...:+%%%##:.+-..........:...:--:.:=*:::::::::::.........:::::::::::::::::::::..:....:.:...::::::::::-+=-*=--:*++-=::-::++-*#+=:-=+:....=-.===..-%+-::-+#+++=+*##-*:.-#==++#*+**=:+-:.-#%=:::-:..-=:-***+#=-*+.....-....... =-:.:+++*:..=:-+:=.-%+.......+:.....==.===-.-+:......................::....--:+:...=..:.:++....:#*@%-:+-:---.-:..::...:==:.................................:::=+*:..::--#:-.==.--+:.....-=*+%%#%.:+-*=.:.:.::*=:::--:..:#=::.::::::::::::::::::::::::::::::........:++-=*-.......:..::.::.::+=*...:=+-*=:=--:-.-++-:=+:......:.::.=-++##%+-+-##+=-:+##+=.=*#**#+--::+=++=-.-#%:......:=:=+%#+%+##=+.:.:.-:-=.... :-=:..=+-*+=-...=:=.#-=:.::-:=--..:-=:......:::......................:+*....*=:*:++-#+=*==+:..-:##@%#=.:-***:....:---::-:..................................-:.......:..--=:.=:::-=.....::-:*%%#*.*-:.:....::..-++=:.::-=+-=-+==::::::::::::::::::::::::::::.....:.:+.....:*....-+:::=+....::-*=.*+:-=:=*:.-**-*#*=+##-..........=::++::++:==:+=::-=*##+--+-%++++::+.-.***-+*##:..::......-#+#%%%%%%%%+**+%%##=:* ...:=.-:.=*-:.-:-=:-%:..:=:.=...=+-:....:..:==.........................=+-:--*::-.-+:...::=-...:**%%*#-:#*+++...==..----................................::.:-:.......:..:=+-=-+--=*:..-+.+-+###*-*......:.=-**=*+:...:.+:.::-:--::::::::::::::::::::::::::::::::::*:......-+..--.....:#:-::::*+:++-.++=+.:+-+-:=*#+*#*-..::==+*-:--..+::-:-:=**-::.=##*##*:-**:.-+=+*-#+*+:+##:.......+#*#-+*##-%+%%%%*+=*#*:+*- .....-++:=*+=-...:=+%-:=-..-....-*=:......-:............................=+:-+:::==+=--=-::-*+::.++%#=:*=***=--::--:.:=...................::::::::...:...::::::...:..-::::.=:+**-:.:+.::::-.*%##-**=---....:.--===++=*=*:::::::::::::::::::::::::::::::::::::::::::#::::::::+..*:.:.:::=-:-::=*+-:-=*+#=*:-==-++=++:=+#*-::--:....:-=---+..:==-=:=++*%%#:..::=#=:==##==#=-::#%#=-:::.....::.:-.==-*=####%%%%#+-:+ .....-:#*..:+:--...+%#.::+==:..:-..-:....::.............................--=*:::=*+...--....==::.**%%%#%%%%%#%%###+::-:.......::::::::::::::::::::-=::::::.:..::::.::-:-:::-:+:-+=:.:*-:::::+*##-*+:::::::=::-*+-*=::-+-::::::::::::::::::::::::::::::::::::::::::=%=::::::.+*-#:.::::----=-:.-=-:::*#%=*:-:=-:*--..-=::+++-====-.:::=-:.-==--:+....*#%=::...-+=-+##%#+.:.-=*%#::+=:..................:-*+%%%%%%% ....:-.-=+-.-*==-::-%+...---:-=:........:+-:::............................--.:#==*-.-:...:-:+=-+%@%%@%%%@%%%%%@@@@@%#+=:::::::::::::::::::::::-+**#**-::::=+*++=:::::-=-:-:+=:=*:-*###=::+#*###*-::::::::::-::++::::++:::::::::::::::::::::::::::::::::::::::::::#%%:::::::#@#*::::::-**--.:--+=:=*=+%+%+++::+=#+*=-:.:-++-:-:=......--::.=-..:+-..+##-:.:::*+==**+-+.:-=++#%#--::......................-***%%#* ....::==*-+=-=+#*+:=%-...---=*-::......:#:::+.............................:=:..-.-=::..:--:.=#%%%@@@@@@@@@@@@@@@@@@@@@%-::::::::::::::::::::-++=+*#****=+=*###*++:::::-=**#*+:::::----+--*=*###*:::::::::::-:::::::=+:::::::::::::::::::::::::::::::::::::::::---...-=-::::*@+*:::::-*%%++::-:-*-::+=+*%+-::**+.:+==--=:..:-::*=-:-:..:-=:..==:--:++##-:-=-=+##+=*+*+-::-*%#%#:.::::.......:.....:.:.:::.-.::=** .....:...+:.+*+:*+-:%-..-.:==-=-:-.....-.-*#=:........................::.:-.=::-+-+#=:.::::+%@%@@@@@@@@@@@@@@@@@@@@@@@@@%=::::::::::::::::====*##%##%##%#%%%%###*+===-*#*=:+=+---==-:::=**=**##:::--:::::::+=::::::*:::::::::::::::::::::::::::::::::::::::::::::...:::::::*@+*::::-=:..:--.-+:=*:.-=-%===:+-:--+=-.:--=-=::=-::...:....:-=...++*=.=##-.::=*%*+==*+#==:++###%%**=::................:::.......:.: ..........=..:##*+++%-.=-=++*-.....:-++=--=:..:::...:......::::::::::::-::::.-:-++:==-:-::#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#::::::::::::::==**##%=::::%%%#%--:-%%##*#*-=+-=-*=:**%+:-::-::*%%%%*:--:::::::--=*#*=--+::::::::::::::::::::::::::::::::::::::::::::::::::::::::+%++:::::::..::-*--==+=-=-=%***####*+=::-+:.:::=+==#-::::..::..-=:...:*=*##**#*:=#=-==:=*=::*#=:#%%=#%#+...:-.-==:...............:.-. .......:-.-+*:+-:+:*%%**=-.-:-:.--..--:==:::::::::::::::::::::::::::::::=-:::=#+::::==:=-%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@-:::::::::::=+###%*::::-::-***-+-===#####*++:+##*##*##+=:---:+=%#%+---=:--==-===:+=-:*-:-==-:::::::::::::::::::::::::::::::::::::::::::::::::::*%*=:::::--+::-::--::-*+===#::=:-=++::-:--::::-:=*--=+-==-.....::=:=....*%%%%*+=-:-=+-:==#+*=*+#%%%**##%#+:*##+:++................:-. .........:=--:#*...+%+.:..:-:::.:.:=:::.-:::::::::::::::::::::::::::::::-*=-=:-+---:-##+@%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@-:------::=+###%*:------------------*#####**++#+=:+=+*=--:-=*-*##+:----:=+=---:+#*--=:+-==*+------------------::::::::::::::::::::::::::::::::-#-:::::::---:::::=::::*.=:#:=:+=-:*+**:-==::--:=:=:...-*-::::::=:===:..+%%**:-.==-:=-+==+==++#+%%*:+=-=+#*##*%%=..................== ...........:++#+=::=%=::..:==-:::-=:=::+=-::::::::::::::::::::::::::::::::=-:+:-=%=:::=#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@-:-----:=+*#####:-------------=--+-:*#####**++=:::=-*+*--==-:*##+-----------=*==*=*:------:-------:-----------:::::::::::::::::::::::::::::::-#-::::::::=*-:::::=:::=:=-#-=:+:--=*#+#=+:-=-::::::::::-.+#:.++:..:+::.+##*==+=++=*##=:+-+=++++%%%#**#+:-....#=+==:........:+#*%::=+ ........::::-:%#==.+%=..:-::::++=::::-::::::::::::::::::::::::::::::::::::::-:-=*=----+@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+:----=+*######*:--=---=--=--=---+=*###*********@@@@@@@@@@@%@@%#-:::::--:---=+::=::::::-:::::--:-:::::::::::::::::::::::::::::::::::::::::::=%--:=::::::*=::::::-::-*=%#:==**+-=::-=====:::::::::::-::---*-...:.:*:.+%#*==+%=-*--+###+-#:=--%%###*#*:::.....:*+=.==:..:.:=*%%%%*- ::-:.........:+*+*-*%-......-.-*+-:.:+***::::::::::::::::::::::::::::::::::::--::**:::#%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*::=++***######*+-::--:-------:=+**#########****%@@@@@@@@@@@@@@@@@@@@@@@@@@%#**+--::::::::::::-:++---::::::::::::::::::::::::::::::::::::::=%-:-=-:::::-*+::::::=:-+***.-*=+=*=*=:=+#=**-.:.:::::::::+-.::-+:...:=#+##+.-#**++=-+*+=*+=*=+=%%%%+=**=-...:....:::+##+*%##=...-:.. =-.........:::*+#+=*%*.....:+*+--=.:==:-....:.:::::::::::::::::::::::::::::----+*+*=:=@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%++**############*##*=:=:-+*#**##%%%%%%%%%%#####@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%%%##*+===+=:::::::::::::::::::::::::::::::::::::=%-:-:--:::::-*=::::::---*%+=--:-#*--++==#---==:-:::::::::.::::.::-+-:-=##%#+*#==+:-+-*#%#**-++*%%%#%+*#*-..:-::....::::-==+#%%#**:=: .--......:--::=-=+=*%+.....+=*=-=+:--...:..::::.:.:.:::::::::::::::::::::--::::::::#-#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%*####%%%%%%*+==+%%##*#*#%%%*=-=-:=--==+%%%####@@@@@@@@@%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%%%##*+=--::::::::::::::::::::=%:::---::::::-++=::::=-:-%+::==*++-:::**+:..:-+#++=::::.:::::::::.-++-+%%#%*#*++=.-++==#*+*#**#%%###+--:.-=::..:.::..:.:=#+*%%%%%%++ ...-:...:=.:::-=:-**%=.::=:-:.-+-*+::.::.:.:::.:::::::::::::-:::::::::::::::=:::-=-=#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%%%#+==-::::::::#+:=****=:::+=:++-+::::%%%%###@@@@@@@@#.:%#..#+.-%#-+@**%%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%.::::::::::::::::::+%::::=-:--::::-*-:.::-==-%=:+=+:=..---**-=-=:..::**-::::::.::::.:==:.-+####+==*++=--=+*%#+##%##%%*-....:+===-.::-:::.:.:-:-#+*+::::= ..:--=-:::--:.-*=-:#%+=+-.:=:.:=-::::::=#%=-**::==+--:::-=-+*+:::::-:::::::-:.:::--=%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@-...:..:::::::.*==..:.::::.--::::::.:#######%@@@@@@@@#.:%*..#=..-+.:%:.=:.+%-.-:...:=@*==+#@@@%%@@@@@@@@@@@@@@@@@@@#.::::::::::::::::::+%::--:=:--.::::=+:-:::+:+%#=*+-=::==:-=====:...:...-=:::..::-:.:==...::####:-=-..-==-+*#%###***%%-:::=+=:.+:-::::..:.:..::.::::::::: .......-=::*+..--:+%%*...::-:+-:::::-=*#%%*+%%****##+---*####:-==#==:-:::::::--::-:+%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+:::::::::::::.*--:::::::-:::::-:::--#@@@@@@@@@@@@@@@#.:%*..#+...:.:%:.=+..+..*:.:==*@-....:%:...-@@*..%@@==@@@@@@@#:::::::::::::::::::+%::::::--==:::::++:.:::==%+==--*=-:-=-::::*#*=-::::-:=+=:-:+-=:.++...::+###=--+*+++####*%*+**##%%==-=:.:=*::=-::.::::::::::::::::::: ........:-++--++*#+%%#::::-=-:-::::+#%%#%##%%%%#-=*#+:**#*%%%-=*##****--:-=-:.::-:=%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%-++#+:::::::::*=*+::=:::-::::---::::*######@@@@@@@@@#..#+..#=.:...-%:.+%....=%.....#@-.=*..#..++#@%:..=@#..%@@@@@@*:::::::::::::::::::*%:::::==----:::--+::---=##***+#-::--:--:.::::-::::.:.:..:===+=:.-:-:..:*%%#:-:=*%++**=*%#+#++-=%%+==:..:+-:-=:::.:::..::::..::::.::: #*##+-::=*#%%%*+*%#%#==.:-#=:.::::*##%%##%%%%%%%*%%%#%%%%%%%#+#%%#%%+*-*#*+-=::-=+#%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#=-##+:::::::.**-::=::---=::::+-::::*######@@@@@@@@@@:....=%-.=+..-%..+%=...#%..-==%%.....=%+...=@=....%#..%@@@@@@#=+=::-:--::::::::::*%:::::::--:=::--:+*+=:--*#-=-:+:::--+=:-::::::=::::::::::.#=+##::..-+..+%##....:##*--=#%%#+=:-#%%:...::-=.-=-:::::::.::::::::::::::: %%%%%@%+*%@%@%%%%%%%%#*#+*%#*-=::.+%%%%%%#%%#%%%%%%@%%+*%%*%%%+%*%%#**=%%%==*#*-=*%@%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*:-*=**+=-::::*#-:::-=::::=:::+*+::-**#####@@@@@@@@@@@#++#@@=:*@=.+%:.#@#..=%%.....+%..=..%%:=*..*.....+#..%@@@@@@@#%+:-=-=:::::::::::*%::::.:::--=::-::-+*==:+#%#+-*-:.--:=::=:::::-:+-:.:::.:::#+...-+-::=:=*%##:-+*+:=-.-**##+==+**%@=:-++**+**--::::::::::::::::::::::: %%%#%@%+#%%%@@%%%%@%%%%%%%%%%###****%%%###%%#%%%%%%@%%%@%*#+#%%#+%%#*%%%#%#%#*%%%#%@%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#-==%###+#=*#=%%+-:=#=:::::=::#*%+=+**#####@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%@@@#*++=#@-:%=.-@-...==.=@*..*....=@@@@%##*=*%#=*==::::::::##::::::::--=:-=::::*-:-+#%+:++++*-:--:::::::::::=++-::::::#-.:::=:=+*=-*%%#=#*#*+=*#%%%#%+=*-:*%%+-:-+-::=:::=-+:::::::::::::::::::: @@%@@@%%%%%%%%%%#@@%%%@@%@@%@%%@%%%%%%%#%%%@@@@@@%%@@@@@@%%%@%%*%%#%%%%%%%%%##%%#%%@%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+:*=##%%#%#%%%%%%=:**+*:::=+##%%%*-+**#####@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%@#*+=*@@@@*----=-=++++=++==---**+-*::::-::-=:=*=::-*-::*%-=--:=::+*+#+::::.::::-+#+==-=*=#-.:=*+*-::-:#%%%=.....:+##*+%%+*+:+#%%=*-:-+-*+:.:::::::::::::::::::::::: @@@%%%@@@@%%%%%%%%%%%%%#@@@@@@@%%%@%@@%@@@@@@%@@@@@@@@@@@%@#%*#%%#%%%%%%%%%%%@%##%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%++#%%#%%%%%%%%@%*##%%--*##%%%%#%=:=***######@@#%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+---====+##*=+**+=====+----=--++++++++-*-:+=-+*+=-=--:--==+*+=#:::::-:.:::+::=:#:=#%####%%%%%%%#-*=.=+=*==-*%#-==+*#%%-+-===*--::==+::::::::::::::::::::: @%%%%%%@@%@@%@%%%%%%%@@@@@@@@@@@%%@@@@@@@@@@@@@@@@@@@@@@@%@%%*%%%%%%%@@%%%%@@%%#%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%:=#%%*%+#%%%%%@%%%@*#+*%%#%%%%%-:-+**#####*=#*=*%%%%*##************##%%%%#%%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+---===+#***++%#+=*#**=------=+###*#*+=------=+++++=====+++++++++++=-==-+==++++**%%%%%+#%####%%%*#*=**++-+:=%%--*#**%#-++=+:::::::::::::::::::::::::::::: @%%@@%%@@%%%@%%@@%%%%%@@@%@@%%%@%%%@@%%%%%%%%%%%%%%%@@@@##@%%%@@%%@@@@%%%@@@@@@%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%+=%%#%%#%#%%%%@%%*%%#%*#%%%%%%-::=+***####*-+=*%%%%%%%#**#***************+*#####%+++=::::+*#######%%%%%%%%#%%@@@@@+=-===+*****++*+=*#***==-----=*###***+==-----=###**+++=*########*++====++******++==--====++==+=+==:---+++++++++=+-.*%%+-.:::::::..:.::::-:.:::.::.:.:.::: %%%%@%%@@%%@%#%@@@%%%%@@%%%@%%@@%%%@@%%%%%%%%%%%%@%%@@@%%%@%%%%@@%%%@%%%%%%%%%%%%@@@%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%#+%%%%%##%%%@%%@@%%%%%%%%%%%%+:-:++**#####*=++%%%%%%%%#%*%%***********###++######++=-.:++##*#*#########*++=***###*=+====+******=+=+*****==--=-=+#*******+=--=-=+#**++==++#######****======+###***++=======+*#####*+=--==+#######*==:-#%#:=#+=:........:-=--:-+=.:=::.:::::: @%%@@@@@@%@@@%%@@%%%%%%@@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@%%%%%%%%%%%%%%%%%%%%%%@@@%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%%%%%%%%#%%%%%%%@%%@%%%%%%%%%:::=++**#####*=+++++++++++**#*++*********#**==*#####++=--=+%#%**########%%#+==*******+++==+*******+++******+===--=********++==-=-=+*+++==+=+*###******+=+=+==+#****+++========*##***+===-=+######**+++:=%%%##%%++.::::-::-++++=-*=:-=*+:-:***# @@@@@@@%@@@@%@@@@@%%%%@@@%@%%@@%@%@@@%%%@%%%@@%%%%%%%@@%%%@%%@@@%@@@@%%%%%%#%%#%%@@@%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%@@%%%%%%%%%%%%%%%@%%@%%%%%%%%%=:--++***#####*==--====+****+==++==+*********==+***#*++==+++++#*****##=++++++==********==++*****++++=*******+-===-+********++=====+++++====+#**********+++====+**++++++=======+****+++++==++++****+++**=*%@%%%%%%%-:-==:==+++++=###*+#####:.... @@@@@@%@@@@@%@@@@@%%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%%%@@@@%%%@@%%#%@@@%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%@@%%%%%%%%%%%%%%%%%%%%%%%%%%%---=++***#####++=====++**++=+#####*++********==+*******+*###++********=+**++++=+********==+===++=====*******+=====+******++++===-==++++====+%*********++++++=++*++++++++=======++++++++==+==++++++++*%*-*%%%%%%%%%*=+*++=++##+==*####%%%%%%%%%* @@@@@@@@@@@%@@@@@@%%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%%%%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%@@%%%%%%%%%%%@%%%%%%%%%%%%%%#---=++***#####=+====++++++=+######**=++++++++==+*******=*#**++********=+#*****++********=-=========+++***+++++===+*****+++++++====+++====+=++++===*+*++++=++=+++++++++++======++++++++=============*%@%%*%@@@@%@%%####%#*#*+%###%%%##%%%%%%%%%% @@@@@@@@@@%@@@@@@@@%%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%%##%@@@@@@@@@%%%%#%@@@%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%%@@%%%%@@@@@@@%@@@@@@%%@%%%@*---=+****####+=++++++++++++######***++++++=+++********+=*#**++********=+#******=+****++++=========+**=*+++++++=+=+**++++++++++====++====++=+++====++++++++=+==++++++=+++======+++++++====---======+%%%%%%%%%%%%%%%%%%%%#%#%%%%%%%%%%%@%%%%%%%%% @@@@@@@@@@%@@@@@@@@%%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%%##%@@@@@@@@%%@@*%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%@@@@@@%%@@%%%%@@@@@@%@@@@@@@@@%@@@+---++***#####++*++++++++++*#####****++=+*##*++***++++++=****++********=*#*******=*%#-=--=========+*#*=++++++++===#++++++++++++====+=======+++=====+*+++++++++=++++++=+++======+++++++=+=------===+#%%%@%%%@@%%%%@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% @@@@@@@@@%@@@@@@@@@%%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%@@@@@@@@@@@@@@@@@@@@#.+#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%%%###%%==*#%%%%%%@@@@@%@@@@@@@@@@@@@=---=+**#####*=+*++++++++++*%#%#+*****###****++*++++++++=***+++*******+=*********++#=------=======+#**+++++++++==========+++++++===========++======+*+++++++=+=++++++=++=======+++++===---------=+#%%@@@@%%%@@@@@@@@@@@@@@%%%%%%%%%%%%%%%%%%%%%% @@@@@@@@%@@@@@@@@@@%%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@#.-*#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%%#*+-------::-::=------=+#%@@@@%%%#---===**#######-+++++++++++*%###+******#****+++*+++++++++***+++*******+=**********=+==------=====+#***+=++++++++-=======-+++++++-=======+=+======++=+***++++===++++++=++=======+****===---------+*%%%@@@@%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@%@@@@@%%@@@%%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@=-=*#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%#%**%+=--:-------:-.:=+=---==+==--===+++++++**#####@#*++++++++++=*###*****++==+**+++++++++++++=***+++***#%%**=**********++=------=====+******-++++++*+=-=======++++++++====--=+========+*++%****+++==++++++=++=======+%@%+-----------=*%%%%@@@@%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@%@@@@@%%%@@@%%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@==++#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%%##%**#===-:::::::::::-==+*=+++++++++++++*****#####%@+*++++++++++=+*****+++++=+===+++++++++++++=**++++#*%@@@@*=***********=+=-----=====*******=+%#-=----=====-===+==========-==========+**++#****+++==++++++==========+%@%%***********++#%%%@@@@%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ %%@@@@%@@@@@@%%@@@@%%%@@@@@@@@@@@@@@@@%%%%%%%%%%@@%%@@@@@@@@@@@@@@@@@@@@@@++++#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%%%*+*##*+=----:::===+**+***+++*********#####%@@%%%++++++++++++***++++++*+*+*+===++++++++++**++++##%@@@@*+************++=========+********=#=-=----====-==+==+=-=======-==========+++==+==**++++=++++=+==+=====-=+=======+*****+*+++#%%@@@@%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @%@%@%%%@@@@@%%@@@@%%%@@@@@@@@@@@@@@%@%%%%%%%%%#%#+#%@@@@@@@@@@@+%##%%%%+:=++**%%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%###**++*=:----=+*##*=:==+++**************#####%@@@@@@@@#++++++++++=+*++++==+******+++==++++++++**++=+#%@*+=--=+++++++++++++++=++=++++*******++=+-------==-=--+#=+=--======-===+%%#*%%%%#*+=+---+++++++++==+==+-------+========*++++++++=+%@@@@@%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@*#@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@+*%@@@@@@@@@@@@@%*#%@%#+:=++**%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%%%%*-=+++***##*******#######@@@@@@@@@=++++++++++++===+=+++***++++++==++++++++=*+++=+#=:::::::++++++++++++=+++===+=+=*******++==-------=----=*#+==---------=+=*@@##%@@@%*#*###*+++=+++++==+===========++=======++++++++++*%@@@@%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%+***%@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@=+%@@@@@@@@@@@@@@@@@@%+-%%@%+++#%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%%#######%%#%%%%%%@@@%-=***######***######*+*+=@@@@@@@@=+#%%%##::=+---++++++++++++++==+++++++++=*+++=+%--:-:::-+++++++++++++++====+=+=******++++==----------=+##*==-----:---==+#@@##%%@@%**+++++++====+***+**********+=+=+======+++++++++++#@@@@%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%*@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@**%@@@@@@@@@@@@@@@@%#+**###%@*++*%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%%%%##**++===-=**##############%%=*#==%@@@@@@%+=+#%@@+:===-::---==+++++++===++++++=+++=*+++=+%**------+++++++++++++++====+=+=******++++==----:::---=+##*+=----::-:===*@@%##%%@@%++==+=++++====*%%+**********++*++====++++++++++++++#*#%%%@@@@@@@@@@@@@@@@@@@@@@@@@@@%%%@@@@@%@ %%%%%%%%%%%@@%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%#*#%%%%@@@@@@@@@@@@%*%#%%%%%%%%++*%%@@@@@@@@@%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%#*#**+*++******++++*+-+*#############%%%%%+++==+++++++=+=+%@@++***+=:----=++++======++++++=++++*+++=*%#-------++++++++++++++=====+==+**+++++++++=--:::::-:-+##***=---::---======---=+++++++++#++++====+%@%%%#%%%%%%%##%###*##*%%********##*#@@@%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@* ----------------------------------------------+#----*@@@@@@@@@@@+-------:-----+*%@@@@@@@@@@%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@##****+*++++==--==++*=-+*######*+=------:--+====++++++++++=+%%-+-++=:-:----==========+++++==+=++*+++=*%+::::::=*+++++++++++++========+*++++++++++==::::::--=+*****==-:::---+=====---=+**##***++*++=====+%@@@%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@# ------------------------------:---:--::------+#+::::+@@@@@@@@@@@+::::::::::::-+*%@@@@@@@@@@%@@@@@@@@@@@@@@@@@@@@@@@@@@@@%%#*****++==------====--***##+-------:::::-=++=++****#*+++++=+++**:---------====-=++*=++=====+=++**+++*%====---=*+++++++++++++========+*++++++++++==:::::-:-+*******=-:::--=====----=+#######**+**+==+=+=#@@@%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%%@@@%%%%%%%%%%%@@@@@@@@@@@@@@@@@@@@@@# ::::::::::::::::-------::::::::::::::::::::::-=::::=#@@@@@@@@@@@*::::::::::::-##%@%@@@@@@@@%@@@@@@@@@@@@@@@@@@@@@@@@@@@%%##*++**==-----=======--*#*=--------=====-#+==*+++*##********+=++-----------=====+*#*=++=+===+=++*+++=+#%%%%%%#+*+++++++++++++=======++*+++++++++++==----===+*******+======+=========*####*****+++++++=+=+*%%#%@@%=...-*....::.*%*.:*.--.-+.:#-..#%@@@---------------------------=#*#=-* :::---------------::::::::::::::::--------:-::------@@@@@@@@@@@@#+++++++++++=-+*%%%@@@@@@@@%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%%%#########%%%%%%##*=-**+===+====+++++++#+-+*++******++###***==++=------===+++*%%#*=+======++=+**++===#%%%@@++*+++++++++++=++++++++++*******+++*+=+++===++*#####**++++++++++++++++*##%%%%####*******##*##@@@@@@#-.:..-..+##..+%+..=.::..:..:..*%@@@@---------------------------*+#+--* ------=====-++++++++++++++=+==++=============++=====@@@@@#@@@@@@#============*##%%%@@@%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%%###****#***++++++++=+=-*+++==++++++=====-=-=+++@@@@@@###%%%%%%%%*=+=========+#####%################%@@@%%%@@%##################################################%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@@@@@@@@@@@#-....-....-..+%+..=..:.....:.-:#@@@@*************+++++++======%*=#---# ++++++++++++++++++++++++++++++++++++++++++++++++++++@@@@@*@@@@@@*=+++++======*##%%%@@@%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%#%#####****+++++============-----+++++++****#****#@@@@%*#*######*#############*#*####################%@@@%%%%%%##############################################%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@@@@@@@@@@@@%-....:....=..=...:+.::.::..=..:%@@@@#+**+*++*+++++++++++*+++++******+# ++++++++++++++++++++++++++++++++==============+=+---=*%@%=@@@@@@+====+=+===-=*##%#%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%##***++++=*+===-=-===+++------::::-::---**********@@@@##############################################%@@%@@%##@%########################################%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@@@@@@@@@@@@@%***%%#***%%#@%*#@@%%@#@@%%@@%#@%@@@@%##%=--------::------------------ ==+++=+++++++++++++++++===---------:-++++++++=++++++==**++++*#===========---=**#%#%@@@%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%*#+++++=+==+--===++++++=:-----:::::::::-********#*%@@@*#############################################%@@@@%%%#%%#####################################%%%%%%%%#%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%%@@@@++===++++=================-------- ==++++++=--=========++++++++=+++++++++++++++=====----=+*-::=+*:::::::::::::::+##%%%@@%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%##**++++++++**##*****++-:::::::::------=#*********@@@@##############################################%%%%@##%%#%%#################################%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%%@@@@++++++++=========================- =====----------::::::::::::::::::::::::::::::::::::::-=+::-=+*:::::::::::::::+##%%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%%%#######****+=====++*-::::::::::::::::-#***####*#@@@@%##############################################%%%%%#==-+==######################******+++++******************#############################*****############+-::::::.::-::-:..::.::........+%@@**+===========================--=--- ::::::::::::::::::::::::::::::::::::::::::::::::::::::=+-:=+*=::::::::------:==*%*%%%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%#%##*****+++**++++*%%*::::::--:--------=########*%@@@@@#################################******+++++++++=+===========---======--------------------------:::::-::--------::::::::::::::::::::::::::::::::::::::::::::---:::::::::::::::--::::::::::*%@%-----===============---------------- ::::::::::::::::::::::::::::::::::::::-:-------::--::--=.:=+*::::::::::::::::::##*%%%%%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%%%##*****++++##%@@@%*-::-::------------===+++++**-*##@*****+++++++========-------------------------------:------:-----:----------------------:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::-----------=======++++++++++++++=%%@%++++++++++++++++++++++++++++++++++++ :::::::::::------:::::::::::::::::::::::::::::::::::::.:###*=::::::::::::::::::####*%%%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%#+++*:::::---::------------------==---==---------------------------::-:::::::::::::::::::::::---------::::::::::::::::::::::::::::::::::::::::::::::::::::::::--------======+++++++++++++++++++++++++==========++++++++++++++++++%%@%++++++++++++++++++++++++++++++++++++ :::::::::::::::::::::::::::::::::::::::::::::::::::::.=##=*#::::::::::::::::::-%*%**%*%@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@%%%%%%###***++++**#@=::::::::::::::-::-:----:::::-:::::::::::--:::--::::::::::--::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::--------=======+++++++++++++===========+++++++++++++++++++++++++++++++=========+++++++++++++++++++++**++++++++++++++++++++++++++++++++===++ ::::::::::::::::::::::::::::::::::::::::::::::::::::=%%#--:--:---:::::::::::::#**%###**%%%%@@@@@@@@@@@@@@@@@@@@@@@@@@@%%###*******##*+*%%#-::::::::::::::::::::::::::::::::::::::::::---::::::::::::::::::::::::::::::::::::::::::::::::::::::-----====++++++++++++++++++++++++++++++++++++++++++++=+++======++++++++++++++++=====++++++++==========+++===++=========+++++++++++++++++++++++++++++++++++++++++++ :::::::::.:::::::::::::::::::::::--::::::::::::::-::-==:-===----:::::::::---:=#*##+%#+###%%@%@@@@@@@@@@@@@@@@@@@@@@@@@@@%%%%%%%%%@@@@%*==+::::::::::::::::::::-:::::----::::::----::::::::::::::::::::::::::::::::::::::::::---====+++++++++++++++++++++++++++++++++++++++++++++++++++++++++==++==++================+++++++++====++++++++++++======+++======+++++++++++++****++++++++++++++++++++++++++++++==+++ ::::::::::::-::::::::::::::::::::::::::::::::::::::::::--:-::::::::--------:-==+#+=#%%++#%%@%%@@@@@@@@@@@@@@@@@@@@@@@@@@%%##*****+++====%#:::::::::::::::::-----:::::::::::::::::::::::::::::::::::::::::-----====+======++=+++++===+++++++++++++++++++++++++=+==++++++=====+=++++=================================++++++=+===++==+++++++++====+======+++==++=========++++++++++++++++++++++++++++++++=====+=+++ :::::::::::::::::::::::::::::::::::::::::::::::::::----------------------:-::-::=:=*+=#%%#%@%%@@@@@@@@@@@@@@@@@@@@@@@@@@@@%#**++++===-*@*=:::::::::::::::---:::-----::::::::::::::::::::::---==++++++++=========++++++=========++++++++++++++++++++===++=================================-===========================+++++++++++++++++==================+=+++++++++===++++++++++++++++++++++++++++++++++++++++++ :::::::::::::::::::----:::::::..::::::---:::::::::::---::--::::::-:::---:::-::----:%=+*+#%%@@@%%@@@@@@@@@@@@@@@@@@@@@@@@@%%%%*+=====*%+=*#:::::::::::-:--:::::::::..:.::::::-==+====================---====------------=-=====================================================================-==========================================================================++=======+++++++++++==+++++====+++=+==+ -:::::::..:....::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::-:=%@%+***#%%@@@@@@@@@@@@@@@@@@@@@@@@@@@%##%*%%@@#+=#*=%-:::::::::::::::::--===========++==+=======================--=---==-------===--=--------============================----===================-==---=====================================================-=--============================================================= ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::--+@@%#+#**##%@@@@@@@@@@@@@@@@@%%@@@@@##**%%%##++%@#-...::-===--------=----===========++++==================-======--------=-----===++++*+++++==================-======================================================================================--=----===-====-------=====-===========--============================ ::::::::::-------:---::::::::.:::..:...:::::....::.::....:::::::::::::::::---:::::::+%%*-+#@@@%**#%%@@@@@@@@@@@@@@@%%%@@%@@@@#@###*@%*%@+------------------==================++===============================+++++++++++=+==+=++++++++++++++++****+++==++++++++==================================================================================--===============--=-===--==================================== ::::::::::::::::::::::::::::::::::::::::::::---:::::::::::::::::::::::::::::.:::::::*@+#*#*****#@@@++%%%@%@@@@@@@@@%%@%#**%*@@@%*%--+%@@=----------------------===============================================================++++++++++++==++++++++++++++++++++++==+++++++++++++++++++++++++======================================================-----------------------=================-==================== :::::::::::::::::::::::::::::.:::::::::::::::::::::::::::..:.::...::::::::::::::::::#%#+##%#%@@%%##*-+###@%%@@@@@@@@%%###%%@%**@@@@*-+@@@+--------------------=-===============================================-================================++++++++++++++++++==++++++++++++++++++=+++++=++=-++==++++++++++++++++++++++++==================-=-----=--=====--=-------=--==-==============================++++ ::::.:::::::::::::::::..::::::::..::::::::.............::::::::...:.....:::::::::::.-%@@@@@%%@@%#*##*=@@##@%%%#%@%%%%@@%@%#%@@+#@@@@@%%%@%*##=---=---=------============++==++++=+===============+======================================================================+++++++==++==+++++===+++++++++++=====++++++++++++++++++=+++++++++++++++++++==+++++==================+=++++++++++++++==+++++++++++++++++= ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::-=+*#%%@@@@@@@@@%-**+++#%+++*##@@@+++%%%#+==-+%#@@@%===:-=*=-==-====-==============++++++++++===================================+=============+++=+==++++==++==+==+++++++++++=++=====================+++++++++++++++++++++=-+++++++++++++++++++++++++++==================+=+++++++++++++++++=++++++++=====++++++++++++++++++ :::::::::::::::::::::::::::::::::::::::::::::::::::::::::...::....:..::::--========##**##%%%%%@%%%%%#--*=+++#+===+**@=====+%=+===+@@#+#@@@##%%##*#+===============+++++++++++++++++++++++++++++++++========+==++++++++====+==+===++++=+=+=++=++=+++++=++=++=====+++========+++++++++=++++++++++++++++++++++++++++++++++++++++++++++++++++++++=========++++++++++++++===================+++++++++++++************ ::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::---=----------=--===+=#*###%%#%%%%%@%%%----=+%#%#=+#==%+---=*%@@@**@@@@%##@@@@@#**-:-+@%=-==========+++++++++++++++++++++++++=++++++++++++++++++++++++++==========+======+===+++++++++====================+=============+++++++++==+=+++=======++++++===++++++++==+++=+++++++++++++++++++++++++++++++++++--+++++++++++++++++++++++++++++++=-=***** ::::::::::-:::::::::::::::::---:::::::::::::::::::::-==========----=---===--======*#+**#####%%#%%%%@@%--##@%###%#==*%%@==###@@%@@@@@##===+%*%@@%*=-:*##-----=--========++++==++++++++++++=++=++++=+++++++++=====+====+==+===========+=+=+++++++++++==+==========-===-====================================++====+=+++++++++++++++=+++++++++++++++==============++++++++++++++++++++*******+++++++++++++++++++++++ ::::::::::::::::::::::::::::::::::::::----===---------=-=======------------=====-*+++**##*####%%#%%%@@#=%--*%##@@@#@**%%=%@@@+#*+@@@%+==++@@%*#@@@@*@@*----===--==================+++++============================================================++++================+=++=+=====================+++++++++++++++++++++++++++++++++++++++++++++++++==++++===========================+++++++++++++++++++++++*++++ :::::::::::::::.:.....:....:::--===------=----=-============--------------------=+*+++++++*##%%%%%#%%%%:=---=#@@@=--#%#=:#@@#=#*%*+#@@@%*###%#=*@@%@@*----=----======+=======+===++++++++===========================+=++========+==+++++=+=+++=====+==+++====+==++==============+++=++++============++++++++++++==++==++++++++++++++++++++++++++++++++++++========++++++++++++++++++++++++++=====+=====+=+++++++ .:::::::::::::::::::-====--=-==-==-======--=-=-=----------------------------=====#******#######%###%%%@--=-=+--#------*--:=%@@@%+%*=**%@@@@@%====%@##%-============+===++==++++========================++=====-===+==-=======+======++++=+++++=++=++++++++===========-=====+=++=======+==+++++=++++=++=========+=+++++++++++++++++++++++++++++++++++++++++++++++++++==++=+++++++=======+==++++++++++++++++++++++ :::::::::-====-----=---------=====-==------------------===------=-===============*******##%%%%%%%%%%%%%%-+==-+%@%---=*@%--:@@@@@@@#=#%*%##@@@+==%@#-%@=========+=+==++++++++++++++++=========+=====+=========-=====-===--=======+=======+=+++==+=++++=+++++==+=+++++++++++++++++++=++*+++++=+++==========+++++=++++++++++++====++++++++++========++++++++====+======+++++++===============+==++++++++++=++++++++ ====----------:--------------------------------=====-====---======--=-===========**#*#%####%%%%%%%%%%@@@#+@*@##%@@*=***@@%%@@@%*#@@@@*+%+%@@%@#%@@--%@==------=========++++++++++++=++=+===========================+===++=====================+===+++++++++++==========-========+++===+++=++++++++++++++++++++++++++++++++++++===++===+==++++================+++++++++******++*****++++++++++++**********+++**** -------------------------------------------------=-===========------=-----=====****#**####%%#%#%%%%%%%%@@@%-+@*%**==@##%#---%@+====#@@@@#@%###+++*-==%*=========+++++++++++++=++++++++++=+++++====+======+=-======================+=========================================+++=========+===+=++++++++++++++++++++++++**++++++++++++++++==++++++++++++++++++++++++==++++++++++++++++=++++++++++++++++++++**+**** ---------------------:--------------------------------===--====--=====----=====**#########%#*#%%%%%%%%%@@@*---%#+----*@*====-+#--=-+%%@@@%@%#++*%@@--%*---==============+=+==+++===+=+====================================-=========+====++++=++=++++=+==+=+++++++++++++++========+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=++++++++++++===++=+++++++===++==++==++=+++++++++++=++++++*++**** ----------------::::---:---------::---::----------------------=-=-------------+*#########%%####%#%#%%%%%@@@+=**#-=----#*====*%@@@*##*##+---=##*-=-=#+@+======================+=========+==+++++=++=++++++++++++++++++++++=++++++++++++++++++++++++++++====++++++====++++====+=====+++++++++++++++=========++++++++++++++++++++==++++===++++++++=++++===++++==++++=++++++++++++++++++=+++++++++++++++++++++++++++ ------------------------------------------------------------------------------+*######%%%%###%%#%%%%#%%%%@@@%%%%@*--*@@@@%+#%@@@@=-=#@*+=++%@*=====+#@#=====================+===++++++++++=+++=+++++==+++++===================++++======+++++++++=+++++==+++++++++++++++++++=+==+++++++++++++++++++=++++++++++++++++++++++++++++++++++++++++++=+++++++++++++++++===+==++++++++++++++++++++++=+++++++++++++++++++ --------------------------=-------=-===------==---=========------------------=**%%%#####%%%%%%%%%%%%%%%@@@@%%%%%##*#@@@@%*==#@@%===+*%@%*#@@*========#%==+==+====+=++====+==++=======+++============++++==========+++=+==============+++++++++++++===+++++++++++=+==+======++++++++===++++===++++++++=====+=+====+++++++++++++++++++++++=++++++++++++=+++++=====++++++++++++++++=+++++++++++++++++++++++++++++++ ----------=-----------------=--=------------------------==--=-=-------------=**%%#*###%%%%%%%%%%%%%%%%%%%%@@@%%%%%****%#**+===%#+=+@@@@@++*%%=========+=============================+==========+=======+=++==================+==++==+++++++++++++++++=++++++++++++++++=++++++=======++++=+================++===+++++++==+===++++++++++++++++++++++++++==+++=+===++++++++=++++++++++++++=++++++++++++++++++++++++ --------------------------------------------------===========================**%%#%%%%#%%#####%%%%@%%%%%%%%%%%%#%%@@@@@@@%***%%%@@@@###@%*@%%============================+++++=++==========+++++=+=============+=+=++=++++==++++++==+=++++++++++++++++++==+++=++======+++++++++====++++++++++++++++++++++++++++++++++++++++++=++++++++++=++++=+++++++=+==+=+===++===+=++++++++========++++++++++++++++++++++++*+ -----------------------=-============-------------=-=========-==============***#%%%%%%%%%%##%%%%%%%@%%%%%@%%%%%%%%@@@@@#++++#@%%#++#%@@%@@@@%#========++++=============++==++++===========+++++++++++=+====+====+====+++=++++++++++++++++=++++++++++++++++++++++++++++====+=+++++++++++++++++++++++++++++++++++++++++++++++==+==++++++++=+=+=++++++=+=+=+++===++===++++++++++++=++=+++++++++++++++++++++++++++++ ====----=--------------==--------==----=-------------=====---=-------------=**##%%%%%%%%%%%%%@@%%%%@@%%@%%%%%%%%%%%@@@@@@@##%%@#*++*@@@@@@@%%%=++=+===+===++============+======+++===+++===+++++++=======++++=+=+==+++++=+++++====+==+++++++++++++++++++++++++++++++++++++++++=++++++++++++++++++++++++++++++++++++++++++++++++++++======+++==++++++===+==++++=====+++++++++++++++++++++++++++==+++++++++++***++ -=-------=--------=---=====----------------------====-===-==================**@%%#%%%%%%%%%%%%%%%%%@@@%%%%%%%%%%%@@@@@@@@@@@@@@@@%%@@@@@@%%%%%+==+=++===+++=++++++++++++++++++++++++++++++++=++++++++++++++=======-=======================++=++++===++++++++++++++++++++++++=++++++++++++++++++++++++++++++++++=++++++++++++++++++++++++++++++=++++=+++====+=+++=++=+++=+++++++++++++++++++++++*++++**++++++*+** =====--==----==-=-:-==--======-=----=-==-===--==-------===--========-------***######%%%%%%%%%%%%%%%%@%@%@%%%%%%%%%%@%%%%@%@@@%@@@@@@@@@%%%%%%%#+==================+++=+==+++++++++++++++=+++=+=+++=+++=======+++=++==========++++++++==++=++=====+=+++++++++++++++++=+++++++++++=+=++++++++++++++=++++++++++++++=+=+=++++++++++++++++++++++++++++++++==========++++++===+++++++++++++++++++++*++++**++++++++++++ --=========------------=-==--=------==------------=---======-==-=========-=***#####%#%%%%%%%%%%%%%%%%#%%%%%%%%%%%%%@%%%%%%%%%%@%%@@@@%%%@%%%%%%#============-=======++++++++++++++++++++++++++++========+=++=+++++=+++++==++=+======+=+++=====+=====+++++===+=+++++=+=++++++++++=++++====++++===+======++++=+++++++++++++++++++++++++++++++++========++++++++++++===++++++++++++++++==+=++++++++++++++++++++++++ `; // 创建 Canvas 并绘制 ASCII 艺术 const asciiCanvas = document.createElement('canvas'); const asciiContext = asciiCanvas.getContext('2d'); // 设置字体和测量文本尺寸 const fontSize = 50; // 增大字体大小以使ASCII艺术更大 asciiContext.font = `${fontSize}px monospace`; asciiContext.fillStyle = 'lime'; // 字符颜色是亮绿色 asciiContext.textBaseline = 'top'; const lines = asciiArt.split('\n').filter(line => line.trim() !== ''); const lineHeight = fontSize * 1.2; // 行高 const canvasWidth = Math.max(...lines.map(line => asciiContext.measureText(line).width)) + 300; // 增加填充 const canvasHeight = lines.length * lineHeight + 300; // 增加填充 asciiCanvas.width = canvasWidth; asciiCanvas.height = canvasHeight; // 重新设置字体(因为 Canvas 尺寸变了,需要重设) asciiContext.font = `${fontSize}px monospace`; asciiContext.fillStyle = 'lime'; asciiContext.textBaseline = 'top'; // 绘制每一行文本 lines.forEach((line, index) => { asciiContext.fillText(line, 30, 30 + index * lineHeight); // 加上边距 }); // 创建纹理 const asciiTexture = new THREE.CanvasTexture(asciiCanvas); asciiTexture.minFilter = THREE.LinearFilter; asciiTexture.wrapS = THREE.ClampToEdgeWrapping; asciiTexture.wrapT = THREE.ClampToEdgeWrapping; // 创建材质 const asciiMaterial = new THREE.MeshStandardMaterial({ map: asciiTexture, transparent: true, emissive: new THREE.Color(0x00ff00), emissiveIntensity: 0.5 }); // 创建几何体(平面) const scaleFactor = 1.5; // 增大scaleFactor以使ASCII艺术更大 const asciiGeometry = new THREE.PlaneGeometry( (asciiCanvas.width * scaleFactor) / 100, (asciiCanvas.height * scaleFactor) / 100 ); // 创建网格并添加到场景 const asciiPlane = new THREE.Mesh(asciiGeometry, asciiMaterial); // 初始化 Three.js 场景 const scene = new THREE.Scene(); scene.add(asciiPlane); // 创建相机 const camera = new THREE.PerspectiveCamera(45, 1, 0.1, 1000); // aspect ratio 后面会设置 camera.position.set(0, 0, 30); // 调整相机位置 // 创建容器面板 const container = document.createElement('div'); // 初始容器大小基于视口大小的百分比 function calculateContainerSize() { const containerWidth = Math.min((asciiCanvas.width * scaleFactor) / 100 + 600, window.innerWidth * 0.8); // 增加填充 const containerHeight = Math.min((asciiCanvas.height * scaleFactor) / 100 + 800, window.innerHeight * 0.8); // 增加填充 return { width: containerWidth, height: containerHeight }; } let { width: containerWidth, height: containerHeight } = calculateContainerSize(); container.style.position = 'fixed'; container.style.bottom = '20px'; container.style.right = '20px'; container.style.width = `${containerWidth}px`; container.style.height = `${containerHeight}px`; container.style.backgroundColor = 'rgba(0, 0, 0, 0.5)'; // 透明背景,避免阻挡页面点击 container.style.border = 'none'; // 去掉边框 container.style.borderRadius = '8px'; container.style.zIndex = '10000'; container.style.boxShadow = '0 0 20px rgba(0,0,0,0.7)'; container.style.cursor = 'move'; container.style.overflow = 'hidden'; container.style.pointerEvents = 'auto'; // 确保容器可以接收事件 document.body.appendChild(container); // 创建渲染器 const renderer = new THREE.WebGLRenderer({ alpha: true, antialias: true }); renderer.setSize(containerWidth, containerHeight); // 设置渲染器的背景为半透明黑色 renderer.setClearColor(0x000000, 0.3); // 半透明背景 renderer.domElement.style.pointerEvents = 'auto'; // 允许渲染器接收事件 container.appendChild(renderer.domElement); // 添加 OrbitControls const controls = new THREE.OrbitControls(camera, renderer.domElement); controls.enableDamping = true; // 惯性 controls.dampingFactor = 0.05; controls.enableZoom = true; controls.enablePan = false; controls.minDistance = 5; // 调整最小缩放距离 controls.maxDistance = 200; // 增加最大缩放距离,允许用户进一步缩放 controls.update(); // 添加动态光照 const ambientLight = new THREE.AmbientLight(0xffffff, 0.5); scene.add(ambientLight); const pointLight = new THREE.PointLight(0xffffff, 1); pointLight.position.set(10, 10, 10); scene.add(pointLight); // 创建最小化按钮 const minimizeButton = document.createElement('button'); minimizeButton.innerHTML = '_'; // 简单的下划线表示最小化 minimizeButton.style.position = 'absolute'; minimizeButton.style.top = '10px'; minimizeButton.style.right = '10px'; minimizeButton.style.width = '30px'; minimizeButton.style.height = '30px'; minimizeButton.style.backgroundColor = 'rgba(255, 255, 255, 0.2)'; minimizeButton.style.border = 'none'; minimizeButton.style.borderRadius = '4px'; minimizeButton.style.color = 'white'; minimizeButton.style.fontSize = '20px'; minimizeButton.style.cursor = 'pointer'; minimizeButton.style.zIndex = '10001'; // 确保按钮在最前 container.appendChild(minimizeButton); // 创建一个用于包裹渲染器的内容容器 const contentContainer = document.createElement('div'); contentContainer.style.width = '100%'; contentContainer.style.height = '100%'; container.appendChild(contentContainer); // 将渲染器移动到内容容器中 contentContainer.appendChild(renderer.domElement); // 最小化状态变量 let isMinimized = false; // 最小化按钮点击事件 minimizeButton.addEventListener('click', () => { if (!isMinimized) { // 缩小面板 contentContainer.style.display = 'none'; container.style.height = '50px'; // 设置最小高度 minimizeButton.innerHTML = '+'; // 更改按钮符号为加号 isMinimized = true; } else { // 恢复面板 contentContainer.style.display = 'block'; const { width, height } = calculateContainerSize(); container.style.height = `${height}px`; minimizeButton.innerHTML = '_'; // 恢复按钮符号为下划线 isMinimized = false; } }); // 使容器可拖动 (function makeDraggable(el) { let isDragging = false; let startX, startY, initialX, initialY; el.addEventListener('mousedown', (e) => { if (e.target.tagName.toLowerCase() === 'canvas' || e.target === minimizeButton) return; // 避免拖动时与渲染器或按钮交互冲突 isDragging = true; startX = e.clientX; startY = e.clientY; // 获取当前的 right 和 bottom 值 const computedStyle = window.getComputedStyle(el); initialX = parseFloat(computedStyle.right); initialY = parseFloat(computedStyle.bottom); document.body.style.userSelect = 'none'; }); document.addEventListener('mousemove', (e) => { if (!isDragging) return; const dx = e.clientX - startX; const dy = e.clientY - startY; el.style.right = `${initialX - dx}px`; el.style.bottom = `${initialY + dy}px`; }); document.addEventListener('mouseup', () => { isDragging = false; document.body.style.userSelect = 'auto'; }); })(container); // 自动调整相机位置以适应 ASCII 艺术 function adjustCamera() { const boundingBox = new THREE.Box3().setFromObject(asciiPlane); const size = boundingBox.getSize(new THREE.Vector3()); const maxDim = Math.max(size.x, size.y); const fov = camera.fov * (Math.PI / 180); let cameraZ = Math.abs(maxDim / 2 / Math.tan(fov / 2)); camera.position.set(0, 0, cameraZ * 1.2); // 调整相机位置,使其稍微靠近 camera.lookAt(scene.position); controls.update(); } adjustCamera(); // 初始调整 // 创建粒子系统 const particleCount = 500; // 保持粒子数量适中以优化性能 const particlesGeometry = new THREE.BufferGeometry(); const particlePositions = []; const particleVelocities = []; for (let i = 0; i < particleCount; i++) { particlePositions.push( (Math.random() - 0.5) * 20, (Math.random() - 0.5) * 20, (Math.random() - 0.5) * 20 ); particleVelocities.push( (Math.random() - 0.5) * 0.02, (Math.random() - 0.5) * 0.02, (Math.random() - 0.5) * 0.02 ); } particlesGeometry.setAttribute('position', new THREE.Float32BufferAttribute(particlePositions, 3)); particlesGeometry.setAttribute('velocity', new THREE.Float32BufferAttribute(particleVelocities, 3)); const particlesMaterial = new THREE.PointsMaterial({ color: 0xffffff, size: 0.05, transparent: true, opacity: 0.7 }); const particleSystem = new THREE.Points(particlesGeometry, particlesMaterial); scene.add(particleSystem); // 动画循环 const clock = new THREE.Clock(); function animate() { requestAnimationFrame(animate); const elapsed = clock.getElapsedTime(); const delta = clock.getDelta(); controls.update(); // 更新控制器 // 更新粒子位置 const positions = particleSystem.geometry.attributes.position.array; for (let i = 0; i < particleCount; i++) { positions[i * 3] += particleSystem.geometry.attributes.velocity.array[i * 3]; positions[i * 3 + 1] += particleSystem.geometry.attributes.velocity.array[i * 3 + 1]; positions[i * 3 + 2] += particleSystem.geometry.attributes.velocity.array[i * 3 + 2]; // 反弹边界 if (positions[i * 3] > 10 || positions[i * 3] < -10) particleSystem.geometry.attributes.velocity.array[i * 3] *= -1; if (positions[i * 3 + 1] > 10 || positions[i * 3 + 1] < -10) particleSystem.geometry.attributes.velocity.array[i * 3 + 1] *= -1; if (positions[i * 3 + 2] > 10 || positions[i * 3 + 2] < -10) particleSystem.geometry.attributes.velocity.array[i * 3 + 2] *= -1; } particleSystem.geometry.attributes.position.needsUpdate = true; // 添加缓慢的持续旋转动画,仅在Y轴旋转 asciiPlane.rotation.y += 0.0005; // 更慢的旋转速度 // 移除X轴和Z轴的旋转 // asciiPlane.rotation.x += 0.0005; // asciiPlane.rotation.z += 0.0003; // 添加一些发光效果 asciiMaterial.emissiveIntensity = 0.5 + 0.5 * Math.sin(elapsed * 2); renderer.render(scene, camera); } animate(); // 更新容器大小和渲染器大小 function updateContainerSize() { const { width, height } = calculateContainerSize(); container.style.width = `${width}px`; container.style.height = `${height}px`; camera.aspect = width / height; camera.updateProjectionMatrix(); renderer.setSize(width, height); adjustCamera(); } // 窗口大小变化时调整相机和渲染器 window.addEventListener('resize', function(){ updateContainerSize(); }, false); })();