// ==UserScript==
// @name 链接助手
// @namespace https://github.com/oneNorth7
// @match *://*/*
// @version 1.2.9
// @author 一个北七
// @run-at document-end
// @description 常用网盘自动填写密码; 跳转页面自动跳转; 文本转链接; 净化跳转链接; 维基百科及镜像、Mozilla开发者自动切换中文(可控), 维基百科、谷歌开发者链接转为镜像链接; 新标签打开链接(可控)
// @license GPL-3.0 License
// @grant GM_registerMenuCommand
// @grant GM_unregisterMenuCommand
// @grant GM_notification
// @grant GM_info
// @grant GM_setValue
// @grant GM_getValue
// @noframes
// @icon https://raw.fastgit.org/oneNorth7/LinkHelper/main/asset/link-helper.png
// @created 2021/1/26 下午18:03:47
// @downloadURL none
// ==/UserScript==
!(function () {
// 显示消息通知
function showNotice(msg) {
GM_notification({
text: msg,
title: GM_info.script.name,
highlight: false,
silent: false,
timeout: 60,
});
}
let url_regexp = /((?:https?:\/\/|www\.)[\x21-\x7e]+[\w\/=]|\w(?:[\w._-])+@\w[\w\._-]+\.(?:com|cn|org|net|info|tv|cc|gov|edu)|(?:\w[\w._-]+\.(?:com|cn|org|net|info|tv|cc|gov|edu))(?:\/[\x21-\x7e]*[\w\/])?)/i;
// 网盘密码预处理
if (/http:\/\/www\.38hack\.com\/\d+\.html/.test(location.href)) {
// 爱之语
let lines = document.querySelectorAll("div.down-line");
if (lines.length)
lines[lines.length - 1].appendChild(
lines[0].previousElementSibling.previousElementSibling
);
} else if (/https:\/\/www\.mikuclub\.org\/\d+/.test(location.href)) {
// 初音社
let password = document.querySelector(".password1");
if (password)
document.querySelector("a.download").hash = password.value;
} else if (/https:\/\/www\.acggw\.com\/\d+\.html/.test(location.href)) {
// ACG港湾
let ps = document.querySelectorAll(".single-content>p"),
l = null,
m = null;
for (let p of ps) {
if (p.innerText.startsWith("链接:")) l = p;
if (l && p.innerText.startsWith("密码:"))
l.innerText += "#" + p.innerText.replace("密码:", "");
if (m && p.innerText.startsWith("国外M盘:"))
m.innerText += "#" + p.innerText.replace("国外M盘:", "");
if (p.innerText.startsWith("国外M盘:http")) m = p;
}
} else if (
/http:\/\/www\.olecn\.com\/download\.php\?id=\d+/.test(location.href)
) {
// 百度网盘资源
let lis = document.querySelectorAll("div.plus_l li");
let a = document.querySelector("div.panel-body a");
a.hash = lis[3].innerText.replace("网盘提取码 :", "");
} else if (
/https:\/\/www\.qiuziyuan\.net\/(?:pcrj\/|Android\/\d+\.html)/.test(
location.href
)
) {
// 求资源网
var filetit = document.querySelector("div.filetit");
for (var a of filetit.children) {
if (a.href) {
var result = url_regexp.exec(a.innerHTML);
if (result)
a.href = result[1].startsWith("http")
? result[1]
: "https://" + result[1];
}
if (
a.innerHTML.startsWith("90网盘:") ||
a.innerHTML.includes("90pan")
) {
var dom = filetit.nextElementSibling.nextElementSibling;
var result = /(?:90网盘:|\/\s*)(\d+)/.exec(dom.innerHTML);
if (result) a.href += "#" + result[1];
}
}
}
// 网盘自动填写密码
let YunDisk = {
sites: {
"pan.baidu.com": {
// 百度云
inputSelector: "#accessCode",
buttonSelector: "#submitBtn",
regStr: "[a-z\\d]{4}",
timeout: 0,
clickTimeout: 0,
},
"eyun.baidu.com": {
// 百度企业网盘
inputSelector: "input.share-access-code",
buttonSelector: "a.g-button",
regStr: "[a-z\\d]{4}",
timeout: 10,
clickTimeout: 10,
},
"cloud.189.cn": {
// 天翼云
inputSelector: "#code_txt",
buttonSelector: "a.btn-primary",
regStr: "[a-z\\d]{4}",
timeout: 10,
clickTimeout: 500,
},
"lanzou.com": {
// 蓝奏云
inputSelector: "#pwd",
buttonSelector: "#sub, .passwddiv-btn",
regStr: "[a-z\\d]{2,8}",
timeout: 10,
clickTimeout: 10,
},
"n802.com": {
// 城通网盘
inputSelector: "#passcode",
buttonSelector: "button.btn-primary",
regStr: "[a-z\\d]{4,6}",
timeout: 10,
clickTimeout: 500,
},
"306t.com": {
// 城通网盘
inputSelector: "#passcode",
buttonSelector: "button.btn-primary",
regStr: "[a-z\\d]{4,6}",
timeout: 10,
clickTimeout: 500,
},
"089u.com": {
// 城通网盘
inputSelector: "#passcode",
buttonSelector: "button.btn-primary",
regStr: "[a-z\\d]{4,6}",
timeout: 800,
clickTimeout: 500,
},
"ct.ghpym.com": {
// 果核城通网盘
inputSelector: "#passcode",
buttonSelector: "button.btn-primary",
regStr: "[a-z\\d]{4,6}",
timeout: 500,
clickTimeout: 500,
},
"474b.com": {
// 爱之语城通网盘
inputSelector: "#passcode",
buttonSelector: "button.btn-primary",
regStr: "[a-z\\d]{4,6}",
timeout: 500,
clickTimeout: 500,
},
"590m.com": {
// 小众软件城通网盘
inputSelector: "#passcode",
buttonSelector: "button.btn-primary",
regStr: "[a-z\\d]{4,6}",
timeout: 500,
clickTimeout: 500,
},
"www.90pan.com": {
// 90网盘
inputSelector: "#code",
buttonSelector: "button.btn-info",
regStr: "[a-z\\d]{4, 6}",
timeout: 10,
clickTimeout: 500,
},
"vdisk.weibo.com": {
// 微盘
inputSelector: "#keypass",
buttonSelector: "div.search_btn_wrap>a",
regStr: "[a-z\\d]{4}",
timeout: 100,
clickTimeout: 10,
},
"pan.xunlei.com": {
// 迅雷云盘
inputSelector: "input.td-input__inner",
buttonSelector: "button.td-button",
regStr: "[a-z\\d]{4}",
timeout: 1500,
clickTimeout: 10,
store: true,
inputEvent: true,
},
"share.weiyun.com": {
// 微云
inputSelector: "input.input-txt",
buttonSelector: "button.btn-main",
regStr: "[a-z\\d]{4,6}",
timeout: 1000,
clickTimeout: 10,
inputEvent: true,
},
"115.com": {
// 115网盘
inputSelector: "input.text",
buttonSelector: "a.btn-large",
regStr: "[a-z\\d]{4}",
timeout: 500,
clickTimeout: 10,
inputEvent: true,
},
"quqi.com": {
// 曲奇云
inputSelector: "div.webix_el_box>input",
buttonSelector: "button.webixtype_base",
regStr: "[a-z\\d]{6}",
timeout: 600,
clickTimeout: 10,
},
"caiyun.139.com": {
// 和彩云
inputSelector: "input",
buttonSelector: "a.btn-token",
regStr: "[a-z\\d]{4}",
timeout: 500,
clickTimeout: 10,
inputEvent: true,
store: true,
},
"mo.own-cloud.cn": {
// 小麦魔方
inputSelector: "#pwd",
buttonSelector: "button.MuiButton-root",
regStr: "[a-z\\d]{4,8}",
timeout: 500,
clickTimeout: 10,
store: true,
react: true,
},
"cloud.qingstore.cn": {
// 清玖云
inputSelector: "#pwd",
buttonSelector: "button.MuiButton-root",
regStr: "[a-z\\d]{4}",
timeout: 500,
clickTimeout: 10,
store: true,
react: true,
},
"pan.mebk.org": {
// 马恩资料库云盘
inputSelector: "#pwd",
buttonSelector: "button.MuiButton-root",
regStr: "[a-z\\d]{6}",
timeout: 500,
clickTimeout: 10,
store: true,
react: true,
},
"mega.nz": {
regExp: /^[a-z\d\-_]{22}$/i,
},
},
// 自动填写密码并点击跳转
autoFill: function (host) {
let site = this.sites[host];
if (site.inputSelector) {
setTimeout(function () {
let input = document.querySelector(site.inputSelector);
let button = document.querySelector(site.buttonSelector);
let code = null;
if (input) {
if (site.store) code = GM_getValue(host);
else code = location.hash.slice(1);
if (code) {
let regExp = new RegExp(
"^" + site.regStr + "$",
"i"
);
if (regExp.test(code)) {
if (site.inputEvent) {
let t = setInterval(function () {
input.focus();
input.value = code;
if (input.value !== "") {
if (
typeof InputEvent !==
"undefined"
) {
//使用 InputEvent 方法,主流浏览器兼容
input.dispatchEvent(
new InputEvent("input")
); //模拟事件
} else if (KeyboardEvent) {
//使用 KeyboardEvent 方法,ES6以下的浏览器方法
input.dispatchEvent(
new KeyboardEvent("input")
);
}
clearInterval(t);
input.blur();
button.dispatchEvent(
new MouseEvent("click")
);
}
}, 1000);
} else if (site.react) {
let event = new Event("input", {
bubbles: true,
});
let lastValue = input.value;
input.value = code;
let tracker = input._valueTracker;
if (tracker) tracker.setValue(lastValue);
input.dispatchEvent(event);
setTimeout(
() => button.click(),
site.clickTimeout
);
} else {
input.value = code;
setTimeout(
() => button.click(),
site.clickTimeout
);
}
} else console.log("未找到提取码!");
} else console.log("无需提取码!");
} else console.log(`input: ${input}`); // showNotice(`input: ${input}`);
}, site.timeout);
}
},
// 映射域名
mapHost: function (host) {
return host
.replace(/.*lanzou[isx]?.com/, "lanzou.com")
.replace(/quqi\.\w+\.com/, "quqi.com");
},
addCode2: function (a) {
let site = this.sites[this.mapHost(a.host)];
let regExp = new RegExp("^" + site.regStr + "$", "i");
if (!regExp.test(a.hash.slice(1))) {
// let reg = new RegExp( "(?:提[取示]|访问|查阅|密\\s*|艾|Extracted-code|\\skey)[码碼]?\\s*[:: ((]?\\s*(" + site.regStr + ")|^\\s*[:: ((]?\\s*(" + site.regStr + ")$", "i" );
let reg = new RegExp(
"\\s*(?:提[取示]|访问|查阅|密\\s*|艾|Extracted-code|key|password)[码碼]?\\s*[:: ((]?\\s*(" +
site.regStr +
")|^\\s*[::【\\[ ((]?\\s*(" +
site.regStr +
")[】\\]]?$",
"i"
);
let code = reg.exec(a.textContent);
for (
let i = 10, current = a;
!code && i > 0;
i--, current = current.parentElement
) {
let next = current;
while (!code) {
console.log(next);
next = next.nextSibling;
if (!next || next.href) break;
else code = reg.exec(next.textContent);
}
}
let store = this.sites[this.mapHost(a.host)].store;
if (code) {
let c = code[1] || code[2];
if (store) GM_setValue(this.mapHost(a.host), c);
else if (location.host.includes("zhihu.com")) {
let span = document.createElement("span");
span.classList.add("invisible");
span.innerText = "#" + c;
a.appendChild(span);
} else a.hash = c;
} else {
if (store) GM_deleteValue(this.mapHost(a.host));
console.log("找不到code!");
}
}
},
};
let dealedHost = YunDisk.mapHost(location.host);
if (YunDisk.sites[dealedHost]) YunDisk.autoFill(dealedHost);
else {
let RedirectPage = {
sites: {
"show.bookmarkearth.com": {
// 书签地球
include: "http://show.bookmarkearth.com/view/",
selector: "a.open-in-new-window",
},
"t.cn": {
// 微博
include: "http://t.cn/",
selector: "a.m-btn-orange",
},
"sunbox.cc": {
// 阳光盒子
include:
"https://sunbox.cc/wp-content/themes/begin/go.php?url=",
selector: "a.alert-btn",
},
"www.itdaan.com": {
// 开发者知识库
include: "https://www.itdaan.com/link/",
selector: "a.c-footer-a1",
},
},
// 获取真实链接并跳转
redirect: function (host) {
let site = this.sites[host];
let node = document.querySelector(site.selector);
if (node) location.href = node.href;
},
// 维基百科及镜像
wiki: function () {
let isZh = location.host.includes("zh");
let jumpToZh = GM_getValue("jumpToZh", true);
let a = document.querySelector(
'a.interlanguage-link-target[lang="zh"]'
);
let lastHref = null;
if (!isZh) {
lastHref = location.href;
if (jumpToZh) {
history.pushState(null, null, lastHref);
if (a) location.href = a.href;
else showNotice("没有找到中文页面!"); // console.log("没有找到中文页面!");
}
}
// 注册菜单项控制是否自动切换中文
let menuID = GM_registerMenuCommand(
`${jumpToZh ? "[✔]" : "[✖]"}自动切换中文`,
autoJump
);
function autoJump() {
jumpToZh = !jumpToZh;
GM_setValue("jumpToZh", jumpToZh);
GM_unregisterMenuCommand(menuID);
menuID = GM_registerMenuCommand(
`${jumpToZh ? "[✔]" : "[✖]"}自动切换中文`,
autoJump
);
if (!isZh && jumpToZh) {
if (a) location.href = a.href;
else showNotice("没有找到中文页面!");
} else history.back();
}
},
// Mozilla开发者页面
mozilla: function () {
let isZh = location.pathname.includes("zh-CN");
let jumpToZh = GM_getValue("jumpToZh", true),
lastHref = null;
let options = document.querySelectorAll(
"#select_language>option,#language-selector>option"
);
if (!isZh) {
if (jumpToZh) {
for (let i = options.length - 1; i > 0; i--) {
if (options[i].value.startsWith("/zh-CN")) {
lastHref = options[i].value;
break;
}
}
if (lastHref) {
location.href = lastHref;
} else showNotice("没有找到中文页面!");
}
}
// 注册菜单项控制是否自动切换中文
let menuID = GM_registerMenuCommand(
`${jumpToZh ? "[✔]" : "[✖]"}自动切换中文`,
autoJump
);
function autoJump() {
jumpToZh = !jumpToZh;
GM_setValue("jumpToZh", jumpToZh);
GM_unregisterMenuCommand(menuID);
menuID = GM_registerMenuCommand(
`${jumpToZh ? "[✔]" : "[✖]"}自动切换中文`,
autoJump
);
if (!isZh && jumpToZh) {
for (let i = options.length - 1; i > 0; i--) {
if (
((lastHref = options[i].value),
lastHref.startsWith("/zh-CN"))
)
break;
}
if (lastHref) location.href = lastHref;
else showNotice("没有找到中文页面!");
} else history.back();
}
},
};
// 跳转页面
if (RedirectPage.sites[location.host])
RedirectPage.redirect(location.host);
// 维基百科及镜像页面
else if (location.host.match(/.+wiki(?:\.sxisa|pedia)\.org/))
RedirectPage["wiki"]();
// 点击元素(文本或链接)
else {
// Mozilla开发者页面
if (location.host == "developer.mozilla.org")
RedirectPage["mozilla"]();
// 页面监听
document.addEventListener("mouseup", function (clickObj) {
let e = clickObj.target ?? clickObj.originalTarget,
isTextToLink;
if (e && !e.href) {
// 非链接
let flag = true,
selectNode = null;
for (
let current = e, limit = 5;
current.localName !== "body" && limit > 0;
current = current.parentElement, limit--
) {
if (current.localName === "a") {
e = current;
break;
} else if (
["code", "pre"].some(
(tag) => tag === current.localName
)
) {
// 代码块
let selection = getSelection(),
text = selection.toString();
if (url_regexp.test(text))
selectNode =
selection.anchorNode || selection.focusNode;
else flag = false;
break;
}
}
if (e.localName !== "a" && flag) {
let node =
selectNode || clickObj.explicitOriginalTarget;
if (node.nodeValue) e = text2Links(node);
else e = textToLink(e);
if (e) isTextToLink = true;
}
}
if (e && e.localName === "a") {
// 链接
let a = e;
if (location.href.includes("mod.3dmgame.com/mod/")) {
// mod.3dmgame.com
a.search = "3dmgame.com";
}
if (isLinkText(a)) {
// 链接文本为真实链接
if (url_regexp.test(a.innerText))
a.href = a.innerText.startsWith("http")
? a.innerText
: "https://" + a.innerText;
}
// 含真实链接的跳转链接
cleanRedirectLink(a);
if (a.host.includes("wikipedia.org")) {
// 维基百科
a.href = a.href.replace(
"wikipedia.org",
"wiki.sxisa.org"
);
} else if (a.host.includes("developers.google.com")) {
// 谷歌开发者
a.href = a.href.replace(
"developers.google.com",
"developers.google.cn"
);
} else if (YunDisk.sites[YunDisk.mapHost(a.host)]) {
// 网盘
YunDisk.addCode2(a);
if (isTextToLink) a.click();
}
add_blank(a);
}
});
// 文本字数限制
let textLength = GM_getValue("textLength", 200);
// 注册菜单项限制文本字数
/*let menuID = GM_registerMenuCommand(`设置文本字数限制(${textLength})`, limitText);
function limitText() {
let input = prompt("请输入文本字数限制: ", GM_getValue("textLength", 200));
if (+input) {
GM_setValue("textLength", +input);
GM_unregisterMenuCommand(menuID);
menuID = GM_registerMenuCommand(`设置文本字数限制(${+input})`, limitText);
}
}*/
// 文本转链接
function textToLink(e) {
if (
!["body", "code", "pre"].some(
(tag) => tag === e.localName
) &&
!["www.google"].some((h) => location.host.includes(h))
) {
let span = null,
count = 0;
for (
let i = e.childNodes.length - 1, limit = 10;
i >= 0 && limit > 0;
i--
) {
let child = e.childNodes[i];
if (
!["a", "br", "code", "pre", "img", "script"].some(
(tag) => tag === child.localName
) && // 剔除遍历节点类型
child.className !== "textToLink" &&
child.textContent.length < textLength
) {
// 限制文本字数
let result = url_regexp.exec(child.textContent);
if (result && !result[0].includes("@")) {
span = document.createElement("span");
span.className = "textToLink";
span.innerHTML = child.textContent.replace(
url_regexp,
result[0].startsWith("http")
? '$1'
: '$1'
);
child.parentNode.replaceChild(span, child);
count++;
}
limit--;
}
}
return count == 1 && span && span.firstElementChild;
}
}
function text2Link(node) {
let result = url_regexp.exec(node.nodeValue),
span = null;
if (result && !result[0].includes("@")) {
span = document.createElement("span");
span.className = "textToLink";
span.innerHTML = node.nodeValue.replace(
url_regexp,
result[0].startsWith("http")
? '$1'
: '$1'
);
node.parentNode.replaceChild(span, node);
}
return span && span.firstElementChild;
}
function text2Links(node) {
if (node.nodeValue.length < textLength) {
let url_regexp_g = new RegExp(
"\\b(" +
"https?:\\/\\/[^\\s+\"\\'<>,\\[\\]():\\*\\u4E00-\\u9FFF]+" +
"|" +
"ed2k:\\/\\/\\|file\\|[^\\|]+\\|\\d+\\|\\w{32}\\|(?:h=\\w{32}\\|)?\\/" +
"|" +
"magnet:\\?xt=urn:btih:\\w{40}(&[\\w\\s]+)?" +
")",
"ig"
);
let result = url_regexp_g.exec(node.nodeValue),
span = null,
count = 0;
if (result && !result[0].includes("@")) {
// console.log(result);
span = document.createElement("span");
span.className = "textToLink";
span.innerHTML = node.nodeValue.replace(
url_regexp_g,
function ($1) {
count++;
return $1.startsWith("http") ||
$1.includes("magnet") ||
$1.includes("ed2k")
? `${$1}`
: `${$1}`;
}
);
node.parentNode.replaceChild(span, node);
}
// console.log(count);
return count == 1 && span && span.firstElementChild;
}
}
// 链接文本为真实链接
function isLinkText(a) {
let keywords = [
"www.sunweihu.com/go/?url=",
"jump.bdimg.com/safecheck/index?url=",
"jump2.bdimg.com/safecheck/index?url=",
"zhouxiaoben.info/wp-content/themes/begin/go.php?url=",
];
return keywords.some((k) => a.href.includes(k));
}
let excludeSites = GM_getValue("excludeSites", [
"v.qq.com",
"v.youku.com",
"blog.csdn.net",
"cloud.tencent.com",
"translate.google.com",
"domains.live.com",
"passport.yandex.ru",
"www.iconfont.cn",
"baike.sogou.com",
"www.kdocs.cn",
"help.aliyun.com",
"cn.bing.com",
"service.weibo.com",
]);
// 注册菜单项添加例外域名
GM_registerMenuCommand("添加例外域名", addExcludeSite);
// 添加例外域名
function addExcludeSite() {
let input = prompt(
"输入的域名下的链接不会被净化: ",
location.host
);
if (input) {
if (/[\w]+(\.[\w]+)+/.test(input)) {
if (!excludeSites.some((s) => s.includes(input))) {
excludeSites.push(input);
GM_setValue("excludeSites", excludeSites);
} else showNotice(`例外域名 <${input}> 已存在!!!`);
} else showNotice(`<${input}> 不是有效域名!!!`);
}
}
function cleanRedirectLink(a) {
// 净化跳转链接
let reg = /((?:http|https|\/|\%2F).*?\?.+?=)((?:http|\/|\%2F).+|([\w]+(?:(?:\.|%2E)[\w]+)+))/;
let result = reg.exec(a.href);
if (result) {
let temp = decodeURIComponent(
decodeURIComponent(result[2])
);
if (
!(
decodeURIComponent(location.href).includes(
temp.split("&")[0]
) ||
(result[3] && result[3].includes(location.host)) ||
excludeSites.some((s) => result[1].includes(s)) ||
YunDisk.sites[YunDisk.mapHost(a.host)]
)
) {
let href = decodeURIComponent(
decodeURIComponent(
result[3]
? "http://" + result[3]
: result[2].startsWith("http")
? result[2]
: location.origin + result[2]
)
);
if (a.title)
a.title += "\n" + decodeURIComponent(a.href);
else a.title = decodeURIComponent(a.href);
a.href = href;
}
}
}
let defaultTargetSites = GM_getValue("defaultTargetSites", []);
let isAddBlank = GM_getValue("isAddBlank", false);
let isDefault = defaultTargetSites.some((s) => s == location.host);
// 注册菜单项该站链接保持默认打开方式
if (!isDefault) {
let menuID2 = GM_registerMenuCommand(
"该站链接保持默认打开方式",
function () {
defaultTargetSites.push(location.host);
GM_setValue("defaultTargetSites", defaultTargetSites);
isDefault = defaultTargetSites.some(
(s) => s == location.host
);
GM_unregisterMenuCommand(menuID2);
GM_unregisterMenuCommand(menuID);
}
);
// 注册菜单项启停在新标签打开链接
let menuID = GM_registerMenuCommand(
`${isAddBlank ? "[✔]" : "[✖]"}在新标签打开链接`,
addBlank
);
// 启停在新标签打开链接
function addBlank() {
isAddBlank = !isAddBlank;
GM_setValue("isAddBlank", isAddBlank);
GM_unregisterMenuCommand(menuID);
menuID = GM_registerMenuCommand(
`${isAddBlank ? "[✔]" : "[✖]"}在新标签打开链接`,
addBlank
);
}
}
// 给链接添加[target="_blank"]属性
function add_blank(a) {
if (isAddBlank && !isDefault) {
let result =
a.target == "_blank" ||
/javascript[\w:;()]+/.test(a.href) ||
/\/\w+-\d+-\d+\.html|.+page\/\d+|category-\d+_?\d*/.test(
a.href
) ||
/[前后上下首末].+[页篇张]|^\.*\s*\d+\s*\.*$|^next$|^previous$/i.test(
a.innerText
) ||
["prev", "next"].some(
(r) => r == a.attributes.rel?.nodeValue
) ||
["prev", "next", "nxt"].some((r) =>
a.className.includes(r)
) ||
(/thread-\d+-\d+-\d+/.test(a.href)
? a.attributes.href.nodeValue.startsWith("#")
: !/^(?:http|\/\/).+/.test(
a.attributes.href.nodeValue
)) ||
a.href == location.origin + "/" ||
a.href.endsWith(".user.js");
// 移除论坛帖子链接的点击事件
if (/thread-\d+-\d+-\d+/.test(a.href)) a.onclick = null;
if (!result) a.target = "_blank";
}
}
}
}
})();