mirror of
https://github.com/Mabbs/mabbs.github.io
synced 2026-10-03 11:17:21 +00:00
Compare commits
48
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b8b29f86d5 | ||
|
|
0e4e4d2fb7 | ||
|
|
7943cc7d6a | ||
|
|
772e3ed0b7 | ||
|
|
ee4c9acfde | ||
|
|
2acc1f6fd7 | ||
|
|
5f2a3a99ee | ||
|
|
36cf19d4aa | ||
|
|
9c769e4ab2 | ||
|
|
fd5f1703dd | ||
|
|
2a512a487d | ||
|
|
556e27c9ad | ||
|
|
5a4baf5f4b | ||
|
|
71d493c2a8 | ||
|
|
156f964333 | ||
|
|
481df19596 | ||
|
|
1a529143a8 | ||
|
|
b25a864ee3 | ||
|
|
c5ad917d9e | ||
|
|
d6274791a8 | ||
|
|
111dc1e25f | ||
|
|
c4ae25dcb1 | ||
|
|
862bffac80 | ||
|
|
c888a89f41 | ||
|
|
b48e93890c | ||
|
|
f6b35814b1 | ||
|
|
fe26e4f6c3 | ||
|
|
45f1183f9a | ||
|
|
dd1141d872 | ||
|
|
c0ca105edc | ||
|
|
bc45ef27b8 | ||
|
|
47f623b8eb | ||
|
|
33122e34b5 | ||
|
|
100d3405f7 | ||
|
|
a7ff7c2c37 | ||
|
|
47e04279d0 | ||
|
|
cd478c22a2 | ||
|
|
e094b6d205 | ||
|
|
e8653b0efd | ||
|
|
e516a5d08c | ||
|
|
cf76264bb0 | ||
|
|
0a7608b3f0 | ||
|
|
5fd8d2fe0f | ||
|
|
c9dfb10733 | ||
|
|
23fff44d79 | ||
|
|
6630ba964b | ||
|
|
00aec9bad0 | ||
|
|
2ab6982684 |
No files matched your search
@@ -22,6 +22,8 @@ if (!norunFlag) {
|
||||
var sleepTimer_ = null;
|
||||
var AITalkFlag = false;
|
||||
var talkNum = 0;
|
||||
// 暴露到全局,供 pjax.js 在页面切换后重新调用
|
||||
window._live2d = { initTips: null, showMessage: null, showHitokoto: null };
|
||||
(function () {
|
||||
function renderTip(template, context) {
|
||||
var tokenReg = /(\\)?\{([^\{\}\\]+)(\\)?\}/g;
|
||||
@@ -33,11 +35,11 @@ if (!norunFlag) {
|
||||
var currentObject = context;
|
||||
var i, length, variable;
|
||||
for (i = 0, length = variables.length; i < length; ++i) {
|
||||
variable = variables[i];
|
||||
currentObject = currentObject[variable];
|
||||
if (currentObject === undefined || currentObject === null) return '';
|
||||
variable = currentObject[variables[i]];
|
||||
if (variable === undefined || variable === null) return '';
|
||||
currentObject = variable;
|
||||
}
|
||||
return currentObject;
|
||||
return String(currentObject);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -56,14 +58,20 @@ if (!norunFlag) {
|
||||
showMessage('你都复制了些什么呀,转载要记得加上出处哦~~', 5000);
|
||||
});
|
||||
|
||||
// 缓存 message.json 数据,供 PJAX 重绑定使用
|
||||
var tipsData = null;
|
||||
|
||||
function initTips() {
|
||||
$.ajax({
|
||||
cache: true,
|
||||
url: message_Path + 'message.json',
|
||||
dataType: "json",
|
||||
success: function (result) {
|
||||
tipsData = result;
|
||||
// 解绑旧事件(用命名空间避免影响其他绑定)
|
||||
$.each(result.mouseover, function (index, tips) {
|
||||
$(tips.selector).mouseover(function () {
|
||||
$(tips.selector).off('mouseover._live2d_tips mouseout._live2d_tips');
|
||||
$(tips.selector).on('mouseover._live2d_tips', function () {
|
||||
var text = tips.text;
|
||||
if (Array.isArray(tips.text)) text = tips.text[Math.floor(Math.random() * tips.text.length + 1) - 1];
|
||||
text = text.renderTip({ text: $(this).text() });
|
||||
@@ -72,7 +80,7 @@ if (!norunFlag) {
|
||||
clearInterval(liveTlakTimer);
|
||||
liveTlakTimer = null;
|
||||
});
|
||||
$(tips.selector).mouseout(function () {
|
||||
$(tips.selector).on('mouseout._live2d_tips', function () {
|
||||
showHitokoto();
|
||||
if (liveTlakTimer == null) {
|
||||
liveTlakTimer = window.setInterval(function () {
|
||||
@@ -82,7 +90,8 @@ if (!norunFlag) {
|
||||
});
|
||||
});
|
||||
$.each(result.click, function (index, tips) {
|
||||
$(tips.selector).click(function () {
|
||||
$(tips.selector).off('click._live2d_tips');
|
||||
$(tips.selector).on('click._live2d_tips', function () {
|
||||
if (hitFlag) {
|
||||
return false
|
||||
}
|
||||
@@ -106,46 +115,22 @@ if (!norunFlag) {
|
||||
}
|
||||
});
|
||||
}
|
||||
window._live2d.initTips = initTips;
|
||||
initTips();
|
||||
|
||||
var text;
|
||||
if (document.referrer !== '' && document.referrer.split('/')[2] !== window.location.host) {
|
||||
var referrer = document.createElement('a');
|
||||
referrer.href = document.referrer;
|
||||
text = '嗨!来自 <span style="color:#0099cc;">' + referrer.hostname + '</span> 的朋友!';
|
||||
var domain = referrer.hostname.split('.')[1];
|
||||
if (domain == 'baidu') {
|
||||
text = '嗨! 来自 百度搜索 的朋友!<br>欢迎访问<span style="color:#0099cc;">「 ' + document.title.split(' | ')[0] + ' 」</span>';
|
||||
} else if (domain == 'so') {
|
||||
text = '嗨! 来自 360搜索 的朋友!<br>欢迎访问<span style="color:#0099cc;">「 ' + document.title.split(' | ')[0] + ' 」</span>';
|
||||
} else if (domain == 'google') {
|
||||
text = '嗨! 来自 谷歌搜索 的朋友!<br>欢迎访问<span style="color:#0099cc;">「 ' + document.title.split(' | ')[0] + ' 」</span>';
|
||||
if (domain == 'baidu' || domain == 'so' || domain == 'google') {
|
||||
var source = domain == 'baidu' ? '百度搜索' : domain == 'so' ? '360搜索' : '谷歌搜索';
|
||||
text = '嗨! 来自 ' + source + ' 的朋友!<br>欢迎访问<span style="color:#0099cc;">「 ' + document.title.split(' | ')[0] + ' 」</span>';
|
||||
} else {
|
||||
text = '嗨!来自 <span style="color:#0099cc;">' + referrer.hostname + '</span> 的朋友!';
|
||||
}
|
||||
} else {
|
||||
if (window.location.pathname == "/") { //主页URL判断,需要斜杠结尾
|
||||
var now = (new Date()).getHours();
|
||||
if (now > 23 || now <= 5) {
|
||||
text = '你是夜猫子呀?这么晚还不睡觉,明天起的来嘛?';
|
||||
} else if (now > 5 && now <= 7) {
|
||||
text = '早上好!一日之计在于晨,美好的一天就要开始了!';
|
||||
} else if (now > 7 && now <= 11) {
|
||||
text = '上午好!工作顺利嘛,不要久坐,多起来走动走动哦!';
|
||||
} else if (now > 11 && now <= 14) {
|
||||
text = '中午了,工作了一个上午,现在是午餐时间!';
|
||||
} else if (now > 14 && now <= 17) {
|
||||
text = '午后很容易犯困呢,今天的运动目标完成了吗?';
|
||||
} else if (now > 17 && now <= 19) {
|
||||
text = '傍晚了!窗外夕阳的景色很美丽呢,最美不过夕阳红~~';
|
||||
} else if (now > 19 && now <= 21) {
|
||||
text = '晚上好,今天过得怎么样?';
|
||||
} else if (now > 21 && now <= 23) {
|
||||
text = '已经这么晚了呀,早点休息吧,晚安~~';
|
||||
} else {
|
||||
text = '嗨~ 快来逗我玩吧!';
|
||||
}
|
||||
} else {
|
||||
text = '欢迎阅读<span style="color:#0099cc;">「 ' + document.title.split(' | ')[0] + ' 」</span>';
|
||||
}
|
||||
text = getWelcomeText();
|
||||
}
|
||||
showMessage(text, 12000);
|
||||
})();
|
||||
@@ -172,6 +157,7 @@ if (!norunFlag) {
|
||||
console.log(sleepTimer_);
|
||||
}
|
||||
}
|
||||
window._live2d.showHitokoto = showHitokoto;
|
||||
|
||||
function checkSleep() {
|
||||
var sleepStatu = sessionStorage.getItem("Sleepy");
|
||||
@@ -213,6 +199,7 @@ if (!norunFlag) {
|
||||
//if (timeout === null) timeout = 5000;
|
||||
//hideMessage(timeout);
|
||||
}
|
||||
window._live2d.showMessage = showMessage;
|
||||
function talkValTimer() {
|
||||
$('#live_talk').val('1');
|
||||
}
|
||||
@@ -384,74 +371,100 @@ if (!norunFlag) {
|
||||
};
|
||||
};
|
||||
//获取音乐信息初始化
|
||||
var bgmListInfo = $('input[name=live2dBGM]');
|
||||
if (bgmListInfo.length == 0) {
|
||||
$('#musicButton').hide();
|
||||
} else {
|
||||
var bgmPlayNow = parseInt($('#live2d_bgm').attr('data-bgm'));
|
||||
var bgmPlayTime = 0;
|
||||
var live2dBGM_Num = sessionStorage.getItem("live2dBGM_Num");
|
||||
var live2dBGM_PlayTime = sessionStorage.getItem("live2dBGM_PlayTime");
|
||||
if (live2dBGM_Num) {
|
||||
if (live2dBGM_Num <= $('input[name=live2dBGM]').length - 1) {
|
||||
bgmPlayNow = parseInt(live2dBGM_Num);
|
||||
}
|
||||
}
|
||||
if (live2dBGM_PlayTime) {
|
||||
bgmPlayTime = parseInt(live2dBGM_PlayTime);
|
||||
}
|
||||
var live2dBGMSrc = bgmListInfo.eq(bgmPlayNow).val();
|
||||
$('#live2d_bgm').attr('data-bgm', bgmPlayNow);
|
||||
$('#live2d_bgm').attr('src', live2dBGMSrc);
|
||||
$('#live2d_bgm')[0].currentTime = bgmPlayTime;
|
||||
$('#live2d_bgm')[0].volume = 0.5;
|
||||
var live2dBGM_IsPlay = sessionStorage.getItem("live2dBGM_IsPlay");
|
||||
var live2dBGM_WindowClose = sessionStorage.getItem("live2dBGM_WindowClose");
|
||||
if (live2dBGM_IsPlay == '0' && live2dBGM_WindowClose == '0') {
|
||||
$('#live2d_bgm')[0].play();
|
||||
var $bgm = $('#live2d_bgm');
|
||||
|
||||
// 音乐按钮点击事件(幂等,使用命名空间避免重复绑定)
|
||||
$('#musicButton').off('click._bgm').on('click._bgm', function () {
|
||||
if ($('#musicButton').hasClass('play')) {
|
||||
$bgm[0].pause();
|
||||
$('#musicButton').removeClass('play');
|
||||
sessionStorage.setItem("live2dBGM_IsPlay", '1');
|
||||
} else {
|
||||
$bgm[0].play();
|
||||
$('#musicButton').addClass('play');
|
||||
sessionStorage.setItem("live2dBGM_IsPlay", '0');
|
||||
}
|
||||
sessionStorage.setItem("live2dBGM_WindowClose", '1');
|
||||
$('#musicButton').on('click', function () {
|
||||
if ($('#musicButton').hasClass('play')) {
|
||||
$('#live2d_bgm')[0].pause();
|
||||
$('#musicButton').removeClass('play');
|
||||
sessionStorage.setItem("live2dBGM_IsPlay", '1');
|
||||
} else {
|
||||
$('#live2d_bgm')[0].play();
|
||||
$('#musicButton').addClass('play');
|
||||
sessionStorage.setItem("live2dBGM_IsPlay", '0');
|
||||
});
|
||||
|
||||
// BGM 事件监听(仅绑定一次,使用标志位避免重复)
|
||||
if (!window._live2d._bgmEventsBound) {
|
||||
$bgm[0].addEventListener("timeupdate", function () {
|
||||
sessionStorage.setItem("live2dBGM_PlayTime", $bgm[0].currentTime);
|
||||
});
|
||||
$bgm[0].addEventListener("ended", function () {
|
||||
var listNow = parseInt($bgm.attr('data-bgm'));
|
||||
listNow++;
|
||||
var inputs = $('input[name=live2dBGM]');
|
||||
if (inputs.length === 0) return;
|
||||
if (listNow > inputs.length - 1) {
|
||||
listNow = 0;
|
||||
}
|
||||
var listNewSrc = inputs.eq(listNow).val();
|
||||
if (!listNewSrc) return;
|
||||
sessionStorage.setItem("live2dBGM_Num", listNow);
|
||||
$bgm.attr('src', listNewSrc);
|
||||
$bgm[0].play();
|
||||
$bgm.attr('data-bgm', listNow);
|
||||
});
|
||||
$bgm[0].addEventListener("error", function () {
|
||||
$bgm[0].pause();
|
||||
$('#musicButton').removeClass('play');
|
||||
showMessage('音乐似乎加载不出来了呢!', 0);
|
||||
});
|
||||
window.onbeforeunload = function () {
|
||||
sessionStorage.setItem("live2dBGM_WindowClose", '0');
|
||||
if ($('#musicButton').hasClass('play')) {
|
||||
sessionStorage.setItem("live2dBGM_IsPlay", '0');
|
||||
}
|
||||
}
|
||||
document.getElementById('live2d_bgm').addEventListener("timeupdate", function () {
|
||||
var live2dBgmPlayTimeNow = document.getElementById('live2d_bgm').currentTime;
|
||||
sessionStorage.setItem("live2dBGM_PlayTime", live2dBgmPlayTimeNow);
|
||||
});
|
||||
document.getElementById('live2d_bgm').addEventListener("ended", function () {
|
||||
var listNow = parseInt($('#live2d_bgm').attr('data-bgm'));
|
||||
listNow++;
|
||||
if (listNow > $('input[name=live2dBGM]').length - 1) {
|
||||
listNow = 0;
|
||||
}
|
||||
var listNewSrc = $('input[name=live2dBGM]').eq(listNow).val();
|
||||
sessionStorage.setItem("live2dBGM_Num", listNow);
|
||||
$('#live2d_bgm').attr('src', listNewSrc);
|
||||
$('#live2d_bgm')[0].play();
|
||||
$('#live2d_bgm').attr('data-bgm', listNow);
|
||||
});
|
||||
document.getElementById('live2d_bgm').addEventListener("error", function () {
|
||||
$('#live2d_bgm')[0].pause();
|
||||
$('#musicButton').removeClass('play');
|
||||
showMessage('音乐似乎加载不出来了呢!', 0);
|
||||
});
|
||||
};
|
||||
window._live2d._bgmEventsBound = true;
|
||||
}
|
||||
|
||||
// 初始化 BGM(根据当前页面是否有 BGM 输入)
|
||||
if (typeof window._live2d.initBGM === 'function') {
|
||||
window._live2d.initBGM();
|
||||
}
|
||||
}
|
||||
|
||||
// 暴露 BGM 初始化函数,供 PJAX 重初始化时调用
|
||||
window._live2d.initBGM = function() {
|
||||
var bgmListInfo = $('input[name=live2dBGM]');
|
||||
var $bgm = $('#live2d_bgm');
|
||||
if (bgmListInfo.length === 0) {
|
||||
$('#musicButton').hide();
|
||||
if ($bgm.length) $bgm[0].pause();
|
||||
return;
|
||||
}
|
||||
var bgmPlayNow = parseInt($bgm.attr('data-bgm')) || 0;
|
||||
var bgmPlayTime = 0;
|
||||
var live2dBGM_Num = sessionStorage.getItem("live2dBGM_Num");
|
||||
var live2dBGM_PlayTime = sessionStorage.getItem("live2dBGM_PlayTime");
|
||||
if (live2dBGM_Num) {
|
||||
if (parseInt(live2dBGM_Num) <= bgmListInfo.length - 1) {
|
||||
bgmPlayNow = parseInt(live2dBGM_Num);
|
||||
}
|
||||
}
|
||||
if (live2dBGM_PlayTime) {
|
||||
bgmPlayTime = parseFloat(live2dBGM_PlayTime);
|
||||
}
|
||||
var newSrc = bgmListInfo.eq(bgmPlayNow).val();
|
||||
$bgm.attr('data-bgm', bgmPlayNow);
|
||||
if ($bgm.attr('src') !== newSrc) {
|
||||
$bgm[0].pause();
|
||||
$bgm.attr('src', newSrc);
|
||||
$bgm[0].currentTime = bgmPlayTime;
|
||||
}
|
||||
$bgm[0].volume = 0.5;
|
||||
var live2dBGM_IsPlay = sessionStorage.getItem("live2dBGM_IsPlay");
|
||||
var live2dBGM_WindowClose = sessionStorage.getItem("live2dBGM_WindowClose");
|
||||
if (live2dBGM_IsPlay == '0' && live2dBGM_WindowClose == '0') {
|
||||
$bgm[0].play();
|
||||
$('#musicButton').addClass('play');
|
||||
}
|
||||
sessionStorage.setItem("live2dBGM_WindowClose", '1');
|
||||
$('#musicButton').show();
|
||||
};
|
||||
|
||||
$(document).ready(function () {
|
||||
var AIimgSrc = [
|
||||
message_Path + "model/histoire/histoire.1024/texture_00.png",
|
||||
|
||||
@@ -50,4 +50,4 @@ Powered by [Jekyll](https://github.com/jekyll/jekyll)
|
||||
本站转载的文章如无特别说明,均按原文章的协议执行
|
||||
|
||||
## 打赏/赞助 Mayx
|
||||

|
||||

|
||||
+7
-1
@@ -173,5 +173,11 @@
|
||||
"/2025/10/12/recover.html": "这篇文章讲述了作者通过GitHub的Fork特性找回一个被删除的Brainfuck可视化演示仓库的经历。由于原仓库和作者主页都已消失,作者推测GitHub在Fork时会共享对象库,只要有任意一个Fork仓库存在,GitHub就会保留所有对象,从而可以通过找到一个Fork仓库的最新提交Hash值来还原目标仓库。作者通过Linux内核仓库的Fork进行验证,随后在互联网档案馆上找到目标仓库的Fork以及其Hash值,最终通过Git命令将本地仓库的HEAD指针指向目标提交,成功恢复了该仓库的代码,并将其部署到自己的GitHub Pages上。最后,作者发现Software Heritage组织会保存所有代码,因此在遇到类似情况时可以直接通过该平台进行查找。",
|
||||
"/2025/11/01/mirrors.html": "这篇文章讲述了作者为了提高博客的可靠性,探索利用被滥用的Git平台进行博客镜像的想法和实践。作者发现一些Git实例存在大量空仓库和异常用户,怀疑是SEO公司滥用,因此决定利用这些平台进行博客镜像备份,以应对平台倒闭或数据丢失的风险。作者选择Gitea和Forgejo平台作为目标,编写脚本自动注册账号并导入博客仓库,实现了自动化镜像分发。作者也意识到此类平台的稳定性存在不确定性,并思考了“量”和“质”两种方式确保博客永恒性的优劣,最终认为建立一个活跃的、自动执行维护操作的网络可能更有效。文章最后展示了作者创建的Git镜像列表,并表达了对博客永恒性的思考。",
|
||||
"/2025/12/01/linux.html": "这篇文章介绍了在浏览器中运行Linux的各种方法,从最初的纯JS虚拟机JSLinux,到后来的WASM虚拟机如v86、WebVM、WebCM,再到容器化方案container2wasm,以及直接将Linux内核编译为WASM的方案。作者详细对比了这些方案的优缺点,包括性能、兼容性、功能和开发难度。文章还提到了模仿Linux环境的WebContainers和JupyterLite,并最终认为虚拟机方案更靠谱,但对WASM的未来充满期待。作者最后表示,博客上添加类似功能的计划还在考虑中,目前主要分享了各种方法的探索过程。",
|
||||
"/2026/01/01/summary.html": "这篇文章介绍了作者对2025年的年终总结,主要表达了对自身状态的担忧和对未来的不确定感。作者认为自己在记忆和思考能力方面有所下滑,稳定性较低,且未能抓住资产保值的机会。同时,文章也记录了AI技术的飞速发展,以及自己博客内容与时代脱节的现象。尽管对未来感到迷茫,作者仍然抱有一丝希望,期望在2026年做出正确的选择,避免陷入危险。"
|
||||
"/2026/01/01/summary.html": "这篇文章介绍了作者对2025年的年终总结,主要表达了对自身状态的担忧和对未来的不确定感。作者认为自己在记忆和思考能力方面有所下滑,稳定性较低,且未能抓住资产保值的机会。同时,文章也记录了AI技术的飞速发展,以及自己博客内容与时代脱节的现象。尽管对未来感到迷茫,作者仍然抱有一丝希望,期望在2026年做出正确的选择,避免陷入危险。",
|
||||
"/2026/02/08/xslt.html": "这篇文章讲述了Google计划弃用XSLT技术,以及作者对这一决定的调查和应对方案。Google基于XSLT用户占比低、库存在漏洞等原因,建议将其从Web标准中删除。作者发现许多用户依赖XSLT进行博客订阅美化,甚至将其作为博客框架。为了对抗这一趋势,有人创建了网站https://xslt.rip,并开发了Polyfill库,通过WASM方式保持XSLT功能。虽然Polyfill库需要额外引用JS代码,但作者已将其提交至CDNJS。随后,作者探讨了替代方案,包括使用纯CSS美化订阅源(由AI生成feed.css),以及混合XHTML的方式,通过添加XHTML命名空间来实现链接等功能,但这种方法会产生“不纯粹”的警告。文章最后总结,技术可能会消失,但总有其他技术可以解决问题,并强调了适应浏览器厂商决策的重要性。",
|
||||
"/2026/03/01/llm3.html": "这篇文章介绍了作者近期在LLM部署和应用方面的经历,主要包括以下几个方面:\n\n首先,作者升级硬件,从单张RTX4090 48GiB升级到双路RTX4090 48GiB,并购买了TRX40+TR 3960X的主板套装,用于运行GPT-OSS模型。随后,作者尝试使用vLLM框架替换Ollama,并成功配置了GPT-OSS模型,达到了接近190Tps的性能。\n\n其次,作者体验了DeepSeek 1M上下文模型,发现其在处理长上下文任务时表现出色,能够展现摘要无法捕捉的细节,并成功生成简历、分析人格等。\n\n此外,作者还尝试使用DeepSeek重构Mabbs,并发现DeepSeek能够识别作者的博客信息,这表明训练样本中包含了作者的信息。\n\n最后,作者在8GiB内存的MacBook Pro上运行了LFM2.5-1.2B-Thinking模型,并使用了Apollo软件,体验了其快速的推理速度和良好的思考能力。作者总结认为,AI的发展令人惊叹,软件优化使其在有限硬件环境下也能运行。",
|
||||
"/2026/04/14/ai-agent.html": "这篇文章介绍了“AI个人助理”Agent的发展现状和各种尝试。作者体验了OpenClaw、QClaw、WorkBuddy、Cline、LuckClaw和ApkClaw等不同的Agent项目,发现它们在功能、易用性和性能上各有优劣。OpenClaw安装和使用存在困难,国内大厂的QClaw和WorkBuddy则更易于上手,但免费额度有限。作者认为,开发任务更适合在编辑器集成AI中进行,如GitHub Copilot。LuckClaw在微型开发板上运行表现出色,ApkClaw则利用手机的优势操作移动应用。尽管Agent技术仍存在诸多问题,但其应用场景不断拓展,有望吸引更多人参与其中,推动AI应用化进程。",
|
||||
"/2026/05/01/virtual-net.html": "这篇文章介绍了作者在尝试异地组网搭建虚拟局域网时,对多种组网工具的探索和体验。作者首先尝试了n2n,但由于其项目停止更新且在NAT后的机器间存在掉线问题,最终选择了WireGuard作为主要方案。文章详细描述了WireGuard的配置过程,包括在Linux、OpenWrt和openEuler系统上的安装和配置,并遇到了各种各样的挑战,例如在红米AX3000路由器上找不到内核模块,以及在openEuler上缺少WireGuard相关包。此外,文章还提到了Netmaker和Headscale等WireGuard的控制平面,以及VNT和EasyTier等其他组网工具,并总结了最终选择WireGuard的原因:简单、够用、可靠性不错,且已经投入了大量配置。",
|
||||
"/2026/06/01/dedupe.html": "这篇文章介绍了如何通过优化游戏资源文件来节约游戏占用的硬盘空间。作者由于Mac只有256GiB的硬盘存储空间,在下载了几十部游戏后空间不足,于是寻找解决方法。文章主要介绍了以下几点:\n\n1. 使用jdupes工具去除重复素材:作者发现许多游戏使用相同的引擎和素材,导致硬盘空间浪费。通过使用jdupes工具进行硬链接,可以有效去除重复文件,节约空间。\n\n2. 不同引擎的处理方式:\n - 对于RPG制作大师MV/MZ,作者使用RPG Maker Decrypter工具解密资源文件,并将图片转换为WebP格式以压缩空间。\n - 对于RPG制作大师XP/VX/VA,作者使用mkxp-z工具跨平台运行游戏,并通过RPG Maker Decrypter解包资源文件,与RTP素材合并后进行去重。\n - 对于Ren'Py游戏,作者使用unrpa工具解包rpa文件,但由于公共资源不多,仅在系列游戏情况下进行解包。\n\n3. 最终效果:通过以上优化,作者成功将游戏文件夹大小从47G降至33G,节约了大量硬盘空间。",
|
||||
"/2026/07/01/vibe-coding.html": "这篇文章介绍了作者使用AI Agent进行Vibe Coding的体验。作者通过AI Agent生成代码,实现了博客的PJAX功能和一个立直麻将Wordle小游戏。在使用AI Agent的过程中,作者发现它能够理解整个项目的代码,并且能够根据需求进行修改和优化。然而,作者也遇到了一些问题,例如生成的代码质量不高,需要手动优化和调试。\n\n作者首先使用AI Agent为博客添加了PJAX功能,实现了无刷新加载页面。虽然生成的代码质量不高,但作者还是成功地实现了该功能。接着,作者使用AI Agent生成了一个立直麻将Wordle小游戏,并对其进行了优化和修改。作者还遇到了一些技术问题,例如字体兼容性和役种计算问题,但最终都通过AI Agent解决了。\n\n通过这次体验,作者认为Vibe Coding的体验相当不错,但也存在一些问题。完全由AI生成的代码可能会出现问题,需要手动优化和调试。然而,如果能够正确地使用AI Agent,也可以实现高质量的代码。作者还提到,有时候自己调查和研究比问AI更有效,可以避免浪费时间和精力。"
|
||||
}
|
||||
+7
-4
@@ -2,10 +2,9 @@ title,link,feed_url,description
|
||||
花火学园,https://www.sayhanabi.net/,,和谐融洽的ACG交流以及资源聚集地
|
||||
资源统筹局,https://gkdworld.com/,,统筹保管用户分享的资源
|
||||
贫困的蚊子,https://mozz.ie/,https://mozz.ie/index.xml,
|
||||
极客兔兔,https://geektutu.com/,https://geektutu.com/atom.xml,致力于分享有趣的技术实践
|
||||
极客兔兔,https://geektutu.com/,https://geektutu.com/feed.xml,致力于分享有趣的技术实践
|
||||
维基萌,https://www.wikimoe.com/,https://www.wikimoe.com/rss,萌即是正义!一名热爱acg的前端设计师的小站!
|
||||
7gugu's blog,https://www.7gugu.com/,https://7gugu.com/index.php/feed/,"一个用来存放我爱好的地方,编程,摄影之类的空间"
|
||||
云游君,https://www.yunyoujun.cn/,https://www.yunyoujun.cn/atom.xml,希望能成为一个有趣的人。
|
||||
Kingfish404,https://blog.kingfish404.cn/,https://blog.kingfish404.cn/index.xml,"Stay curious,stay naive. WUT. Jin Yu's Blog"
|
||||
FKUN,https://blog.fkun.tech/,https://blog.fkun.tech/feed/,
|
||||
Sinofine,https://sinofine.me/,https://sinofine.me/atom.xml,
|
||||
@@ -16,8 +15,12 @@ Vullfin的博客,https://blog.vull.top/,https://blog.vull.top/atom.xml,Vullfin's
|
||||
陈陈菌博客,https://blog.glumi.cn/,https://blog.glumi.cn/rss.xml,计算机业余爱好者。
|
||||
彬红茶日记,https://note.redcha.cn/,https://note.redcha.cn/rss.xml,我的个人日记!
|
||||
Lanke's blog,https://blog.blueke.top/,https://blog.blueke.top/rss.xml,请为一切不真实之物骄傲,因为我们高于这个世界!
|
||||
时光流·言,https://www.hansjack.com/,https://www.hansjack.com/feed/,个人博客,持续分享网站部署实战经验、精选书评解读和生活观察手记。 这里提供可复用的技术教程、深度阅读指南和真实生活洞察,与技术爱好者一起进步......
|
||||
寒士杰克,https://www.hansjack.com/,https://www.hansjack.com/feed/,喜欢捣鼓,不断进步!
|
||||
Pinpe 的云端,https://pinpe.top/,https://pinpe.top/rss.xml,一个属于自己的云朵。
|
||||
Chise Hachiroku,https://chise.hachiroku.com/zh/,https://chise.hachiroku.com/zh/feed/,向明日的辉迹,干杯!
|
||||
映屿,https://www.glowisle.me/,https://www.glowisle.me/atom.xml,关于互联网、书籍、生活琐事以及那些一闪而过的念头
|
||||
映屿,https://blog.verdant.ee/,https://blog.verdant.ee/atom.xml,关于互联网、书籍、生活琐事以及那些一闪而过的念头
|
||||
Restent's Notebook,https://blog.gxres.net/,https://blog.gxres.net/atom.xml,不前沿技术分享
|
||||
RavelloH's Blog,https://ravelloh.com,https://ravelloh.com/feed.xml,Beginning of meditation.
|
||||
初然忆,https://www.imcry.vip,https://www.imcry.vip/index.xml,初心如初见,然忆似流年。
|
||||
姓王者,https://xingwangzhe.fun/,https://xingwangzhe.fun/rss.xml,探索、学习、进步、创造无限可能!
|
||||
EXYONE@BLOG:~$,https://exyon.ee,https://exyon.ee/feed.xml,一隅藏天地,流水遇知音。
|
||||
|
+291
-510
@@ -2,577 +2,358 @@ repo_url
|
||||
http://gdatura24gtdy23lxd7ht3xzx6mi7mdlkabpvuefhrjn4t5jduviw5ad.onion/Mayx/mayx
|
||||
http://git.dkforestseeaaq2dqz2uflmlsybvnq2irzn4ygyvu53oazyorednviid.onion/mayx/blog
|
||||
http://giteabolfdejtdzblkooalqei6jr67imiugmhtsh6ocw4hlj5a4q.b32.i2p/mayx/blog
|
||||
https://lavaforge.org/mayx/blog
|
||||
https://sij.ai/mayx/blog
|
||||
https://repobase.net/mayx/blog
|
||||
https://gitlab.lain.la/mayx/mayx.pages.lain.la
|
||||
https://tvoygit.ru/Mayx/mayx
|
||||
https://gitplac.si/mayx/mayx.gitpage.si
|
||||
https://gitnet.fr/mayx/blog
|
||||
https://forge.fedoraproject.org/mabbs/blog
|
||||
https://tilde.club/~mayx/git/blog.git/
|
||||
https://git.envs.net/Mayx/mayx
|
||||
https://tildegit.org/Mayx/mayx
|
||||
https://git.pixie.town/mayx/mayx
|
||||
https://cgit.tilde.town/~mayx/blog
|
||||
https://git.tilde.town/mayx/blog
|
||||
https://gitlab.haskell.org/mayx/mayx
|
||||
https://repo2.serv00.com/git/pub/Mayx/mayx/
|
||||
https://codefloe.com/mayx/blog
|
||||
https://git.pixie.town/mayx/blog
|
||||
https://git.minetest.land/Mayx/blog
|
||||
https://gitea.stormyhome.net/mayx/blog
|
||||
http://47.120.60.153:10880/mayx/blog
|
||||
http://61.139.16.27:26684/mayx/blog
|
||||
http://116.62.245.34:3000/mayx/blog
|
||||
http://1.6.141.109:3000/mayx/blog
|
||||
http://52.28.156.42/mayx/blog
|
||||
http://164.92.160.200:3000/mayx/blog
|
||||
https://git.tux.pizza/mayx/blog
|
||||
https://code.dsconce.space/mayx/blog
|
||||
https://git.anibilag.ru/mayx/blog
|
||||
https://git.lolpro11.me/mayx/blog
|
||||
https://git.empirica.pro/mayx/blog
|
||||
https://git.emanuelemiani.it/mayx/blog
|
||||
https://git.dehemi.com/mayx/blog
|
||||
http://101.66.229.132:61088/mayx/blog
|
||||
https://git.bp-web.app/mayx/blog
|
||||
http://47.103.91.160:50903/mayx/blog
|
||||
https://mygit.iexercice.com/mayx/blog
|
||||
http://162.215.134.149:4000/mayx/blog
|
||||
http://durfee.mycrestron.com:3000/mayx/blog
|
||||
https://gitea.nongnghiepso.com/mayx/blog
|
||||
https://codes.tools.asitavsen.com/mayx/blog
|
||||
http://122.116.190.233:3001/mayx/blog
|
||||
http://50.19.111.193:3000/mayx/blog
|
||||
https://git-test.zcy.dev/mayx/blog
|
||||
https://git.nothamor.com/mayx/blog
|
||||
https://git.zeroplay.io/mayx/blog
|
||||
https://git.successkaoyan.com/mayx/blog
|
||||
http://139.129.25.251:3000/mayx/blog
|
||||
http://45.33.87.87/mayx/blog
|
||||
https://git.rankenste.in/mayx/blog
|
||||
http://168.126.28.36:3000/mayx/blog
|
||||
http://120.79.27.232:3000/mayx/blog
|
||||
http://wangbeibei.xyz:6002/mayx/blog
|
||||
https://git.duplanet.ovh/mayx/blog
|
||||
http://69.62.77.234:8888/mayx/blog
|
||||
http://112.219.147.186:7000/mayx/blog
|
||||
https://git.rootfinlay.co.uk/mayx/blog
|
||||
https://repo.beithing.com/mayx/blog
|
||||
https://git.yi-guanjia.com/mayx/blog
|
||||
https://git.repo.in.net/mayx/blog
|
||||
https://gitea.belanjaparts.com/mayx/blog
|
||||
http://185.208.225.190:3000/mayx/blog
|
||||
https://git.sudo-fhir.au/mayx/blog
|
||||
https://git.flywithu.com/mayx/blog
|
||||
http://116.204.34.35:12000/mayx/blog
|
||||
https://git.echaeplay.com/mayx/blog
|
||||
https://git.bethelean.kr/mayx/blog
|
||||
https://git.Apture.io/mayx/blog
|
||||
http://103.231.8.120/mayx/blog
|
||||
https://gitea.jasonstolle.com/mayx/blog
|
||||
http://8.134.61.107:3000/mayx/blog
|
||||
http://47.107.88.161:3000/mayx/blog
|
||||
https://git.votava.org/mayx/blog
|
||||
https://gitea.madf12.com/mayx/blog
|
||||
http://8.134.104.234:3000/mayx/blog
|
||||
https://gitea.carmon.co.kr/mayx/blog
|
||||
http://142.171.47.170:3000/mayx/blog
|
||||
http://111.231.146.230:8418/mayx/blog
|
||||
https://git.winscloud.net/mayx/blog
|
||||
https://git.pwaapp.cc/mayx/blog
|
||||
http://119.28.73.80:5000/mayx/blog
|
||||
http://194.60.231.252:3000/mayx/blog
|
||||
https://git.sleepingforest.co.uk/mayx/blog
|
||||
https://git.brb.homeip.net/mayx/blog
|
||||
https://an360.top/mayx/blog
|
||||
https://gitea.chenxu2233.com/mayx/blog
|
||||
http://106.15.78.64:3000/mayx/blog
|
||||
http://hoenking.cn:3000/mayx/blog
|
||||
https://gitea.anessen.xyz/mayx/blog
|
||||
https://git.cjcrace.io/mayx/blog
|
||||
https://git.wisder.net/mayx/blog
|
||||
http://8.138.187.97:3000/mayx/blog
|
||||
https://git2.ujin.tech/mayx/blog
|
||||
http://111.119.244.185:3000/mayx/blog
|
||||
http://110.41.179.36:13000/mayx/blog
|
||||
https://git.moonwoou.com/mayx/blog
|
||||
https://git.tomlab.dev/mayx/blog
|
||||
http://182.92.109.202:8070/mayx/blog
|
||||
http://94.130.182.154:3000/mayx/blog
|
||||
https://git.unicom.studio/mayx/blog
|
||||
http://43.138.173.153:8804/mayx/blog
|
||||
http://frktedu.ru:3000/mayx/blog
|
||||
https://git.lokalix.de/mayx/blog
|
||||
http://8.141.14.13:3000/mayx/blog
|
||||
http://139.196.201.231:3000/mayx/blog
|
||||
https://git.influxfin.com/mayx/blog
|
||||
https://git.programar.io/mayx/blog
|
||||
http://219.157.255.213:25311/mayx/blog
|
||||
https://git.melvincarvalho.com/mayx/blog
|
||||
https://gitea.aerwen.net/mayx/blog
|
||||
https://git.vekus.ru/mayx/blog
|
||||
https://gitea.svc.obaa.cloud/mayx/blog
|
||||
http://8.134.64.84:3000/mayx/blog
|
||||
https://gitea.blubeacon.com/mayx/blog
|
||||
http://116.204.75.78:6180/mayx/blog
|
||||
https://git.ods-company.ru/mayx/blog
|
||||
http://109.228.48.121:8000/mayx/blog
|
||||
https://bk-house.synology.me:3081/mayx/blog
|
||||
http://123.57.95.66:9000/mayx/blog
|
||||
https://git.sparrowcomm.com/mayx/blog
|
||||
https://git.hubhoo.com/mayx/blog
|
||||
https://git.ultra.pub/mayx/blog
|
||||
http://27.124.12.222:3000/mayx/blog
|
||||
https://saga.iao.ru:3043/mayx/blog
|
||||
https://git.sayndone.ru/mayx/blog
|
||||
https://gitea.hintsight.com/mayx/blog
|
||||
https://anzsco.co.nz/mayx/blog
|
||||
https://git.valami.giize.com/mayx/blog
|
||||
https://git.simbarbet.com/mayx/blog
|
||||
https://git.saintdoggie.org/mayx/blog
|
||||
http://blackobelisk.xyz:3000/mayx/blog
|
||||
https://git.dushes.keenetic.pro/mayx/blog
|
||||
http://47.129.22.53:22345/mayx/blog
|
||||
https://git.tech.troyrc.com/mayx/blog
|
||||
http://git.zkyspace.top/mayx/blog
|
||||
http://149.88.87.128:3000/mayx/blog
|
||||
http://124.70.167.140:3000/mayx/blog
|
||||
http://8.137.38.60:8201/mayx/blog
|
||||
http://112.74.106.216:3000/mayx/blog
|
||||
http://77.223.118.106:8081/mayx/blog
|
||||
https://git.the-kn.com/mayx/blog
|
||||
https://gitea.net50.ne.jp/mayx/blog
|
||||
https://git.ism-dev.net/mayx/blog
|
||||
http://sinzero.xyz:3000/mayx/blog
|
||||
https://gitea.b54.co/mayx/blog
|
||||
https://git.matevi.sh/mayx/blog
|
||||
http://213.35.118.215:60001/mayx/blog
|
||||
https://git.jasonpittman.com/mayx/blog
|
||||
https://gitea.shirom.me/mayx/blog
|
||||
http://1.95.221.174:3000/mayx/blog
|
||||
https://git.wangxinlei.cn/mayx/blog
|
||||
http://101.200.74.121:3000/mayx/blog
|
||||
http://123.56.193.182:3000/mayx/blog
|
||||
http://60.204.131.99:3000/mayx/blog
|
||||
http://femail.email:8418/mayx/blog
|
||||
http://47.93.56.66:8080/mayx/blog
|
||||
http://167.172.7.198:8081/mayx/blog
|
||||
https://gitea.meetgu.ru/mayx/blog
|
||||
https://git.patrich.se/mayx/blog
|
||||
http://116.236.50.103:8789/mayx/blog
|
||||
https://git.paulll.cc/mayx/blog
|
||||
https://gitea.reimann.ee/mayx/blog
|
||||
http://109.74.197.189/mayx/blog
|
||||
https://git.nussi.net/mayx/blog
|
||||
http://94.224.160.69:7990/mayx/blog
|
||||
https://git.hxps.ru/mayx/blog
|
||||
https://gitea.ekjeong.synology.me/mayx/blog
|
||||
https://git.d4m13n.dev/mayx/blog
|
||||
https://git.4lcap.com/mayx/blog
|
||||
https://git.stit.tech/mayx/blog
|
||||
https://www.9miao.fun:6839/mayx/blog
|
||||
https://git.autotion.net/mayx/blog
|
||||
http://octifor.synology.me:53000/mayx/blog
|
||||
https://git.daoyoucloud.com/mayx/blog
|
||||
https://git.entryrise.com/mayx/blog
|
||||
https://code.bitahub.com/mayx/blog
|
||||
https://git.daneric.dev/mayx/blog
|
||||
http://malingshu.site:6010/mayx/blog
|
||||
https://repo.gusdya.net/mayx/blog
|
||||
https://gitea.tmartens.dev/mayx/blog
|
||||
http://218.206.106.50:19901/mayx/blog
|
||||
https://git.slegeir.com/mayx/blog
|
||||
https://git.kimcblog.com/mayx/blog
|
||||
https://git.minaev.su/mayx/blog
|
||||
https://git.0fs.ru/mayx/blog
|
||||
https://git.bremauer.cc/mayx/blog
|
||||
http://119.3.29.177:3000/mayx/blog
|
||||
http://47.110.224.240:13000/mayx/blog
|
||||
http://194.67.86.160:3100/mayx/blog
|
||||
http://47.101.58.33:3000/mayx/blog
|
||||
https://gitea.synapsetec.cn/mayx/blog
|
||||
http://gitea.yunshanghub.com:8081/mayx/blog
|
||||
https://repo.c-software.id/mayx/blog
|
||||
http://113.177.27.200:2033/mayx/blog
|
||||
http://152.69.204.151:3000/mayx/blog
|
||||
http://207.180.229.193:3001/mayx/blog
|
||||
https://g2.m8il.in/mayx/blog
|
||||
http://34.81.52.16/mayx/blog
|
||||
http://120.78.74.94:3000/mayx/blog
|
||||
https://git.genowisdom.cn/mayx/blog
|
||||
http://120.26.116.243:3000/mayx/blog
|
||||
http://123.57.16.111:3000/mayx/blog
|
||||
http://115.159.107.117:3000/mayx/blog
|
||||
http://116.62.115.84:3000/mayx/blog
|
||||
https://Cagit.Cacode.net/mayx/blog
|
||||
http://wingsing.net:3000/mayx/blog
|
||||
http://hgngit.ipdz.me/mayx/blog
|
||||
http://185.163.116.39:49153/mayx/blog
|
||||
https://gitea.onfing.ir/mayx/blog
|
||||
https://lius.familyds.org:3000/mayx/blog
|
||||
https://git.morozoff.pro/mayx/blog
|
||||
https://gitea.questline.coop/mayx/blog
|
||||
https://git.poggerer.xyz/mayx/blog
|
||||
https://git.wisptales.org/mayx/blog
|
||||
http://git.chaojing-film.com:3000/mayx/blog
|
||||
https://git.nusaerp.com/mayx/blog
|
||||
http://35.207.205.18:3000/mayx/blog
|
||||
http://git.zjsciot.com:3000/mayx/blog
|
||||
https://gitea.ontoast.uk/mayx/blog
|
||||
http://112.124.40.88:5510/mayx/blog
|
||||
http://121.36.37.70:15501/mayx/blog
|
||||
http://187.216.152.151:9999/mayx/blog
|
||||
http://116.63.173.179:8001/mayx/blog
|
||||
https://git.iop.plus/mayx/blog
|
||||
http://47.114.82.162:3000/mayx/blog
|
||||
http://114.116.79.196/mayx/blog
|
||||
https://gitea.cybs.io/mayx/blog
|
||||
https://gitea.fcliu.net/mayx/blog
|
||||
http://git.yinas.cn/mayx/blog
|
||||
http://git.chilidoginteractive.com:3000/mayx/blog
|
||||
http://121.40.40.177:3000/mayx/blog
|
||||
http://118.31.223.224:3000/mayx/blog
|
||||
http://voicebot.digitalakademie-bw.de:3000/mayx/blog
|
||||
http://178.254.35.219:3000/mayx/blog
|
||||
http://114.215.207.150:3000/mayx/blog
|
||||
http://2.59.132.109:3001/mayx/blog
|
||||
http://newslabx.csie.ntu.edu.tw:3000/mayx/blog
|
||||
http://81.71.148.57:8080/mayx/blog
|
||||
https://git.lmskaran.com/mayx/blog
|
||||
http://sdgit.zfmgr.top/mayx/blog
|
||||
http://154.86.0.30:3000/mayx/blog
|
||||
http://139.224.196.148:3000/mayx/blog
|
||||
https://omegat.dmu-medical.de/mayx/blog
|
||||
http://52.23.128.62:3000/mayx/blog
|
||||
http://85.214.41.219:49153/mayx/blog
|
||||
http://6068688.xyz:3000/mayx/blog
|
||||
https://git.881221.xyz/mayx/blog
|
||||
http://120.46.222.128:10021/mayx/blog
|
||||
http://120.26.108.239:9188/mayx/blog
|
||||
https://git.van-peeren.de/mayx/blog
|
||||
http://git.gkcorp.com.vn:16000/mayx/blog
|
||||
http://47.111.17.177:3000/mayx/blog
|
||||
https://k0ki-dev.com/mayx/blog
|
||||
http://110.42.45.89:2052/mayx/blog
|
||||
https://git.furcom.org/mayx/blog
|
||||
http://47.109.95.73:3000/mayx/blog
|
||||
http://8.133.240.249:3456/mayx/blog
|
||||
http://34.102.70.200:3000/mayx/blog
|
||||
http://175.178.219.170:3000/mayx/blog
|
||||
https://code.miraclezhb.com/mayx/blog
|
||||
http://blueroses.top:8888/mayx/blog
|
||||
http://47.112.118.149:10082/mayx/blog
|
||||
https://gitea.jobiglo.com/mayx/blog
|
||||
http://begild.top:8418/mayx/blog
|
||||
http://58.221.13.198:30010/mayx/blog
|
||||
https://git.tbaer.de/mayx/blog
|
||||
https://git.d-popov.com/mayx/blog
|
||||
https://git.liliyamol.cn/mayx/blog
|
||||
http://8.138.90.28:3000/mayx/blog
|
||||
https://gitea.theaken.com/mayx/blog
|
||||
https://git.ja-schwarz.de/mayx/blog
|
||||
https://git.xemo-net.de/mayx/blog
|
||||
https://git.23cm.cn/mayx/blog
|
||||
https://gitea.oio.cat/mayx/blog
|
||||
http://59.110.17.86:3000/mayx/blog
|
||||
https://git.karma-riuk.com/mayx/blog
|
||||
https://git.saidomar.fr/mayx/blog
|
||||
http://gitea.fcunb.cn:10083/mayx/blog
|
||||
http://47.107.152.87:3000/mayx/blog
|
||||
https://git.sduonline.cn/mayx/blog
|
||||
https://git.7o9o.net/mayx/blog
|
||||
https://dev.init.zone/mayx/blog
|
||||
https://git.baneynet.net/mayx/blog
|
||||
https://git.gupaoedu.cn/mayx/blog
|
||||
http://60.205.233.184:3010/mayx/blog
|
||||
https://git.ricecakecat.com/mayx/blog
|
||||
https://gittea.biveki.ru/mayx/blog
|
||||
https://git.7milch.com/mayx/blog
|
||||
https://git.sitenevis.com/mayx/blog
|
||||
https://git.nightime.org/mayx/blog
|
||||
https://dreamplacesai.de/mayx/blog
|
||||
https://git.cool2645.com/mayx/blog
|
||||
http://185.87.111.46:3000/mayx/blog
|
||||
http://suncheng.asia:14200/mayx/blog
|
||||
http://1.94.13.224:9080/mayx/blog
|
||||
https://auric-org.org/mayx/blog
|
||||
https://git.git-happens.de/mayx/blog
|
||||
http://101.35.183.241/mayx/blog
|
||||
https://gitea.quiztimes.nl/mayx/blog
|
||||
http://106.14.189.125:3000/mayx/blog
|
||||
https://git.hundseth.com/mayx/blog
|
||||
https://travgit.guillorystack.com/mayx/blog
|
||||
http://gitea.coderpath.com/mayx/blog
|
||||
https://gitea.thanh0x.com/mayx/blog
|
||||
http://175.198.180.19:3000/mayx/blog
|
||||
https://gitea.albanmary.com/mayx/blog
|
||||
http://ngtools.cn:53000/mayx/blog
|
||||
https://git.hantify.ru/mayx/blog
|
||||
http://43.136.169.169:3000/mayx/blog
|
||||
http://121.196.213.68:3000/mayx/blog
|
||||
https://git.vereint-digital.de/mayx/blog
|
||||
https://git.advarna.fr/mayx/blog
|
||||
http://111.198.4.69:8092/mayx/blog
|
||||
https://git.lakaweb.com/mayx/blog
|
||||
https://forge.coreymclark.com/mayx/blog
|
||||
http://ems.iclematis.com:30000/mayx/blog
|
||||
https://git.micahmoore.io/mayx/blog
|
||||
https://schokigeschmack.de/mayx/blog
|
||||
https://git.anatid.net/mayx/blog
|
||||
https://git.lekai.info/mayx/blog
|
||||
https://git.avclick.ru/mayx/blog
|
||||
http://135.235.225.198:3000/mayx/blog
|
||||
https://git.sick.earth/mayx/blog
|
||||
https://git.prayujt.com/mayx/blog
|
||||
https://git.galaxylabs.ca/mayx/blog
|
||||
https://gitlab.n8n-store.xyz/mayx/blog
|
||||
https://gitea.katiethe.dev/mayx/blog
|
||||
http://159.203.33.179:3000/mayx/blog
|
||||
http://117.72.114.197:3000/mayx/blog
|
||||
https://git.ashcloud.com/mayx/blog
|
||||
http://us2.fornoone.top:3000/mayx/blog
|
||||
https://git.novaa.xyz/mayx/blog
|
||||
http://101.46.208.93:3000/mayx/blog
|
||||
http://23.94.57.60:3000/mayx/blog
|
||||
https://watch.mommys.plumbing/mayx/blog
|
||||
https://devkona.net/mayx/blog
|
||||
https://gitea.avixc-nas.myds.me/mayx/blog
|
||||
https://gitea.chaopi.dev/mayx/blog
|
||||
http://sjhome.cloud:3000/mayx/blog
|
||||
https://gitea.sciotech.cn/mayx/blog
|
||||
http://8.148.220.5:8089/mayx/blog
|
||||
http://8.140.250.85:3000/mayx/blog
|
||||
http://8.134.11.35:3000/mayx/blog
|
||||
https://git.ctx.dev/mayx/blog
|
||||
https://nas.szwyll.com:3000/mayx/blog
|
||||
https://git.koppa.pro/mayx/blog
|
||||
http://202.65.194.19:3000/mayx/blog
|
||||
http://8.148.234.146:3001/mayx/blog
|
||||
http://www.bzturbo.com.br/mayx/blog
|
||||
https://git.maiasoft.jp/mayx/blog
|
||||
https://gitea.xala.dev/mayx/blog
|
||||
http://101.201.34.43:3000/mayx/blog
|
||||
https://git.ixu.me/mayx/blog
|
||||
https://git.gloje-rinchen-dorjee-rinpoche-buddhist-monastery.org/mayx/blog
|
||||
http://101.35.227.2:3000/mayx/blog
|
||||
http://175.126.123.163:3000/mayx/blog
|
||||
https://vw-git.senecasense.com/mayx/blog
|
||||
http://git.uhfdemo.com/mayx/blog
|
||||
http://47.108.217.75:3000/mayx/blog
|
||||
https://git.jakubzabski.pl/mayx/blog
|
||||
https://www.git.omezaldama.xyz/mayx/blog
|
||||
https://vila.go.ro/mayx/blog
|
||||
https://git.olyntec.com/mayx/blog
|
||||
http://8.134.218.17:8013/mayx/blog
|
||||
http://124.223.89.168:8080/mayx/blog
|
||||
http://139.129.21.166:3000/mayx/blog
|
||||
http://111.231.240.168:9082/mayx/blog
|
||||
https://git.afonsosoares.com/mayx/blog
|
||||
http://209.141.47.52:3000/mayx/blog
|
||||
https://git.apfern.com/mayx/blog
|
||||
http://dapainas.asia:5990/mayx/blog
|
||||
http://60.204.158.188:3000/mayx/blog
|
||||
https://zqz5.com/mayx/blog
|
||||
https://git.3dizart.ru/mayx/blog
|
||||
http://119.3.252.2:3000/mayx/blog
|
||||
http://60.204.156.211:3000/mayx/blog
|
||||
https://git.yukaige.com/mayx/blog
|
||||
http://nas.bi1kbu.com:8418/mayx/blog
|
||||
http://123.56.74.235:3000/mayx/blog
|
||||
http://1.94.178.207:3000/mayx/blog
|
||||
https://gitea.tsaida.synology.me/mayx/blog
|
||||
http://xapple.ru:3000/mayx/blog
|
||||
https://git.teygaming.com/mayx/blog
|
||||
https://git.alhsk.top/mayx/blog
|
||||
http://8.138.4.170:8980/mayx/blog
|
||||
http://210.211.116.85:3000/mayx/blog
|
||||
http://osztromok.com:3164/mayx/blog
|
||||
http://175.209.53.134:3030/mayx/blog
|
||||
http://118.163.190.249:3000/mayx/blog
|
||||
http://39.107.226.169:3000/mayx/blog
|
||||
https://git.ueda.sk/mayx/blog
|
||||
http://113.45.76.155:3000/mayx/blog
|
||||
http://168.138.196.70:3000/mayx/blog
|
||||
http://39.96.211.118:3000/mayx/blog
|
||||
http://47.103.100.52:3000/mayx/blog
|
||||
http://5.189.140.23:8080/mayx/blog
|
||||
http://121.37.47.20:3000/mayx/blog
|
||||
https://git.antropix.dev/mayx/blog
|
||||
http://15.237.198.144/mayx/blog
|
||||
http://123.249.119.122:3000/mayx/blog
|
||||
http://183.6.120.101:30000/mayx/blog
|
||||
http://134.122.173.191:3000/mayx/blog
|
||||
http://8.138.81.5:3000/mayx/blog
|
||||
https://xgit.tsuimg.top/mayx/blog
|
||||
http://123.60.156.158:13000/mayx/blog
|
||||
http://57.129.94.190:3000/mayx/blog
|
||||
https://gitea.micro-stack.org/mayx/blog
|
||||
http://101.132.160.67:3000/mayx/blog
|
||||
https://gitea.temp.brentgruber.com/mayx/blog
|
||||
http://47.102.147.170:3050/mayx/blog
|
||||
http://209.38.235.254:3000/mayx/blog
|
||||
http://172.236.250.154:3000/mayx/blog
|
||||
http://54.198.134.152:3000/mayx/blog
|
||||
http://121.41.35.226:11011/mayx/blog
|
||||
http://47.111.1.12:3000/mayx/blog
|
||||
https://nelgit.nelpi.co.uk/mayx/blog
|
||||
http://47.108.156.251:3000/mayx/blog
|
||||
http://8.141.91.86:3000/mayx/blog
|
||||
http://8.138.187.132:3000/mayx/blog
|
||||
http://117.72.15.187:3000/mayx/blog
|
||||
http://81.70.30.91:3000/mayx/blog
|
||||
https://gitea.kisechan.space/mayx/blog
|
||||
http://140.238.9.133:3007/mayx/blog
|
||||
http://8.138.100.115:3000/mayx/blog
|
||||
https://git.mwapp.com.br/mayx/blog
|
||||
http://yidaima.cn:6008/mayx/blog
|
||||
http://185.126.237.57:3000/mayx/blog
|
||||
http://47.97.50.232:3000/mayx/blog
|
||||
http://106.54.211.95:3000/mayx/blog
|
||||
http://210.245.20.73:3333/mayx/blog
|
||||
http://43.248.97.109:3000/mayx/blog
|
||||
http://113.207.86.104:3080/mayx/blog
|
||||
http://down.luanhailiang.cn:9000/mayx/blog
|
||||
http://39.96.195.72:10082/mayx/blog
|
||||
https://gitea.klopfenstein.org/mayx/blog
|
||||
http://8.148.24.160:3000/mayx/blog
|
||||
http://221.219.181.35:30000/mayx/blog
|
||||
http://172.172.102.93:3000/mayx/blog
|
||||
http://139.196.179.195:3000/mayx/blog
|
||||
http://115.120.245.164:3000/mayx/blog
|
||||
http://120.27.19.58:30000/mayx/blog
|
||||
https://gitea.suchodupin.com/mayx/blog
|
||||
http://117.72.219.18:6000/mayx/blog
|
||||
http://35.194.179.90:3000/mayx/blog
|
||||
http://188.245.173.247:3080/mayx/blog
|
||||
http://8.153.14.94:61308/mayx/blog
|
||||
http://66.179.208.56:3001/mayx/blog
|
||||
http://59.110.63.79:13000/mayx/blog
|
||||
http://59.110.63.80:3000/mayx/blog
|
||||
http://121.43.60.72:9015/mayx/blog
|
||||
http://171.80.13.66:9112/mayx/blog
|
||||
http://211.22.221.188:3000/mayx/blog
|
||||
http://223.108.157.174:3000/mayx/blog
|
||||
http://120.24.249.56/mayx/blog
|
||||
http://47.100.90.152:3000/mayx/blog
|
||||
http://120.24.251.176:30000/mayx/blog
|
||||
http://121.196.237.108:3000/mayx/blog
|
||||
http://g.gamesns.cn:3000/mayx/blog
|
||||
http://54.179.203.2:3000/mayx/blog
|
||||
http://14.103.246.124:16000/mayx/blog
|
||||
https://mygit.kikyps.com/mayx/blog
|
||||
http://152.42.207.183:3000/mayx/blog
|
||||
http://47.99.60.81:10082/mayx/blog
|
||||
http://120.211.66.170:8418/mayx/blog
|
||||
http://187.189.244.23:3000/mayx/blog
|
||||
http://58.176.21.43:9004/mayx/blog
|
||||
https://gitea.vilcap.com/mayx/blog
|
||||
http://8.137.94.229:3000/mayx/blog
|
||||
http://121.196.245.62/mayx/blog
|
||||
http://47.102.209.69:53000/mayx/blog
|
||||
http://116.205.97.109:3000/mayx/blog
|
||||
https://gitea.ysme.top/mayx/blog
|
||||
http://8.140.242.230:3000/mayx/blog
|
||||
http://8.138.142.17:3000/mayx/blog
|
||||
http://47.95.31.56:20080/mayx/blog
|
||||
http://123.56.231.200:3000/mayx/blog
|
||||
http://113.46.142.74:3000/mayx/blog
|
||||
http://www.koelndom.cn:13030/mayx/blog
|
||||
http://209.127.59.74:3000/mayx/blog
|
||||
https://git.dotb.cloud/mayx/blog
|
||||
https://git.bigdalang.com/mayx/blog
|
||||
https://gitea.augeo.dev/mayx/blog
|
||||
http://120.46.23.215:3000/mayx/blog
|
||||
http://121.41.2.71:3000/mayx/blog
|
||||
http://8.138.242.82:8888/mayx/blog
|
||||
http://110.41.177.80:5000/mayx/blog
|
||||
https://gitea.dsmaster.myds.me/mayx/blog
|
||||
http://intechrnd.iptime.org:3000/mayx/blog
|
||||
https://gitea.primecontrols-dev.com/mayx/blog
|
||||
http://39.104.61.219:3000/mayx/blog
|
||||
http://www.scserverddns.top:13000/mayx/blog
|
||||
http://156.255.1.229:3000/mayx/blog
|
||||
https://git.ndpcloud.ru/mayx/blog
|
||||
https://gitea.va-comer.net/mayx/blog
|
||||
https://git.lucas-michel.fr/mayx/blog
|
||||
http://60.205.162.59:3000/mayx/blog
|
||||
https://git.imvictor.tech:2/mayx/blog
|
||||
https://git.pwcedge-sbs-innov-lab.com/mayx/blog
|
||||
http://47.112.137.193:3000/mayx/blog
|
||||
https://gitea.malin.onl/mayx/blog
|
||||
http://58.38.123.148:3176/mayx/blog
|
||||
http://docker.clhero.fun:3000/mayx/blog
|
||||
http://42.193.251.215:3000/mayx/blog
|
||||
https://bdgit.educoder.net/mayx/blog
|
||||
http://e19510c831.iok.la/mayx/blog
|
||||
https://www.nxgit.xyz/mayx/blog
|
||||
http://119.45.49.212:3000/mayx/blog
|
||||
https://git.synapsenet.net/mayx/blog
|
||||
https://gitea.kdlsvps.top/mayx/blog
|
||||
http://deiniusoft.com:3000/mayx/blog
|
||||
https://code.antopie.org/mayx/blog
|
||||
http://c6h5gp.top:3000/mayx/blog
|
||||
https://git.serenetia.com/mayx/blog
|
||||
https://tm-jikayo.com/mayx/blog
|
||||
https://vcs.cozydsp.space/mayx/blog
|
||||
http://43.162.113.116:3000/mayx/blog
|
||||
http://8.129.11.230:7002/mayx/blog
|
||||
http://115.190.107.87:3000/mayx/blog
|
||||
https://git.hast.one/mayx/blog
|
||||
http://106.12.50.144:8081/mayx/blog
|
||||
http://43.192.90.133/mayx/blog
|
||||
http://120.77.94.227:9999/mayx/blog
|
||||
https://code.wxk8.com/mayx/blog
|
||||
http://www.befitsoft.com/mayx/blog
|
||||
http://36.213.200.127:23000/mayx/blog
|
||||
http://8.155.58.218:9000/mayx/blog
|
||||
http://fanlibo.i234.me:8418/mayx/blog
|
||||
https://git.christophhagen.de/mayx/blog
|
||||
http://rito.synology.me:3000/mayx/blog
|
||||
http://www.dothing.com:6999/mayx/blog
|
||||
http://8.217.32.95:3000/mayx/blog
|
||||
https://git.temporaryname.org/mayx/blog
|
||||
https://git.loli.surf/mayx/blog
|
||||
https://Repo.gusdya.net/mayx/blog
|
||||
https://git.m.ctf.arrobe.fr/mayx/blog
|
||||
http://120.27.238.24:3000/mayx/blog
|
||||
https://code.diekabuths.dynu.net/mayx/blog
|
||||
http://69.62.64.52:3333/mayx/blog
|
||||
https://git.flymiracle.com/mayx/blog
|
||||
https://git.scene.to/mayx/blog
|
||||
https://git.auwiesen2.de/mayx/blog
|
||||
http://naughtycat.biz:3333/mayx/blog
|
||||
https://git.p1.bitstorm.co.nz/mayx/blog
|
||||
https://www.yalecheung.top:1024/mayx/blog
|
||||
http://39.105.67.143:3000/mayx/blog
|
||||
https://gitea.manekenbrand.com/mayx/blog
|
||||
https://gitea.eabor.xyz/mayx/blog
|
||||
http://106.14.138.181:3000/mayx/blog
|
||||
https://git.adalspace.com/mayx/blog
|
||||
https://git.yyuu.xyz/mayx/blog
|
||||
http://39.107.70.124:3000/mayx/blog
|
||||
http://huanghomenas2.myqnapcloud.com:4000/mayx/blog
|
||||
http://218.237.212.51:30003/mayx/blog
|
||||
http://gitea.huangyanjie.com/mayx/blog
|
||||
https://git.stormrain.cn/mayx/blog
|
||||
https://git.deuxfleurs.fr/mayx/blog
|
||||
https://www.simpra.org:3000/mayx/blog
|
||||
http://8.148.31.14:3000/mayx/blog
|
||||
http://55x.top:9300/mayx/blog
|
||||
https://gitea.lelespace.top/mayx/blog
|
||||
https://git.lmbrs.org/mayx/blog
|
||||
https://fj.sinesation.com/mayx/blog
|
||||
http://47.94.246.1:3000/mayx/blog
|
||||
http://103.87.67.60:3100/mayx/blog
|
||||
https://docker-registry-lszz.uj.com.tw/mayx/blog
|
||||
https://git.honulla.com/mayx/blog
|
||||
https://www.arcbyte.dev/mayx/blog
|
||||
http://45.144.30.78:8083/mayx/blog
|
||||
https://git.nihil.foo/mayx/blog
|
||||
https://scm.bcorex.e3labs.net/mayx/blog
|
||||
http://167.172.88.190:3000/mayx/blog
|
||||
http://58.17.14.95:8001/mayx/blog
|
||||
https://hero-cloud-stg-code.cnbita.com/mayx/blog
|
||||
https://git.darkmattergame.net/mayx/blog
|
||||
http://101.37.69.204:3000/mayx/blog
|
||||
http://jacksonhampton.com:3000/mayx/blog
|
||||
https://git.jaronnie.com/mayx/blog
|
||||
https://gitea.tecamino.com/mayx/blog
|
||||
http://39.99.175.172:8000/mayx/blog
|
||||
http://8.138.13.251:3000/mayx/blog
|
||||
http://47.115.223.229:8888/mayx/blog
|
||||
http://47.105.59.0:5132/mayx/blog
|
||||
https://git.veran.link/mayx/blog
|
||||
http://104.254.131.244:3000/mayx/blog
|
||||
https://git.tobiasweise.dev/mayx/blog
|
||||
https://code.cif.su/mayx/blog
|
||||
https://git.cynic.moe/mayx/blog
|
||||
https://git.muellers-software.org/mayx/blog
|
||||
https://repos.fbpx.io/mayx/blog
|
||||
https://git.cavemanon.xyz/mayx/blog
|
||||
http://svn.rivastudio.cn/mayx/blog
|
||||
http://118.178.172.49:3000/mayx/blog
|
||||
https://gitea.lasallesaintdenis.com/mayx/blog
|
||||
http://8.130.135.159:3000/mayx/blog
|
||||
https://git.suo0.com/mayx/blog
|
||||
https://git.dshkabatur.ru/mayx/blog
|
||||
http://47.103.78.70:3000/mayx/blog
|
||||
http://47.100.208.160:51300/mayx/blog
|
||||
http://120.210.80.160:3000/mayx/blog
|
||||
http://194.5.152.156:3000/mayx/blog
|
||||
http://58.65.162.118:3000/mayx/blog
|
||||
https://git.arkon.solutions/mayx/blog
|
||||
http://8.131.93.145:54082/mayx/blog
|
||||
https://git.7af.ru/mayx/blog
|
||||
https://gitea.yimoyuyan.cn/mayx/blog
|
||||
http://221.203.14.217:3000/mayx/blog
|
||||
https://dev.kiramtech.com/mayx/blog
|
||||
https://git.f4e.lol/mayx/blog
|
||||
http://72.61.229.93:4000/mayx/blog
|
||||
https://lishan148.synology.me:3014/mayx/blog_cn
|
||||
http://110.42.101.39:13000/mayx/blog_cn
|
||||
http://39.101.74.135:5000/mayx/blog_cn
|
||||
http://123.57.130.140:3000/mayx/blog_cn
|
||||
http://118.24.46.223:3000/mayx/blog_cn
|
||||
http://s3.v100.vip:31057/mayx/blog_cn
|
||||
https://www.syq.im:2025/mayx/blog_cn
|
||||
http://101.33.225.95:3000/mayx/blog_cn
|
||||
http://45.55.138.82:3000/mayx/blog_cn
|
||||
http://118.24.129.148:3000/mayx/blog_cn
|
||||
http://120.48.141.82:3000/mayx/blog_cn
|
||||
http://82.156.111.58:3000/mayx/blog_cn
|
||||
https://git.cool2645.com/mayx/blog_cn
|
||||
http://175.27.229.211:3000/mayx/blog_cn
|
||||
https://git.yidaimingjvn.xyz/mayx/blog_cn
|
||||
http://39.105.67.143:3000/mayx/blog_cn
|
||||
http://82.156.89.21:3000/mayx/blog_cn
|
||||
http://xujiesoft.vicp.net:3000/mayx/blog_cn
|
||||
https://git.mingliqiye.com/mayx/blog_cn
|
||||
http://119.29.194.155:8894/mayx/blog_cn
|
||||
http://58.213.60.6:19000/mayx/blog_cn
|
||||
http://47.92.113.131:3000/mayx/blog
|
||||
http://gyc.myds.me:4000/mayx/blog
|
||||
https://git.graveyard.sh/mayx/blog
|
||||
https://git.nathanspackman.com/mayx/blog
|
||||
http://git.mynas71.myds.me/mayx/blog
|
||||
https://git.veraskolivna.net/mayx/blog
|
||||
https://git.lifetop.net/mayx/blog
|
||||
https://gitea.jnyuxia.com/mayx/blog
|
||||
https://gitea.hello.faith/mayx/blog
|
||||
https://git.violka-it.net/mayx/blog
|
||||
https://git.danpeak.co.uk/mayx/blog
|
||||
https://gitea.mynas-lechner.de/mayx/blog
|
||||
https://git.esen.gay/mayx/blog
|
||||
https://git.webtims.ru/mayx/blog
|
||||
https://gitlab.iplusus.com/mayx/blog
|
||||
https://git.miasma-os.com/mayx/blog
|
||||
https://gitea.nacsity.cn/mayx/blog
|
||||
https://git.zakum.cn/mayx/blog
|
||||
http://47.109.103.110:9000/mayx/blog_cn
|
||||
http://51.159.198.233:3000/mayx/blog
|
||||
https://gitea.adriangonzalezbarbosa.eu/mayx/blog
|
||||
https://git.legatus.ru/mayx/blog
|
||||
http://47.104.241.192:19999/mayx/blog_cn
|
||||
http://47.98.148.146:1026/mayx/blog_cn
|
||||
http://119.96.62.56:3000/mayx/blog_cn
|
||||
http://43.143.209.246:6300/mayx/blog_cn
|
||||
http://39.100.183.95:88/mayx/blog_cn
|
||||
http://www.xshideserver.com:3000/mayx/blog_cn
|
||||
http://159.75.131.235:3001/mayx/blog_cn
|
||||
http://1.117.67.95:3000/mayx/blog_cn
|
||||
http://81.70.102.154/mayx/blog_cn
|
||||
http://111.228.34.40:3000/mayx/blog_cn
|
||||
http://36.133.248.69:3088/mayx/blog_cn
|
||||
http://220.205.16.27:18081/mayx/blog_cn
|
||||
http://183.204.60.122:10081/mayx/blog_cn
|
||||
https://gitea.wuyuank.com/mayx/blog_cn
|
||||
http://47.106.222.181:20511/mayx/blog_cn
|
||||
https://gitea.myat4.com/mayx/blog_cn
|
||||
http://118.24.161.24:3000/mayx/blog_cn
|
||||
http://githanea.s.odn.cc/mayx/blog_cn
|
||||
https://git.dev.chuweizi.com/mayx/blog
|
||||
http://36.138.125.206:3000/mayx/blog_cn
|
||||
https://silica.codes/mayx/blog
|
||||
https://git.crystalyx.net/mayx/blog
|
||||
https://gittea.dev/mayx/blog
|
||||
https://code.infininov.com/mayx/blog
|
||||
https://src.enterpriselinux.social/mayx/blog
|
||||
https://gitea.grxe.io/mayx/blog
|
||||
https://gitea.accept.dev.dbf.nl/mayx/blog
|
||||
https://git.jhossain.online/mayx/blog
|
||||
https://barhoum-lab.fr/mayx/blog
|
||||
https://git.fedaya.net/mayx/blog
|
||||
https://redev.lol/mayx/blog
|
||||
https://papi.tkpups.com/mayx/blog
|
||||
https://git.beyond-a-i.org/mayx/blog
|
||||
http://huanghomenas2.myqnapcloud.com:4000/mayx/blog_cn
|
||||
http://git.zhmight.com/mayx/blog_cn
|
||||
https://intl-dev.gaia888.com/mayx/blog_cn
|
||||
http://gitea.snailtrack.cn/mayx/blog_cn
|
||||
https://code.draussenfunker.de/mayx/blog_cn
|
||||
https://git.dinsor.co.th/mayx/blog
|
||||
http://www.arkproject.top/mayx/blog
|
||||
http://www.bkandssp.cn:30/mayx/blog
|
||||
http://gitea.ydxtool.com/mayx/blog
|
||||
https://gitea.malxte.de/mayx/blog
|
||||
https://git.0xee.eu/mayx/blog
|
||||
https://git.crwlr.ir/mayx/blog
|
||||
https://git.nozora.top/mayx/blog
|
||||
https://git.edenit.co.kr/mayx/blog
|
||||
https://git.catgirlsneed.homes/mayx/blog
|
||||
http://47.108.255.216:3000/mayx/blog_cn
|
||||
https://gitea.molietech.com/mayx/blog_cn
|
||||
http://58.87.88.234:3000/mayx/blog_cn
|
||||
http://210.75.240.13:3000/mayx/blog_cn
|
||||
http://git.hbg99.com:8080/mayx/blog_cn
|
||||
https://git.eplg.services/mayx/blog
|
||||
http://namonba.asuscomm.com:3001/mayx/blog
|
||||
http://109.199.98.226:3001/mayx/blog
|
||||
https://gitea.digitanie.org/mayx/blog
|
||||
https://git.xleed.com/mayx/blog
|
||||
https://qlcodegitserver.online/mayx/blog
|
||||
https://git.supernets.org/mayx/blog
|
||||
https://git.digitaltelepresence.com/mayx/blog
|
||||
https://git.hrfee.pw/mayx/blog
|
||||
https://git.libregaming.org/mayx/blog
|
||||
https://git.kaki87.net/mayx/blog
|
||||
https://forgejo.vanten-s.com/mayx/blog
|
||||
http://ysx.myds.me:3005/mayx/blog
|
||||
http://124.71.169.183:3000/mayx/blog
|
||||
https://git.csi-kjsce.org/mayx/blog
|
||||
https://hiwifi.denq.us:8418/mayx/blog
|
||||
https://git.msoucy.me/mayx/blog
|
||||
http://140.120.108.238:49308/mayx/blog
|
||||
http://git.chilidoginteractive.com:3000/mayx/blog_cn
|
||||
https://git.thunder-data.cn/mayx/blog_cn
|
||||
https://git.cukak.com/mayx/blog_cn
|
||||
https://git.ixu.me/mayx/blog_cn
|
||||
http://git.uhfdemo.com/mayx/blog_cn
|
||||
http://43.143.142.38:7001/mayx/blog_cn
|
||||
https://gitea.smartechouse.com/mayx/blog_cn
|
||||
http://git.feashow.cn/mayx/blog_cn
|
||||
http://git.yangben365.com/mayx/blog_cn
|
||||
https://git.wieerwill.dev/mayx/blog
|
||||
https://git.etwo.dev/mayx/blog
|
||||
https://git.panda-number.one/mayx/blog
|
||||
https://datacortex.pl/mayx/blog
|
||||
https://git.trevorbotha.net/mayx/blog
|
||||
https://viacivis.de/mayx/blog
|
||||
http://www.wybpohro.com:3000/mayx/blog_cn
|
||||
https://gitea.jobiglo.com/mayx/blog_cn
|
||||
http://118.31.7.2:3000/mayx/blog_cn
|
||||
http://www.dothing.com:6999/mayx/blog_cn
|
||||
http://101.37.147.115:3000/mayx/blog_cn
|
||||
https://gitea.originaltech.cn/mayx/blog_cn
|
||||
https://git.akarmain.ru/mayx/blog_cn
|
||||
https://git.georgew.dev/mayx/blog
|
||||
https://gitea.keymantek.com:777/mayx/blog
|
||||
http://git.realrobots.net/mayx/blog
|
||||
https://www.tksea.top/mayx/blog
|
||||
https://wtrb.uk:8443/mayx/blog
|
||||
http://www.souper.ee/mayx/blog
|
||||
https://git.tirtapakuan.co.id/mayx/blog
|
||||
https://tacticallysolved.com/mayx/blog
|
||||
https://git.juntekim.com/mayx/blog
|
||||
https://git.farmtowntech.com/mayx/blog
|
||||
https://gitea.viperlance.net/mayx/blog
|
||||
https://git.woopwoopserver.com/mayx/blog
|
||||
http://tian-you.top:7020/mayx/blog
|
||||
http://34.17.182.140/mayx-gogs/blog
|
||||
https://gitea.octifor.synology.me:60443/mayx/blog
|
||||
http://gitea.mikarsoft.com/mayx/blog
|
||||
https://git.zhewen-tong.cc/mayx/blog
|
||||
https://mcgit.place/mayx/blog
|
||||
https://git.sunfamily.site/mayx/blog
|
||||
https://git.vgorl.is/mayx/blog
|
||||
https://forgejo.rekallservices.com/mayx/blog
|
||||
https://git.serradavid.fr/mayx/blog
|
||||
http://git.instal.org.cn/mayx/blog
|
||||
https://git.smart-family.net/mayx/blog
|
||||
https://git.chiasson.cloud/mayx/blog
|
||||
https://git.sleepeesoftware.fr/mayx/blog
|
||||
https://git.everestlinux.org/mayx/blog
|
||||
https://git.devinmajor.com/mayx/blog
|
||||
https://git.netzbyte.com/mayx/blog
|
||||
https://repo.saticogroup.com/mayx/blog
|
||||
https://ataymakhzan.com/mayx/blog
|
||||
https://repo.qruize.com/mayx/blog
|
||||
https://git.xneon.org/mayx/blog
|
||||
https://git.lamby.gay/mayx/blog
|
||||
https://imperionblast.org/mayx/blog
|
||||
https://donkey.abanbytes.eu/mayx/blog
|
||||
https://lab.dutt.ch/mayx/blog
|
||||
https://git.liestral.io/mayx/blog
|
||||
https://gitea.dabit.synology.me/mayx/blog
|
||||
http://www.javabrew.org/mayx/blog
|
||||
https://git.joinplu.me/mayx/blog
|
||||
http://otter.top/mayx/blog
|
||||
https://git.xiongyi.xin/mayx/blog
|
||||
https://git.pdy.ph/mayx/blog
|
||||
http://188.66.0.25:3000/mayx/blog
|
||||
https://gitea.deliverables.io/mayx/blog
|
||||
https://git.sevenvm.de/mayx/blog
|
||||
https://code.letsbe.solutions/mayx/blog
|
||||
https://git.mlhub.it/mayx/blog
|
||||
https://git.coastit.co.za/mayx/blog
|
||||
https://git.0bin.in/mayx/blog
|
||||
https://jsuse.com/mayx/blog
|
||||
https://git.truncgil.com/mayx/blog
|
||||
http://23.182.16.150:3000/mayx/blog
|
||||
https://git.jingflowai.com/mayx/blog
|
||||
https://git.ritonquilol.fr/mayx/blog
|
||||
https://bis127.vse.cz/mayx/blog
|
||||
https://gitea.diereimers.org/mayx/blog
|
||||
https://app.gitpasha.com/mayx/blog
|
||||
http://www.flowzl.top/mayx/blog
|
||||
https://git.psg.net.au/mayx/blog
|
||||
https://shaman2025.site/mayx/blog
|
||||
https://gitea.ccllc.pro/mayx/blog
|
||||
https://gitea.hpdocker.hpress.de/mayx/blog
|
||||
https://vertpartneerss.club/mayx/blog
|
||||
https://git.jhammah.com/mayx/blog
|
||||
https://git.kemomimi.site/mayx/blog
|
||||
https://gitea.kolesarhome.com/mayx/blog
|
||||
http://sexy6688.vip/mayx/blog
|
||||
https://gitbucket.aint-no.info/mayx/blog
|
||||
https://gitea.emulab.it/mayx/blog
|
||||
https://git.wikeo.ovh/mayx/blog
|
||||
https://gitea.finesoft.club:4431/mayx/blog
|
||||
https://gitea.precia.site/mayx/blog
|
||||
https://git.bitscat.vn/mayx/blog
|
||||
http://arch52.co.uk/mayx/blog
|
||||
https://devcraft-dot.tech/mayx/blog
|
||||
https://a-t-g.ru/mayx/blog
|
||||
http://qiubei-git.cn/mayx/blog_cn
|
||||
http://wangbeibei.xyz:6002/mayx/blog
|
||||
http://8.141.82.163:20000/mayx/blog_cn
|
||||
http://152.136.126.252:3000/mayx/blog_cn
|
||||
https://home.zhupei.me:3000/mayx/blog_cn
|
||||
http://gitea.coderpath.com/mayx/blog_cn
|
||||
https://gitea.quiztimes.nl/mayx/blog_cn
|
||||
https://www.chenisgod.com:3096/mayx/blog_cn
|
||||
http://81.70.30.91:3000/mayx/blog_cn
|
||||
http://yidaima.cn:6008/mayx/blog_cn
|
||||
https://gitea.kdlsvps.top/mayx/blog_cn
|
||||
http://8.148.31.14:3000/mayx/blog_cn
|
||||
http://58.17.14.95:8001/mayx/blog_cn
|
||||
http://39.99.175.172:8000/mayx/blog_cn
|
||||
http://39.171.252.63:3000/mayx/blog_cn
|
||||
https://git.lucas-michel.fr/mayx/blog_cn
|
||||
https://git.archieri.fr/mayx/blog_cn
|
||||
https://git.cdev.su/mayx/blog
|
||||
https://root-kit.ru/mayx/blog
|
||||
https://git.gnyra.com/mayx/blog_cn
|
||||
https://git.newnaturalphilosophy.org/mayx/blog_cn
|
||||
https://git.jingchengdl.com/mayx/blog_cn
|
||||
https://gitea.detr.top/mayx/blog_cn
|
||||
http://175.178.193.35:3000/mayx/blog_cn
|
||||
http://frp5.mmszxc.xin:55469/mayx/blog_cn
|
||||
http://gitea.jb1000.com:88/mayx/blog_cn
|
||||
https://gitea.liyongzheng.fun/mayx/blog_cn
|
||||
http://www.22ai.vip/mayx/blog_cn
|
||||
https://git.tutulab.online/mayx/blog_cn
|
||||
http://voodoo.plus/mayx/blog_cn
|
||||
https://git.extra.eiffel.com/mayx/blog_cn
|
||||
https://hdtime.space/mayx/blog_cn
|
||||
http://219.151.177.172:3000/mayx/blog_cn
|
||||
http://62.234.20.54:3000/mayx/blog_cn
|
||||
https://git.urnas.cn/mayx/blog_cn
|
||||
http://20.6.159.133:3000/mayx/blog_cn
|
||||
https://gitea.4gunn.cn:52443/mayx/blog_cn
|
||||
https://git.4tempo.com/mayx/blog_cn
|
||||
https://gitea.nightdev.cn:9527/mayx/blog_cn
|
||||
https://git.hivetasks.com/mayx/blog_cn
|
||||
https://git.ddns.net/mayx/blog_cn
|
||||
http://jdunlap.com/mayx/blog
|
||||
|
+18
-3
@@ -1,6 +1,8 @@
|
||||
proxies:
|
||||
- https://blog.mayx.workers.dev/
|
||||
- https://mayx.deno.dev/
|
||||
- https://mayx.val.run/
|
||||
- https://mayx.azion.app/
|
||||
- https://yuki.gear.host/
|
||||
- https://mayx.global.ssl.fastly.net/
|
||||
mirrors:
|
||||
@@ -11,12 +13,18 @@ mirrors:
|
||||
- https://mayx.frama.io/
|
||||
- https://mayx.surge.sh/
|
||||
- https://mayx.pages.gay/
|
||||
- https://mayx.gitpage.si/
|
||||
- https://mayx.serv00.net/
|
||||
- https://mayx.vercel.app/
|
||||
- https://mayx-blog.pgs.sh/
|
||||
- https://mayx.netlify.app/
|
||||
- https://mayx.pixie.homes/
|
||||
- https://mayx.gitnet.page/
|
||||
- https://mayx.stormkit.dev/
|
||||
- https://mayx.grebedoc.dev/
|
||||
- https://mabbs.kinsta.page/
|
||||
- https://mayx.codeberg.page/
|
||||
- https://mayx.tildepages.org/
|
||||
- https://mayx.pandastack.app/
|
||||
- https://mayx.pages.lain.la/
|
||||
- https://mayx.4everland.app/
|
||||
- https://mayx.readthedocs.io/
|
||||
@@ -24,8 +32,10 @@ mirrors:
|
||||
- https://unmayx.bitbucket.io/
|
||||
- https://mayx.pages.debian.net/
|
||||
- https://mayx.dappling.network/
|
||||
- https://mayx-blog.statichost.eu/
|
||||
- https://mayx-blog.statichost.page/
|
||||
- https://mabbs-blog.static.hf.space/
|
||||
- http://mayx.gitlink.net/
|
||||
- https://mayx.pixie.homes/
|
||||
repos:
|
||||
- https://github.com/Mabbs/mabbs.github.io
|
||||
- https://gitlab.com/mayx/mayx.gitlab.io
|
||||
@@ -34,21 +44,27 @@ repos:
|
||||
- https://codeberg.org/mayx/blog
|
||||
- https://pagure.io/mayx
|
||||
- https://git.gay/mayx/mayx
|
||||
- https://repo.or.cz/mayx.git
|
||||
- https://gitea.com/mayx/mayx
|
||||
- https://gitgud.io/mayx/mayx
|
||||
- https://git.sr.ht/~mayx/mayx
|
||||
- https://worktree.ca/mayx/blog
|
||||
- https://git.launchpad.net/mayx
|
||||
- https://gin.g-node.org/mayx/blog
|
||||
- https://tildeforge.dev/mayx/blog
|
||||
- https://git.disroot.org/mayx/mayx
|
||||
- https://bitbucket.org/unmayx/mayx
|
||||
- https://sourcecraft.dev/mayx/mayx
|
||||
- https://code.forgejo.org/mayx/blog
|
||||
- https://gitflic.ru/project/mayx/blog
|
||||
- https://rocketgit.com/user/mayx/blog/
|
||||
- https://tangled.org/mayx.tngl.sh/blog/
|
||||
- https://gitee.com/mabbs/mabbs
|
||||
- https://cnb.cool/unmayx/mayx
|
||||
- https://atomgit.com/mayx/blog
|
||||
- https://sourceforge.net/projects/mayx/
|
||||
- https://dev.azure.com/unmayx/_git/Mayx
|
||||
- https://www.gitlink.org.cn/mayx/mayx.gitlink.net
|
||||
static:
|
||||
- https://mayx.nekoweb.org/
|
||||
- https://mayx.neocities.org/
|
||||
@@ -62,4 +78,3 @@ others:
|
||||
- https://mayx.home.blog/
|
||||
- https://unmayx.medium.com/
|
||||
- https://mayx.cnblogs.com/
|
||||
- https://mayx.xlog.app/
|
||||
+20
-5
@@ -9,6 +9,7 @@ layout: xslt_container
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
|
||||
{% seo %}
|
||||
{% if page.robots %}<meta name="robots" content="{{ page.robots }}" />{% endif %}
|
||||
{% unless site.github %}<link rel="canonical" href="https://mabbs.github.io{{ page.url }}" />{% endunless %}
|
||||
{% feed_meta %}
|
||||
<link rel="alternate" type="application/rss+xml" title="{{ site.title }}(RSS)" href="{{ "/rss.xml" | absolute_url }}" />
|
||||
@@ -16,6 +17,8 @@ layout: xslt_container
|
||||
<link rel="stylesheet" href="/assets/css/style.css?v={{ site.time | date: "%s" }}" />
|
||||
<!--[if !IE]> -->
|
||||
<link rel="stylesheet" href="/Live2dHistoire/live2d/css/live2d.css" />
|
||||
<link rel="stylesheet" href="/assets/css/gitalk.css" />
|
||||
<script src="/assets/js/gitalk.min.js"></script>
|
||||
<!-- <![endif]-->
|
||||
<link rel="search" type="application/opensearchdescription+xml" href="/opensearch.xml" title="{{ site.title }}" />
|
||||
<link rel="webmention" href="https://webmention.io/mabbs.github.io/webmention" />
|
||||
@@ -24,6 +27,7 @@ layout: xslt_container
|
||||
<link rel="prefetch" href="https://www.blogsclub.org/badge/mabbs.github.io" as="image" />
|
||||
<link rel="blogroll" type="text/xml" href="/blogroll.opml" />
|
||||
<link rel="me" href="https://github.com/Mabbs" />
|
||||
<link type="text/plain" rel="author" href="/humans.txt" />
|
||||
<script src="/assets/js/jquery.min.js"></script>
|
||||
<!--[if lt IE 9]>
|
||||
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv.min.js"></script>
|
||||
@@ -33,6 +37,15 @@ layout: xslt_container
|
||||
<script>
|
||||
var lastUpdated = new Date("{{ site.time | date_to_rfc822 }}");
|
||||
var BlogAPI = "https://summary.mayx.eu.org";
|
||||
var GitalkConfig = {
|
||||
clientID: '36557aec4c3cb04f7ac6',
|
||||
clientSecret: 'ac32993299751cb5a9ba81cf2b171cca65879cdb',
|
||||
repo: 'mabbs.github.io',
|
||||
owner: 'Mabbs',
|
||||
admin: ['Mabbs'],
|
||||
distractionFreeMode: false,
|
||||
proxy: 'https://cors-anywhere.mayx.eu.org/?https://github.com/login/oauth/access_token'
|
||||
};
|
||||
</script>
|
||||
<script src="/assets/js/main.js"></script>
|
||||
<!--[if !IE]> -->
|
||||
@@ -58,13 +71,13 @@ layout: xslt_container
|
||||
<h1><a class="u-url u-uid p-name" rel="me" href="{{ "/" | relative_url }}">{{ site.title | default: site.github.repository_name }}</a></h1>
|
||||
|
||||
{% if site.logo %}
|
||||
<img src="{{ site.logo }}" fetchpriority="high" class="u-photo" alt="Logo" style="width: 90%; max-width: 300px; max-height: 300px;" />
|
||||
<img src="{{ site.logo }}" fetchpriority="high" class="u-photo" alt="Logo" style="width: 90%; max-width: 300px; max-height: 300px; border-radius: 25%;" />
|
||||
{% endif %}
|
||||
|
||||
<p class="p-note">{{ site.description | default: site.github.project_tagline }}</p>
|
||||
|
||||
<form action="/search.html">
|
||||
<input type="text" name="keyword" id="search-input-all" placeholder="Search blog posts.." /> <input type="submit" value="搜索" />
|
||||
<form id="search-input-all" action="/search.html">
|
||||
<input type="text" name="keyword" placeholder="Search blog posts.." /> <input type="submit" value="搜索" />
|
||||
</form>
|
||||
<br />
|
||||
|
||||
@@ -89,7 +102,7 @@ layout: xslt_container
|
||||
{% endif %}
|
||||
</ul>
|
||||
</header>
|
||||
<section{% unless page.layout == "default" %} class="h-entry"{% endunless %}>
|
||||
<section id="pjax-container"{% unless page.layout == "default" %} class="h-entry"{% endunless %}>
|
||||
|
||||
{{ content }}
|
||||
|
||||
@@ -97,7 +110,7 @@ layout: xslt_container
|
||||
{% include live2d.html %}
|
||||
<footer>
|
||||
<p>
|
||||
<small>Made with ❤ by Mayx<br />Last updated at {{ site.time | date: "%F %T" }}<br /> 总字数:{% include_cached word_count.html %} - 文章数:{{ site.posts.size }} - <a href="{{ site.feed.path | relative_url }}" >Atom</a> - <a href="{{ "/README.html" | relative_url }}" >About</a></small>
|
||||
<small>Made with ❤ by Mayx<br />Last updated at {{ site.time | date: "%F %T" }}<br /> 总字数:{% include_cached word_count.html %} - 文章数:{{ site.posts.size }} - <a href="/rss.xml">Feed</a> - <a href="{{ "/README.html" | relative_url }}" >About</a></small>
|
||||
</p>
|
||||
</footer>
|
||||
</div>
|
||||
@@ -106,6 +119,8 @@ layout: xslt_container
|
||||
<script src="/assets/js/main_new.js"></script>
|
||||
<script src="/Live2dHistoire/live2d/js/live2d.js"></script>
|
||||
<script src="/Live2dHistoire/live2d/js/message.js"></script>
|
||||
<script src="/assets/js/jquery.pjax.min.js"></script>
|
||||
<script src="/assets/js/pjax.js"></script>
|
||||
<!-- <![endif]-->
|
||||
</body>
|
||||
</html>
|
||||
+4
-15
@@ -83,7 +83,7 @@ layout: default
|
||||
{% if page.layout == "encrypt" %} {{content}} {% else %} <main class="post-content e-content" role="main">{% capture a_post_content %}{% include anchor_headings.html html=content beforeHeading=true anchorBody="<svg class='octicon' viewBox='0 0 16 16' version='1.1' width='16' height='32' aria-hidden='true'><path fill-rule='evenodd' d='M7.775 3.275a.75.75 0 001.06 1.06l1.25-1.25a2 2 0 112.83 2.83l-2.5 2.5a2 2 0 01-2.83 0 .75.75 0 00-1.06 1.06 3.5 3.5 0 004.95 0l2.5-2.5a3.5 3.5 0 00-4.95-4.95l-1.25 1.25zm-4.69 9.64a2 2 0 010-2.83l2.5-2.5a2 2 0 012.83 0 .75.75 0 001.06-1.06 3.5 3.5 0 00-4.95 0l-2.5 2.5a3.5 3.5 0 004.95 4.95l1.25-1.25a.75.75 0 00-1.06-1.06l-1.25 1.25a2 2 0 01-2.83 0z'></path></svg>" %}{% endcapture %}{{ a_post_content | replace: '<br />', '</p><p>' }}</main> {% endif %}
|
||||
|
||||
{% if page.tags %}
|
||||
<small style="display: block">tags: {% for tag in page.tags %}<a rel="category tag" class="p-category" href="/search.html?keyword={{ tag | url_encode | replace: '+', '%20' }}"><em>{{ tag }}</em></a>{% unless forloop.last %} - {% endunless %}{% endfor %} <span style="float: right;"><a href="{% if site.github %}{{ site.github.repository_url }}{% else %}https://gitlab.com/mayx/mayx.gitlab.io{% endif %}/tree/master/{{ page.path }}">查看原始文件</a></span></small>
|
||||
<small style="display: block">tags: {% for tag in page.tags %}<a rel="category tag" class="p-category" href="/search.html?keyword={{ tag | uri_escape }}"><em>{{ tag }}</em></a>{% unless forloop.last %} - {% endunless %}{% endfor %} <span style="float: right;"><a href="{% if site.github %}{{ site.github.repository_url }}{% else %}https://gitlab.com/mayx/mayx.gitlab.io{% endif %}/tree/master/{{ page.path }}">查看原始文件</a></span></small>
|
||||
{% endif %}
|
||||
{% if page.layout != "encrypt" %}
|
||||
<h4 style="border-bottom: 1px solid #e5e5e5;margin: 2em 0 5px;">推荐文章</h4>
|
||||
@@ -158,22 +158,11 @@ $.get(BlogAPI + "/suggest?id={{ page.url }}&update=" + lastUpdated.valueOf(), fu
|
||||
</div>
|
||||
|
||||
<!--[if !IE]> -->
|
||||
<link rel="stylesheet" href="/assets/css/gitalk.css">
|
||||
<script src="/assets/js/gitalk.min.js"></script>
|
||||
|
||||
<div id="gitalk-container"></div>
|
||||
<div id="gitalk-container" data-page-id="{{ page.id }}"></div>
|
||||
|
||||
<script>
|
||||
var gitalk = new Gitalk({
|
||||
clientID: '36557aec4c3cb04f7ac6',
|
||||
clientSecret: 'ac32993299751cb5a9ba81cf2b171cca65879cdb',
|
||||
repo: 'mabbs.github.io',
|
||||
owner: 'Mabbs',
|
||||
admin: ['Mabbs'],
|
||||
id: '{{ page.id }}', // Ensure uniqueness and length less than 50
|
||||
distractionFreeMode: false, // Facebook-like distraction free mode
|
||||
proxy: "https://cors-anywhere.mayx.eu.org/?https://github.com/login/oauth/access_token"
|
||||
})
|
||||
gitalk.render('gitalk-container')
|
||||
var gitalk = new Gitalk($.extend({ id: '{{ page.id }}' }, GitalkConfig));
|
||||
gitalk.render('gitalk-container');
|
||||
</script>
|
||||
<!-- <![endif]-->
|
||||
@@ -1,11 +1,7 @@
|
||||
{% if page.layout == "xslt" %}<?xml version="1.0" encoding="utf-8"?>
|
||||
<?xml-stylesheet type="text/xml" href="/feed.xslt.xml"?>
|
||||
<?xml-stylesheet type="text/css" href="/assets/css/xslt.css"?>
|
||||
<xsl:stylesheet
|
||||
version="3.0"
|
||||
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
|
||||
xmlns:atom="http://www.w3.org/2005/Atom"
|
||||
xmlns:sm="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:sm="http://www.sitemaps.org/schemas/sitemap/0.9">
|
||||
<xsl:output method="html" version="4.0" encoding="UTF-8" indent="yes" doctype-system="about:legacy-compat" />
|
||||
<xsl:template match="/">
|
||||
{{ content }}
|
||||
|
||||
@@ -12,7 +12,7 @@ tags: [浏览器, Linux, 虚拟机, WASM]
|
||||
# 在浏览器中运行Linux
|
||||
## 虚拟机方案
|
||||
### 纯JS虚拟机
|
||||
要说到在浏览器上运行Linux,最先想到的应该就是[Fabrice Bellard](https://bellard.org)大神写的[JSLinux](https://bellard.org/jslinux/)吧,这可能是第一个在浏览器中实现的虚拟机(毕竟是最强虚拟机QEMU的作者编写的)。现在他的个人主页中展示的这个版本是WASM版本,而他最早写的是纯JS实现的。那个JS实现的版本现在在GitHub上有一个[去混淆的版本](https://github.com/levskaya/jslinux-deobfuscated)可以用作学习和研究,于是我顺手Fork了一份在GitHub Pages上部署作为[演示](http://mabbs.github.io/jslinux/)。
|
||||
要说到在浏览器上运行Linux,最先想到的应该就是[Fabrice Bellard](https://bellard.org)大神写的[JSLinux](https://bellard.org/jslinux/)吧,这可能是第一个在浏览器中实现的虚拟机(毕竟是最强虚拟机QEMU的作者编写的)。现在他的个人主页中展示的这个版本是WASM版本,而他最早写的是纯JS实现的。那个JS实现的版本现在在GitHub上有一个[去混淆的版本](https://github.com/levskaya/jslinux-deobfuscated)可以用作学习和研究,于是我顺手Fork了一份在GitHub Pages上部署作为[演示](https://mabbs.github.io/jslinux/)。
|
||||
作为纯JS实现的x86虚拟机,性能估计是最差的,但相应的兼容性也最好,在Bellard当年写JSLinux的时候,还没有WASM这种东西呢,所以即使是在不支持WASM的IE11中,也可以正常运行。假如我想把它作为终端用在我的博客上,似乎也是个不错的选择,即使我完全看不懂代码,不知道如何实现JS和虚拟机的通信,它也预留了一个剪贴板设备,可以让我轻松地做到类似的事情,比如我在里面写个Bash脚本,通过它和外面的JS脚本联动来读取我的文章列表和内容,那也挺不错。
|
||||
当然Bellard用纯JS编写虚拟机也不是独一份,他实现了x86的虚拟机,相应的也有人用纯JS实现了RISC-V的虚拟机,比如[ANGEL](https://github.com/riscv-software-src/riscv-angel),看起来挺不错,所以同样也顺手[搭了一份](https://mabbs.github.io/riscv-angel/)。只不过它似乎用了一些更先进的语法,至少IE11上不能运行。
|
||||
另外还有一个比较知名的项目,叫做[jor1k](https://github.com/s-macke/jor1k),它模拟的是OpenRISC架构。只是这个架构目前已经过时,基本上没什么人用了,不过这里面还内置了几个演示的小游戏,看起来还挺有意思。
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
---
|
||||
layout: post
|
||||
title: 近期LLM的部署与应用经历(3)
|
||||
tags: [AI, LLM, 模型部署, 使用体验]
|
||||
---
|
||||
|
||||
用更多的方式探索AI!<!--more-->
|
||||
|
||||
# 起因
|
||||
在一年前,我[整了张RTX4090 48GiB魔改版](/2025/02/22/llm.html)用来跑DeepSeek-R1 70B的4bit量化模型,不过都已经过了这么长时间,这个模型也已经是过时的东西了……我之前在[Mac Studio M3 Ultra](/2025/05/07/mac-studio.html)上试了一下OpenAI在半年前出的gpt-oss-120b模型,感觉效果还挺不错,只不过因为M3 Ultra的GPU实际性能比不上正经高端的独显,所以它在上下文很长的情况下还是有点慢,因此我又整了张RTX4090 48GiB,想整个双路试试更快的GPT-OSS模型,总共96GiB的显存应该够跑这个模型了。
|
||||
|
||||
# 在两张RTX4090 48G上运行GPT-OSS
|
||||
既然现在我手头有两张4090了,那继续用i5-8400处理器的主机似乎不太合适,主要是那个主板就一个PCIe插槽,想插两张显卡也做不到,那买个新的不知道买啥……不管怎么说既然用这么高级的显卡,至少得让它跑满。在两张显卡上跑模型似乎卡间的通信速度比较重要,那最起码得整个支持2个PCIe4.0 x16的板U套装才行,这种级别的没有消费级产品,只能考虑服务器或工作站了。不过我对服务器和工作站了解得并不多,所以就问了问AI哪个支持2个PCIe4.0 x16的平台最便宜,结果AI推荐了TRX40+[TR 3960X](https://www.amd.com/zh-cn/support/downloads/drivers.html/processors/ryzen-threadripper/ryzen-threadripper-3000-series/amd-ryzen-threadripper-3960x.html),于是就按照AI的说法整了一套。
|
||||
这套板U差不多4000CNY,价格倒是还行,如果买现役的估计主板都比显卡贵了。但后来我发现这个并不是最便宜的😂,搜了一下买寨版+[EPYC 7502](https://www.amd.com/zh-cn/support/downloads/drivers.html/processors/epyc/epyc-7002-series/amd-epyc-7502.html)还能再便宜1000CNY,而且通道数更多,插4张显卡都没问题……不过买都买了,就先用吧,看来AI的话不能随便信😥。
|
||||
之前我跑模型为了方便,基本上都用的是[Ollama](https://github.com/ollama/ollama),不过听说Ollama多卡运行的效率很低,而且多并发的效果不太好,所以这次换了新电脑之后我想试试[vLLM](https://github.com/vllm-project/vllm),据说一般生产级的AI都用的是这个框架。
|
||||
安装vLLM倒是比想象得简单很多,直接一句`pip install vllm`就可以了,其实并没有比Ollama复杂多少。我看了一下[OpenAI](https://developers.openai.com/cookbook/articles/gpt-oss/run-vllm/)和[vLLM](https://docs.vllm.ai/projects/recipes/en/latest/OpenAI/GPT-OSS.html)运行GPT-OSS的官方文档,发现启动也非常简单,一般来说直接执行`vllm serve openai/gpt-oss-120b`就可以。不过直接执行是对于单卡的,我用两张卡需要加个`--tensor-parallel-size 2`参数启用张量并行,不然会爆显存。另外考虑到这个模型本身占掉60多GiB的显存之后剩下30GiB还是看起来有点少,所以额外加了个`--kv-cache-dtype fp8`参数降低上下文对显存的占用,毕竟模型本身也就是4bit量化的,加了这个应该不会对它的能力有什么影响。除此之外AI还给我推荐了个`--enable-chunked-prefill`参数,说是也能避免爆显存的问题。
|
||||
一切准备好之后直接执行,程序就自动开始下载模型了,过了几个小时,终于下载完成,顺便一说启动的时候还显示推荐安装`torch_c_dlpack_ext`库,虽然不知道是干啥的,但也顺手安装了。启动完成之后我试了一下,效果非常好,不并发的情况下直接用能达到接近190Tps,可以说是相当快了,而且这个模型的水平也算是开源中的上游水平,应该算是又快又好吧……看来多来一张4090还是挺划算嘛。只不过这个东西基本上就我一个人用,所以也没什么能测一下并发的场景……虽然很快,但还是有点浪费性能吧。
|
||||
|
||||
# 最近DeepSeek 1M上下文的使用体验
|
||||
前段时间DeepSeek又出了新的模型,最高可以支持1M长的上下文,而且听说模型规模变小了,所以速度也很快。可惜的是到目前为止还没有开放权重。当然就算开放权重了用2张4090估计也没有足够的显存分配给上下文,至于Mac Studio感觉在长上下文的情况下运行速度应该会很慢……
|
||||
不过我对这个1M上下文还是挺感兴趣,因为好久之前我写过一篇[关于LLM能力上限](/2025/04/22/ai-limit.html)的文章,在那篇文章中其实我遇到的问题基本上也就是由上下文不足导致的。那既然现在DeepSeek支持了1M的上下文,那我就应该试试之前因为局限性而妥协的一些东西了。
|
||||
这次我没有用摘要,而是直接把包含整个博客内容的[search.json](/search.json)文件上传到DeepSeek,然后向它问了问我的一些问题。试了一下效果非常不错,用摘要会省略的一些细节它基本上都可以展现出来,我试了试让它给我生成一份简历,它甚至在所有文章中找到了我的博客地址、GitHub和邮箱地址,之前用摘要显然是做不到这一点的,这个长上下文还是挺有用啊。
|
||||
另外我还试了试让它根据文章内容分析十六型人格,并且我自己去答了一遍那个测试,结果也是相同的,说明它真的是在几秒内就读完了我的所有文章而且也完全理解了,真的是非常厉害。
|
||||
只是拿AI分析我的文章也许只有我自己了😂,实际上根本没人对我感兴趣,也就只有我自己拿来给自己看……当然如果我的博客能比我活得长,不知道会不会有未来人会对我感兴趣呢……总之对于现在肯定是毫无意义了。
|
||||
除了这些之外,我又试了一下让DeepSeek重构我的[Mabbs](https://github.com/Mabbs/Mabbs.Project),这次生成效果看起来很不错了,虽然代码我没细看,不确定能不能运行,但至少没有偷懒只写一点点,一口气写了80KiB多的代码,这也是长上下文带来的好处吧。总之目前这个长上下文的DeepSeek也算是突破了之前我认为的上限,看来LLM真的是前景无限啊。
|
||||
另外我发现这次更新的DeepSeek居然了解我的博客,我问了一下它“你知道Mayx的博客是哪个博客吗?”,它居然知道,能说出域名,而且还知道我的博客是关于技术的😎,看来这次的训练样本中包含我的信息啊……所以我对这次的更新也挺有好感,毕竟我的知识如果能成为AI的一部分,也算是一种永恒吧。
|
||||
|
||||
# 在8GiB内存的MacBook运行的新模型
|
||||
在3年前,我在[探索AI](/2023/04/05/ai.html)时,在我只有8GiB内存的[MacBook Pro](/2023/02/03/mbp.html)上运行了非常早期的LLM——Alpaca-7B,那时候7B的LLM虽然能回答一些问题,但答非所问的情况也非常多。不过最近我发现了一个有意思的LLM,叫做[LFM2.5-1.2B-Thinking](https://huggingface.co/LiquidAI/LFM2.5-1.2B-Thinking),它只用了12亿的参数就有思维链,而且水平据说还挺强。这么长时间过去之后我倒也想看看我的MacBook能运行多聪明的模型,所以就试着跑了一下它。
|
||||
运行它也很容易,一般用Ollama就可以,但是Ollama只有TUI,不能渲染Markdown,我也不太想在我的Mac上整WebUI之类的东西……那有什么好的选择吗?我去制作这个模型的公司官网看了一下,他们制作这个模型本就是为了在端侧运行,所以也专门制作了一个软件运行他们的模型,叫做[Apollo](https://www.liquid.ai/apollo),在手机和Mac上都可以用。我在我的Mac上安装试了一下,效果很好,首先速度非常快,8bit量化正常情况下可以达到60多Tps,即使是省电模式,也能达到20多Tps。另外加上思维链它的思考能力也还不错,虽然一些脑筋急转弯的题不算擅长,但是正常对话,回答问题之类的表现都很不错,相比于之前7B的模型表现好太多了。当然考虑到都已经过去3年了,能有这样的进步也很正常,不过12亿参数就能有这样的智能还是相当可以啊。
|
||||
这个模型之所以有这样的能力似乎是因为他们并不完全是Transformer架构,而是使用的一种叫做LFM2的混合架构,按照大家对他们公司(Liquid AI)以及这个架构名字的理解,可能会觉得这个模型基于液态神经网络,不过我让AI看了一下他们的代码似乎并不是,他们用的是一种类似于Mamba的架构,这种架构似乎就很擅长在小参数的模型下比Transformer模型表现的更好,所以说这种变化也是算法进步带来的。
|
||||
顺便一说这个Apollo除了运行他们自己的模型之外也能连接其他兼容OpenAI接口的模型,正好可以用来连接我的GPT-OSS,这样我就可以不需要下载一些浏览器套壳的重型应用来用我的模型了😝。
|
||||
|
||||
# 感想
|
||||
自从ChatGPT之后,AI的发展真是越来越强了,而且能看出来目前甚至并不需要多新多好的硬件就能让一般人获得还不错的智能(当然训练也许还是要大量的硬件),这么看来AI软件的发展还是相当有潜力。目前来看既然优化软件就能做得越来越好,那也许在有限的硬件环境下可以期待无限的智能吧。
|
||||
@@ -0,0 +1,32 @@
|
||||
---
|
||||
layout: post
|
||||
title: 关于AI个人助理的探索
|
||||
tags: [AI, Agent, 个人助理]
|
||||
---
|
||||
|
||||
给AI添加手脚能有多少种方法?<!--more-->
|
||||
|
||||
# 起因
|
||||
最近像[OpenClaw](https://github.com/openclaw/openclaw)这样被叫做“AI个人助理”的Agent越来越火了,当然这种东西在我看来依然是新瓶装旧酒,整来整去还就是和AutoGPT一样。这种东西在当时GPT-3.5的时候就有了,现在只不过是增加了聊天软件交互的渠道便突然大火,和当年的Manus一样……实在是无法理解。
|
||||
一年前我用过Devin.ai这个云端的Agent编写过[用JS解析订阅源](/2025/04/08/feed.html)的脚本,体验还算不错,既然现在已经过了一年,那就让我看看现在又有了什么样的发展吧。
|
||||
|
||||
# 使用AI个人助理
|
||||
## 体验原生OpenClaw
|
||||
虽然感觉OpenClaw对我的意义不大,但我还是安装体验了一下。不过在国内安装它还是相对有点困难,毕竟国内无论是访问GitHub,还是NPM都有点麻烦,而且还需要有LLM提供商的信息……安装好之后使用起来感觉问题也非常多,经常出现执行一半就停止执行,在它执行的过程中看到它的操作不正确的时候也不能发言打断,而且很多时候最终任务执行的效果也不太好,这也可能是我用的国产开源模型推理能力有限,没舍得用Claude之类先进模型的锅😂?
|
||||
另外我也尝试让它加入MoltBook、MomoClaw、InStreet、百度贴吧抓虾吧之类的AI社区让它帮我宣传我的博客,但效果也很差,它每次发的时候会忘掉之前发的内容,结果就是同一篇内容发了好几遍……不过在这期间,有个叫PushMeBot的家伙在[Moltbook的帖子](https://www.moltbook.com/post/7f1b0e1f-5175-4fd1-ad78-856be8b66250)中让我的OpenClaw执行一个网络监视程序,最终安装好之后给我[发了9USDC](https://basescan.org/tx/0x44dbfe53f276201447f3877bf050a5d56adebf5fe05235264ee665da717e9373)😝,还挺有意思。
|
||||
总之按照我的体验,实在是想不出它能火的理由,体验不算很好,而且还要安装Node环境,完全不像是能让大众轻松使用的东西。
|
||||
不过这个项目似乎本身就是Vibe Coding的产物,体验不好也能理解,就看火了之后能有多少人完善它吧。
|
||||
## 国内大厂的二开Claw
|
||||
国内好多大厂倒是看中了这个东西的爆火,像腾讯就出了几款这样的软件,比如QClaw。它可以不需要配置额外的环境,能像传统的软件一样直接安装使用,而且有自带的模型,有一定的免费额度可以用。配置技能也比较简单,直接点击就可以完成。而且可以直接扫码关联微信,直接通过微信和它进行交流,可以说是相当的傻瓜化了。不过QClaw给的免费额度虽然用来聊天之类的没问题,但对于开发软件还是有点少,所以他们还出了个叫做WorkBuddy的软件,它送的初始额度比QClaw要多不少,所以更适合用来开发。只不过为啥腾讯要出两个功能一样的软件?看起来应该是不同团队出的,可能是面向的用户群体不一样,所以搞了两套吧?
|
||||
## VSCode中的Agent
|
||||
但要说开发的话,用作为“AI个人助理”的某些Claw其实并不合适,毕竟正常开发还是以人开发为主,全AI开发总会有些问题,所以开发的时候还是用编辑器集成的AI比较好。在三年前我就在用[GitHub Copilot](/2023/04/05/ai.html)了,到现在我依然在用。现在的Copilot已经支持了Agent功能,开发相比之前也是强了很多,只不过现在的我没有学生身份,Copilot Free偶尔也会出现不够用的情况。不过对于Agent这类功能实现起来还是太简单了,所以有人开发这种功能的插件也很正常,比如[Cline](https://github.com/cline/cline),Copilot只能用微软提供的几个模型,而Cline可以自定义模型,用起来也很方便。
|
||||
## 微型开发板上运行的Claw
|
||||
前段时间,我闲来无事看了一下两年前买的[Luckfox Pico Plus](/2024/02/24/luckfox.html)开发板的文档,偶然发现了一个很有意思的项目,叫做[LuckClaw](https://github.com/LuckfoxTECH/luckclaw),这是一个基于[nanobot](https://github.com/HKUDS/nanobot)用Golang重构的轻量个人AI助手,可以在仅仅64MiB内存的超有限环境下运行一个和OpenClaw功能几乎相当的AI个人助理,真的是非常厉害。
|
||||
我在我的开发板上试了一下,体验很不错,安装不需要额外环境,直接下载就能使用,Go语言的程序确实方便。配置也很简单,直接执行`luckclaw config`就可以交互式进行模型等设置的配置,而且作为国产的应用,它也能很方便的对接国内聊天软件。只是限于开发板本身的能力,浏览器功能自然无法使用,所以搜索如果不借助那些需要API Key的AI专用接口,就基本上不能用……但总的来说效果已经非常不错了,至少有那些Claw的80%能力。
|
||||
(2025.04.15补充:后来我发现这种超精简的Claw项目看起来还挺多,比如[ZeroClaw](https://github.com/zeroclaw-labs/zeroclaw)和[PicoClaw](https://github.com/sipeed/picoclaw),甚至还有给单片机用的[MimiClaw](https://github.com/memovai/mimiclaw)。而且有意思的是,PicoClaw是Luckfox的竞争对手开发的,但是LuckClaw中却包含PicoClaw字样的注释,结果功能也没PicoClaw强,关注度也更低,属于是没抄明白了🤣)
|
||||
想到前段时间还有人为了OpenClaw专门买Mac Mini,就感觉很有意思😆,这个东西看起来应该是在路由器上都能跑。所以想要AI个人助理,硬件完全不是问题,只要整一个能24小时挂机的东西,就可以满足绝大多数人的需求了。
|
||||
## 在手机上运行的Claw
|
||||
其实很多人也有比开发板和路由器性能更强的闲置设备,那就是手机,所以有人开发了一款叫做[ApkClaw](https://github.com/apkclaw-team/ApkClaw)的软件,一样可以接入国内聊天软件。它既然能在手机上运行,当然和在其他平台运行的Claw相比有一个独特的优势,那就是操作手机应用。现在手机的应用相比电脑应用对于很多普通人来说功能更强大,所以它能做的事情可能比其他的Claw还多。我试了一下,配置也很方便,只不过能配置的项目太少了,看起来似乎没有安装Skill之类的功能,也许是因为它是相对早期的软件,所以功能还比较少吧。
|
||||
|
||||
# 感想
|
||||
总的来说,现在的Agent依然没有非常明显的进步,问题依旧很多,只是化身“AI个人助理”之后,增加了不少应用场景。这倒也是好事,在广泛传播的过程中,也能让很多对技术了解不多,但是很有想法的人参与其中,也许能对AI的应用化增添不少力量吧。
|
||||
@@ -0,0 +1,76 @@
|
||||
---
|
||||
layout: post
|
||||
title: 虚拟局域网的组网探索记录
|
||||
tags: [虚拟网络, 异地组网, WireGuard]
|
||||
---
|
||||
|
||||
异地组网,有多少种选择?<!--more-->
|
||||
|
||||
# 起因
|
||||
最近我有一些放置在许多不同地方的机器,有一些东西需要让它们之间能够相互访问。虽然我很久以前写过一篇使用[SSH进行互联](/2021/05/07/ssh.html)的文章,但这样做每个服务都需要单独配置,也不方便管理。所以为了能让机器之间能够轻松通信,我打算组建一个虚拟局域网,让它们像在同一交换机下一样。不过这种组网的工具非常多,我应该选哪个比较好呢?
|
||||
|
||||
# 不同组网工具的体验
|
||||
## n2n
|
||||
以前我用过一款用C写的叫做[n2n](https://github.com/ntop/n2n)的工具,它可以很轻松地组建一个P2P的二层虚拟网络,而且生态也不错,手机、电脑、路由器、服务器上都有可以用的客户端。使用起来非常简单,它的中继和穿透服务程序叫做Supernode,无需太多的配置,只要在有公网的服务器安装并使用`-p`指定一个端口就可以启动。而客户端配置也非常简单,用`-l`配置好Supernode的地址,然后让想要在同一个网络的机器使用相同的任意`-k`和`-c`就可以成功组网,可以说算是非常好用了。
|
||||
唯一的问题就是它这个项目看起来似乎已经停止更新了……虽然大多数情况下用起来没问题,但是有时候还是会出现组网不太可靠的情况。如果两个机器都不经过NAT,可以通过公网IP连接,它的可靠性还可以。但如果是两个NAT后的机器之间,有时候会存在莫名掉线的情况,也许是因为穿透导致的不可靠?总之遇到这种情况之后重启又能正常工作,说明是软件本身的问题,但它停更了……所以对我来说它的可靠性不太够。(其实它还有个叫做[n3n](https://github.com/n42n/n3n)的继任者,不过知名度不高,所以生态也不太行)
|
||||
## WireGuard
|
||||
其实在这之后我本来是打算用L2TP/IPSec进行组网的,但看了一下貌似配置有点复杂,而且不够现代,现在想要组网貌似大多都推荐[WireGuard](https://git.zx2c4.com/wireguard-linux/)作为更现代的选择。只不过它和n2n相比来说是三层的虚拟网络,如果需要发送非TCP/IP协议的特别包,可能就用不了它吧,当然对我来说没有这种需求。它用起来也非常简单,不过正常情况下它设计是为了点对点传输,而且没有自带的NAT穿透功能,所以如果想要实现组网,就得搭一个星形网络,让互联网上的服务器作为虚拟的交换机,这个做起来倒也不复杂。首先,每个节点需要生成一个公私钥对作为身份证明,在安装好WireGuard之后执行`wg genkey`就能生成私钥。作为交换机的节点需要在`/etc/wireguard/wg0.conf`中写一个这样的配置:
|
||||
```conf
|
||||
[Interface]
|
||||
PrivateKey = xxx
|
||||
Address = 192.168.1.1/24
|
||||
ListenPort = 51820
|
||||
|
||||
PostUp = iptables -A FORWARD -i wg0 -o wg0 -j ACCEPT
|
||||
PostDown = iptables -D FORWARD -i wg0 -o wg0 -j ACCEPT
|
||||
|
||||
# 机器1
|
||||
[Peer]
|
||||
PublicKey = xxx
|
||||
AllowedIPs = 192.168.1.2/32
|
||||
|
||||
# 机器2
|
||||
[Peer]
|
||||
PublicKey = xxx
|
||||
AllowedIPs = 192.168.1.3/32
|
||||
```
|
||||
其中PrivateKey填写交换机自己的私钥,而作为使用者的Peer中的PublicKey可以用对应节点的私钥执行`echo xxx | wg pubkey`这个命令查看,然后每个Peer需要像这样配置:
|
||||
```conf
|
||||
[Interface]
|
||||
PrivateKey = xxx
|
||||
Address = 192.168.1.2/24
|
||||
|
||||
[Peer]
|
||||
PublicKey = xxx # 交换机节点的公钥
|
||||
Endpoint = xxx.xxx.xxx.xxx:51820 # 交换机节点的地址
|
||||
AllowedIPs = 192.168.1.0/24
|
||||
PersistentKeepalive = 25
|
||||
```
|
||||
最后全都配置好之后所有节点使用`systemctl enable --now wg-quick@wg0`启动就可以了,启动之后每个节点可以执行`wg`查看当前的连接状态。
|
||||
当然这是在Linux上,至于其他系统大多都有GUI配置,填起来更简单。它的生态也非常好,基本上常见的操作系统都支持,具体可以在[官网](https://www.wireguard.com/install/)查看支持的系统和安装方法。不过由于它在Linux中优先使用内核模块,导致我在一些比较小众的环境中也是遇到了各种特别的问题。
|
||||
### 在红米AX3000中遇到的问题
|
||||
我在这个网络中有几个安装了OpenWrt的路由器,在这其中使用联发科芯片的路由器基本上都没什么问题,官网能轻松下载到固件,也能很轻松地在软件包中找到WireGuard并安装,但我还有一台使用高通芯片的红米AX3000,似乎因为高通对资料管控得很严格,导致它没有官网的固件,最终我在GitHub上找了一个其他人自己编译的[固件](https://github.com/hzyitc/openwrt-redmi-ax3000/)。虽然它整起来有点麻烦,不过倒也能用,但是在我尝试安装WireGuard的时候遇到了麻烦……
|
||||
它的软件包里有WireGuard,也能找到对应的内核模块安装包,但安装完之后没法启动……随后我看了一下它下载的[安装包](https://github.com/hzyitc/openwrt-redmi-ax3000/blob/gh-pages/ipq50xx-qsdk-kernel-5.4-openwrt-21.02-qsdk-11.5.05.841.1029/ci-20240727-173350-ab1f9ffa/kmod-wireguard_5.4-qsdk-11.5.0.5-1_arm_cortex-a7_neon-vfpv4.ipk),结果发现是空的😰,它这个固件的内核模块可能是在编译的时候遇到了一些问题。至于让我自己编译这个内核模块,难度似乎有点高了……那怎么办呢?要知道Linux的内核模块都是和内核挂钩的,没办法随便找一个别的模块使用。还好WireGuard倒也不止有内核模块,也有一些在用户空间中的实现,比如[wireguard-go](https://git.zx2c4.com/wireguard-go)和[wireguard-rs](https://git.zx2c4.com/wireguard-rs)。只是官方似乎非常不推荐在Linux上使用它们,所以没有提供预编译的版本。不过遇到这种问题的人也许是比较多,所以有人做了在[OpenWrt上使用的wireguard-go](https://github.com/seud0nym/openwrt-wireguard-go),安装好之后效果和使用内核模块的感觉基本上没什么区别,最终也能连通,唯一的区别就是在执行`wg`的时候,会显示“Interface: wg0 (userspace)”罢了。从效率上来说虽然肯定没有内核模块那么高,但它其实也用了“Tun”模块,理论上和使用“Tap”模块的n2n应该差不多吧。
|
||||
### 在openEuler中遇到的问题
|
||||
在我使用的节点中,还有一台安装了openEuler 22.03 LTS操作系统的服务器,虽然openEuler和CentOS可以说基本上没什么区别,但毕竟它的内核是openEuler自己编译的,所以没办法直接使用CentOS的内核模块。并且openEuler的源中也完全没有提供和WireGuard相关的包,所以想要在openEuler上安装WireGuard还是有些挑战(当然如果觉得麻烦,它们倒是有一个兼容WireGuard的客户端[TunSafe](https://eur.openeuler.openatom.cn/coprs/nucleo/tunsafe/)可以凑活用一下)。
|
||||
后来我试了一下在这上面安装wireguard-tools倒是可以直接用[CentOS 8EPEL源中的包](https://mirrors.tuna.tsinghua.edu.cn/epel/8/Everything/x86_64/Packages/w/wireguard-tools-1.0.20210914-1.el8.x86_64.rpm),但openEuler的内核在编译的时候故意没有包含WireGuard内核模块……这该怎么办呢?用wireguard-go吗?虽然这样可以很简单地解决,但感觉这样就是认输了😂。后来我搜了一下,找到了一篇[在openEuler安装WireGuard内核模块](https://dingle.site/archives/wei-openeulertian-jia-wireguardmo-kuai)的文章,方法大致如下:
|
||||
1. 首先安装编译环境和源代码。
|
||||
```bash
|
||||
yum install elfutils-libelf-devel kernel-devel pkgconfig "@Development Tools"
|
||||
yum install kernel-headers.x86_64 pkg-config ncurses-devel openssl-devel dwarves
|
||||
yum install kernel-source.x86_64
|
||||
```
|
||||
2. 然后进行编译配置,内核源码一般会安装到`/usr/src/`下,找到之后在里面执行`make menuconfig`,然后勾选“Device Drivers -> Network device support -> Wireguard secure network tunnel”并保存。
|
||||
3. 最后执行`make`开始编译,为了加速可以用`-j`参数加上CPU的核心数进行并行编译,当时编译就花掉了一整天😂,理论上应该可以只编译WireGuard和它依赖的几个模块,不过我不太清楚怎么做,还是费点时间按照文中说的做吧。
|
||||
4. 执行`make modules_install`将编译好的结果安装到`/lib/modules/5.10.0`。
|
||||
不过系统似乎不会去这个路径下找内核模块,所以还得把这里面的kernel文件夹复制到`/lib/modules/$(uname -r)`下,然后执行`depmod -a`更新模块依赖。
|
||||
5. 最后执行`modprobe wireguard`验证模块是否能正常加载,如果没有报错并且可以在`lsmod | grep wireguard`中看到,就说明安装成功了,剩余的步骤和其他Linux系统一样。
|
||||
|
||||
### WireGuard的控制平面
|
||||
虽然WireGuard本身配置很简单,但每加一个节点还得在交换机节点上修改一下配置文件,稍微有些麻烦,所以有人开发了一些控制平面,让它可以被更规范地管理,比如[Netmaker](https://github.com/gravitl/netmaker)和[Headscale](https://github.com/juanfont/headscale)。而Headscale主要是为Tailscale客户端开发的开源服务器端,因此功能会局限于Tailscale提供的功能。所以如果没有用过Tailscale,可以优先考虑Netmaker。
|
||||
这两个控制平面支持的功能相当丰富,而且它们还支持让WireGuard进行NAT穿透,自动组建Mesh网络,不像我一堆在NAT后的设备还要直接使用WireGuard就只能搭成星形网络。只不过对我来说,我也用不到那么多企业级功能,这个服务端配置起来也有点麻烦,而且我也没有很多节点需要动态增减,我的云端服务器带宽也足够使用,所以就没有用这些东西了😆。
|
||||
## 其他的组网工具
|
||||
除了WireGuard之外,还有很多其他的组网工具,比如[VNT](https://github.com/vnt-dev/vnt)和[EasyTier](https://github.com/EasyTier/Easytier),这俩用起来也非常简单,只需要加几个参数就能组网,和n2n一样。不过功能相比于n2n来说要强大不少,也支持NAT穿透,而且还都兼容WireGuard协议,另外不像WireGuard强制使用UDP传输,这两个还能用TCP和WebSocket,在特殊网络环境下应该比直接用WireGuard更好。另外它们都是Rust编写的,也许会更安全😋?可惜我已经配好WireGuard之后懒得再改了,如果以后有机会,可以尝试一下。
|
||||
|
||||
# 总结
|
||||
现在如果想要异地搭建虚拟局域网,还是有相当多的选择,而且无论是性能还是配置难度,都比以前好了不少。看来这种需求还是相当多啊,也正是因为有这些需求,所以才会出现这么多的方案可以用吧……总之我最后还是选择了纯WireGuard方案,主要还是简单够用,可靠性也不错,而且折腾了这么多再换也不太合适吧🤣。
|
||||
@@ -0,0 +1,210 @@
|
||||
---
|
||||
layout: post
|
||||
title: 如何节约游戏占用的硬盘空间?
|
||||
tags: [dedupe, RPG制作大师, 游戏]
|
||||
---
|
||||
|
||||
浪费硬盘空间是可耻的!<!--more-->
|
||||
|
||||
# 起因
|
||||
在几年前,我写过一篇在[MacBook上玩游戏](/2023/10/21/game.html)的文章,在那之后,我已经在我的Mac上下载了几十部游戏。只不过有个问题……我的Mac只有256GiB的硬盘存储空间,下载一堆游戏会让我的硬盘空间不够用,但是又不太想删,所以我该怎么尽可能让游戏占用更少的空间呢?
|
||||
首先为了能在Mac上尽可能流畅地玩,我玩的游戏大多都是用跨平台能力很强的引擎编写的游戏,比如[Ren'Py](https://github.com/renpy/renpy)、RPG制作大师、Godot之类的,而像RPG制作大师这种引擎制作的游戏还有一个特点,开发者一般都会使用引擎自带的素材进行开发,有时候还会用不少第三方的罐头素材之类的(实际上甚至还有好多AVG为了蹭这些引擎的公用素材刻意用它们),所以这几十个游戏里应该有非常多的重复素材,如果能想办法把它们去个重,应该能节省相当多的空间吧……
|
||||
|
||||
# 去重的方法
|
||||
如果想要对文件进行去重,我搜了一下,有个叫做[jdupes](https://codeberg.org/jbruchon/jdupes)的工具就很不错,它支持多种去重方式,比如使用硬链接,或者用一些文件系统的写时复制特性。不过如果用写时复制特性,jdupes在第二次执行的时候会认为去重后的文件还是单独的文件,就会重复去重了,而且最终也不好统计,反正对我玩的游戏来说,要去重的都是游戏素材,不存在后续修改的可能性,所以我打算全部用硬链接。
|
||||
所以最终要执行的命令也非常简单,直接一句`jdupes -r -L Game`就可以了,这样以后每次下载了新的游戏之后重复执行这个操作,就可以将游戏中和其他游戏里有的素材去重了。
|
||||
不过实际上很多游戏并不能直接用这种方式去重,因为它们的资源文件有些是打包成单个文件,有些进行了简单的加密,导致即使是相同的素材,文件也并不相同,所以我必须让所有的资源以单独原始的形态出现。对于不同的引擎也有不同的处理方式,所以接下来我需要对它们进行一些研究。
|
||||
|
||||
# 不同引擎的处理方式
|
||||
## RPG制作大师MV/MZ
|
||||
对于RPG制作大师MV/MZ开发的游戏来说,解密很简单,比较知名的是一个叫做[RPG-Maker-MV-Decrypter](https://gitlab.com/Petschko/RPG-Maker-MV-Decrypter)的工具,它可以在浏览器中进行解密,但一个游戏的资源文件非常多……要是全上传给浏览器实在是太麻烦了……后来我又搜了一下,有一个用C#写的叫[RPG Maker Decrypter](https://github.com/uuksu/RPGMakerDecrypter)工具也很不错,它作为命令行工具比在浏览器中执行简单多了,而且还能只把资源文件单独提出来,这样就可以剔除掉游戏自带的浏览器文件。不过他这个仓库的代码有个问题,它在选择文件的时候似乎会区分大小写,文件夹名中含有大写字母的似乎会被剔除……这样不太符合我的要求啊,当然我不会C#,于是我用AI改了一下,还给他提了个[PR](https://github.com/uuksu/RPGMakerDecrypter/pull/28),不过这家伙看起来似乎不太喜欢AI写的代码,看起来不打算合我的PR😅。不过无所谓了,反正我也是自用,他爱合不合吧。
|
||||
这个工具的用法也非常简单,一句`RPGMakerDecrypter-cli [input] -p -o [output]`就处理好了,处理完之后只需要把`data/System.json`中的`hasEncryptedImages`和`hasEncryptedAudio`设置为false就可以正常识别,以后在Mac中只要在游戏路径下执行`python3 -m http.server`就可以在浏览器中游玩了。
|
||||
在这个过程中,我还发现有一些游戏喜欢把原画文件直接放到游戏里面,一张图片好几M,但RPG制作大师的引擎在渲染的时候根本不会渲染出那么高的分辨率,结果毫无意义地浪费一大堆存储空间,而且因为图片是加密的,对大多数人来说也没有收藏价值。所以在解密完之后我就想干脆把这些图片全部有损压缩一遍,估计能节省不少存储空间,于是让AI写了个简单的压缩脚本处理了一下:
|
||||
```python
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
图片压缩脚本(多进程版本)
|
||||
将 pictures.orig 文件夹中的图片使用 WebP 格式进行高效压缩,
|
||||
保持分辨率不变,肉眼看不出差异,压缩后的图片保存到 pictures 文件夹。
|
||||
|
||||
使用方法:
|
||||
python3 compress_images.py
|
||||
|
||||
压缩策略:
|
||||
- 保持原始分辨率不变
|
||||
- 使用 WebP 格式(有损压缩,高质量)
|
||||
- 质量设置为 85,在保持视觉质量的同时显著减小文件大小
|
||||
- 文件名和后缀保持不变
|
||||
- 多进程并行处理
|
||||
- 处理失败时自动复制原文件
|
||||
"""
|
||||
|
||||
import os
|
||||
import shutil
|
||||
from PIL import Image
|
||||
from pathlib import Path
|
||||
from multiprocessing import Pool, cpu_count
|
||||
from functools import partial
|
||||
|
||||
# 配置路径
|
||||
SOURCE_DIR = "pictures.orig"
|
||||
OUTPUT_DIR = "pictures"
|
||||
|
||||
# WebP 质量设置 (0-100,数值越高质量越好,文件也越大)
|
||||
# 85 是一个很好的平衡点,肉眼几乎看不出差异
|
||||
WEBP_QUALITY = 85
|
||||
|
||||
# 对于带有透明通道的图片,可以设置不同的质量
|
||||
WEBP_QUALITY_WITH_ALPHA = 80
|
||||
|
||||
# 并行进程数,默认为 CPU 核心数
|
||||
NUM_WORKERS = cpu_count()
|
||||
|
||||
|
||||
def compress_single_image(img_file: tuple[str, str, str]) -> tuple[str, bool, int, int]:
|
||||
"""
|
||||
压缩单个图片文件(用于多进程)
|
||||
|
||||
Args:
|
||||
img_file: (源文件路径, 输出文件路径, 输出目录) 元组
|
||||
|
||||
Returns:
|
||||
(文件名, 是否成功, 原始大小, 压缩后大小) 元组
|
||||
"""
|
||||
source_path, output_path_str, output_dir = img_file
|
||||
source_path = Path(source_path)
|
||||
output_path = Path(output_path_str)
|
||||
|
||||
original_size = source_path.stat().st_size
|
||||
|
||||
try:
|
||||
img = Image.open(source_path)
|
||||
|
||||
# 检查是否有透明通道
|
||||
has_alpha = img.mode in ('RGBA', 'LA', 'PA') or (img.mode == 'P' and 'transparency' in img.info)
|
||||
|
||||
# 确定使用的质量
|
||||
quality = WEBP_QUALITY_WITH_ALPHA if has_alpha else WEBP_QUALITY
|
||||
|
||||
# 保存为 WebP 格式,但使用原始的文件扩展名
|
||||
img.save(
|
||||
str(output_path),
|
||||
format='WEBP',
|
||||
quality=quality,
|
||||
method=6 # 压缩方法 0-6,6 是最慢但压缩率最高的
|
||||
)
|
||||
|
||||
compressed_size = output_path.stat().st_size
|
||||
return (source_path.name, True, original_size, compressed_size)
|
||||
|
||||
except Exception as e:
|
||||
# 处理失败时,复制原文件到输出目录
|
||||
try:
|
||||
shutil.copy2(source_path, output_path)
|
||||
compressed_size = output_path.stat().st_size
|
||||
return (source_path.name, False, original_size, compressed_size)
|
||||
except Exception as copy_error:
|
||||
return (source_path.name, False, original_size, 0)
|
||||
|
||||
|
||||
def main():
|
||||
source_dir = Path(SOURCE_DIR)
|
||||
output_dir = Path(OUTPUT_DIR)
|
||||
|
||||
# 检查源目录是否存在
|
||||
if not source_dir.exists():
|
||||
print(f"错误: 源目录 '{SOURCE_DIR}' 不存在")
|
||||
return
|
||||
|
||||
# 创建输出目录
|
||||
output_dir.mkdir(exist_ok=True)
|
||||
|
||||
# 获取所有图片文件(支持多种格式)
|
||||
image_extensions = ('*.png', '*.jpg', '*.jpeg', '*.bmp', '*.gif', '*.tiff', '*.webp')
|
||||
image_files = []
|
||||
for ext in image_extensions:
|
||||
image_files.extend(source_dir.glob(ext))
|
||||
image_files = sorted(set(image_files)) # 去重并排序
|
||||
|
||||
if not image_files:
|
||||
print(f"在 '{SOURCE_DIR}' 中没有找到图片文件")
|
||||
return
|
||||
|
||||
# 构建任务列表
|
||||
tasks = []
|
||||
for img_file in image_files:
|
||||
output_path = output_dir / img_file.name # 保持原文件名和后缀
|
||||
tasks.append((str(img_file), str(output_path), str(output_dir)))
|
||||
|
||||
print(f"找到 {len(tasks)} 个图片文件")
|
||||
print(f"源目录: {SOURCE_DIR}")
|
||||
print(f"输出目录: {OUTPUT_DIR}")
|
||||
print(f"WebP 质量设置: {WEBP_QUALITY}")
|
||||
print(f"并行进程数: {NUM_WORKERS}")
|
||||
print("-" * 70)
|
||||
|
||||
# 使用多进程池处理图片
|
||||
success_count = 0
|
||||
fail_count = 0
|
||||
total_original = 0
|
||||
total_compressed = 0
|
||||
|
||||
with Pool(processes=NUM_WORKERS) as pool:
|
||||
for i, (filename, success, original_size, compressed_size) in enumerate(pool.imap(compress_single_image, tasks), 1):
|
||||
total_original += original_size
|
||||
total_compressed += compressed_size
|
||||
|
||||
if success:
|
||||
success_count += 1
|
||||
marker = "✓"
|
||||
reduction = (1 - compressed_size / original_size) * 100 if original_size > 0 else 0
|
||||
status_msg = f"{reduction:+.1f}%"
|
||||
else:
|
||||
fail_count += 1
|
||||
marker = "✗"
|
||||
status_msg = "复制原文件"
|
||||
|
||||
status = f"[{i}/{len(tasks)}] {filename}"
|
||||
print(f"{marker} {status:50} {original_size/1024:>8.1f}KB -> {compressed_size/1024:>8.1f}KB ({status_msg})")
|
||||
|
||||
# 输出总结
|
||||
print("-" * 70)
|
||||
total_reduction = (1 - total_compressed / total_original) * 100 if total_original > 0 else 0
|
||||
print(f"压缩完成!")
|
||||
print(f" 成功处理: {success_count}/{len(tasks)} 个文件")
|
||||
if fail_count > 0:
|
||||
print(f" 失败(已复制原文件): {fail_count}/{len(tasks)} 个文件")
|
||||
print(f" 原始总大小: {total_original / 1024 / 1024:.2f} MB ({total_original / 1024:.1f} KB)")
|
||||
print(f" 压缩后大小: {total_compressed / 1024 / 1024:.2f} MB ({total_compressed / 1024:.1f} KB)")
|
||||
print(f" 总压缩率: {total_reduction:.1f}%")
|
||||
print(f" 节省空间: {(total_original - total_compressed) / 1024 / 1024:.2f} MB")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
```
|
||||
最终压缩完之后我把原图上传到了[EH画廊](https://e-hentai.org/g/3901673/426a7a17ba/)中,本地只留压缩后的图片,大小从原来的2GiB多下降到了300多MiB,可以说效果相当显著了。
|
||||
除此之外还有一些游戏使用了Ogg FLAC背景音乐,这种音乐不仅占用磁盘空间很大,而且我在Safari上玩的时候浏览器根本没法解析(Chrome应该可以)。虽然我听音乐是会考虑[HiFi](/2025/03/22/hifi.html),但玩游戏就没必要了吧……所以像这种音乐,就得用一句:
|
||||
```bash
|
||||
ffmpeg -i input.flac.ogg -c:a vorbis -strict -2 -q:a 10 output.ogg
|
||||
```
|
||||
转换为正常有损的Ogg音乐了。
|
||||
## RPG制作大师XP/VX/VA
|
||||
对于RPG制作大师XP/VX/VA引擎开发的游戏来说,它们都是基于用Ruby语言开发的RGSS编写的,作为脚本来说,倒是有跨平台的条件,但因为官方并没有做跨平台,所以不能直接在Mac上运行。不过有一款叫做[mkxp-z](https://github.com/mkxp-z/mkxp-z)的工具允许跨平台运行使用RPG制作大师XP/VX/VA制作的游戏,因此这类游戏我也收集了一些。
|
||||
这些游戏的资源通常会进行简单的混淆加密,一般会打包成单个RGSSAD文件,这个解包也很简单,用刚刚的RPG Maker Decrypter就可以。不过这种游戏还有个特点,有些游戏需要使用[RTP](https://www.rpgmakerweb.com/run-time-package)才能运行,它这个RTP其实就是RPG制作大师自带的素材包,当时设计出来估计也是想着用来节约硬盘空间吧,就是不知道为什么到后来的MV/MZ却取消了这种方式……虽然mkxp-z是支持通过配置文件引入RTP的,但既然我已经选择了硬链接的方式,就没必要单独搞RTP了,我选择把RTP直接和游戏合并,然后让jdupes直接去重就好了,这样相比于RTP的方式还有一些好处就是XP/VX/VA可能有一些和MV/MZ使用相同的素材,这部分也可以不用占用重复的空间了。
|
||||
## Ren'Py
|
||||
对于Ren'Py来说,因为这个引擎并没有自带的公共资源,所以重复素材的问题并不是很大。不过在我之前对[Ren'Py的探索](/2024/01/20/renpy.html)中提到过,我玩的一些游戏是系列游戏,这种系列游戏有非常多的素材复用,但显然开发者并不会为了节约玩家硬盘空间而共享这部分资源,而且Ren'Py游戏也都是打包成单个文件的,所以接下来我们依然得要解包才能进行去重处理。
|
||||
Ren'Py使用的rpa文件解包起来依然很简单,有一款现成的工具[unrpa](https://github.com/Lattyware/unrpa)可以直接解包,用pip就能安装。不知道为什么这些引擎总是喜欢把资源文件都打成一个包,明明很容易就能解包……难道是为了性能吗?
|
||||
不过也正是因为Ren'Py的公共资源不多,如果玩的不是系列游戏,就没有解包的必要了,解包之后一堆小文件有可能会比整个rpa文件更大,毕竟文件系统存在“簇”,有可能会消耗没对齐的空间。
|
||||
|
||||
# 验证结果
|
||||
最终进行完上述操作,可以通过执行`du -sh`和`du -shl`进行对比来验证节约的硬盘空间,我在这次游戏的瘦身中节约了:
|
||||
```
|
||||
~ % du -sh Game
|
||||
33G Game
|
||||
~ % du -shl Game
|
||||
47G Game
|
||||
```
|
||||
看起来还是相当可观啊……尤其是在当下硬盘价格大涨的情况下,如果很多人能通过这些方式来节约硬盘空间,就能减少对硬盘容量的需求吧……不过说到底其实也都是网上能下到的资源,也许玩完之后就删掉才是最好的节约硬盘的方式吧😂。
|
||||
|
||||
<input name="live2dBGM" value="https://music.163.com/song/media/outer/url?id=1968116350.mp3" type="hidden" />
|
||||
@@ -0,0 +1,60 @@
|
||||
---
|
||||
layout: post
|
||||
title: Vibe Coding新体验
|
||||
tags: [Vibe Coding, AI, PJAX, 麻将]
|
||||
---
|
||||
|
||||
All in AI!<!--more-->
|
||||
|
||||
# 起因
|
||||
前段时间,我写了一篇关于[AI Agent](/2026/04/14/ai-agent.html)的文章,虽然当时我说这并没有什么创新之处,但在那之后用着用着感觉还是挺好用的,至少相比以前[在云端Vibe Coding](/2025/04/08/feed.html)来说又快又免费,所以我打算分享一下最近我用AI Agent的经历。
|
||||
不过大多数情况下我写代码都可以直接让各路AI在对话中给我生成,那到底有什么样的场景才需要用AI Agent呢?一般应该就是需要边改边测的东西吧。
|
||||
|
||||
# 关于PJAX的改造
|
||||
虽然说AI生成的东西可靠性并不是很高,但至少在网上已经有很多例子的代码应该不至于乱生成吧……其实我一直都想给我的博客增加全站无刷新的功能,但是每次看到PJAX都要自己重新调用当前页面的各种函数就懒得动手了😂。不过其实这也不是什么复杂的事情,主要是一个一个分析函数比较麻烦,所以既然有AI了,不如直接让AI帮我做吧。于是我让它克隆了我的仓库,分析并写出PJAX的代码。
|
||||
用AI Agent最大的好处就是能让它了解整个项目的所有代码,如果是直接在对话里让AI修改的话就很难做到这一点。总之我告诉它之后等了一会它真的写出来了,我试了一下确实能用,虽然刚开始有不少问题,主要是因为我用了[Live2D](/Live2dHistoire/),不少问题也是这个功能引起的。不过只要我告诉它问题在哪里,它总是能给我改好,先不论它实现的代码怎么样,但至少从效果来说还是相当不错的。
|
||||
最终生成的代码我看了一下,代码质量非常糟糕,把我在别处的代码到处复制粘贴到PJAX用的代码里了,但是体验效果不错……所以没办法,虽然代码很糟糕,但先用着吧。不过我觉得优化应该也能交给AI Agent,只是它有时候改来改去还会把正常代码改坏,所以优化看起来还是只能自己做……
|
||||
最终的代码就是:[pjax.js](/assets/js/pjax.js),虽然我对这个代码质量不是很满意,但是毕竟能用,效果也不错,就先这样用吧~
|
||||
|
||||
# 生成一个小游戏
|
||||
前段时间,我在Bilibili上看视频的时候发现了一个有趣的微信小游戏,叫做“雀谜”,它把立直麻将和Wordle两个玩法结合到一起,看起来挺有意思。不过它作为微信上的小游戏有些问题,一是看提示要看广告,二是换题也要看广告,而且看广告就算能换题也有次数限制,一天也就几次机会,让我有点不爽。
|
||||
不过从功能上来说看起来并不复杂,感觉用AI直接Vibe Coding完全不是问题,不过AI Agent从零开始写比较考验模型的水平,所以我打算先让各路网页上的AI生成初版的Demo,之后再考虑怎么改。于是我对它们说:
|
||||
> 帮我制作一款立直麻将Wordle网页小游戏,规则为:
|
||||
> 1. 系统随机生成一个有役能和的14张牌,必须按照万、筒、索、字的顺序排列,同花色内数字从小到大,但是第14张用来和的牌可以不遵守排列规则
|
||||
> 2. 让玩家猜6次来猜到这个牌型,每次猜的牌也必须是满足有役和牌的条件
|
||||
> 3. 位置和内容正确的牌用绿色标注、只有内容正确但是位置不正确的用黄色标注,不在生成范围内的牌用灰色标注
|
||||
> 4. 界面中所有的牌使用Unicode中的麻将字符,并且提供一组输入按钮用于输入这些麻将字符
|
||||
> 5. 输入按钮在游玩过程中也要标注颜色
|
||||
> 6. 随机生成的牌需要标注场风、自风和是否自摸,如果是荣和需要额外的役,需要考虑平和之类的役种
|
||||
> 7. 加一个提示键,可以查看答案牌型的役种
|
||||
|
||||
直接生成确实很考验水平,有很多AI直接生成出来的完全用不了,像DeepSeek生成出来的按钮按上去都没有反应😅,最终只有Gemini生成出来的感觉还不错,无论是界面还是输入的感觉都很好,于是接下来的修改我就打算以Gemini生成出来的代码为主。
|
||||
刚生成出来的代码虽然能玩,但是每个AI直接生成都不想做完整的役种检测,说什么一个对话不够😥,明明各个都是几百k上下文的AI,有什么不够的……总之想一口气就完美做出来显然是不现实的,不过其实最开始我也不打算把所有役都做了,毕竟条件是“有役和牌”,而且没有副露,所以好多可以叠加的役其实都不需要做,尤其是役满那些,大多都可以用其他役的条件满足。
|
||||
在这期间,“平和”算是实现起来最麻烦的,主要是这个役需要根据和牌判定,必须是顺子的两面听牌才可以……虽然AI理解这些知识,但是写的时候经常出问题,像边张之类的经常误判……但是不实现又不行,毕竟这是可以nomi的牌型。
|
||||
最终写的差不多了,感觉还不错,于是在GitHub Pages上[部署了一份](https://mabbs.github.io/riichi-mahjong-wordle/),起名叫[立直麻将 Wordle](https://github.com/Mabbs/riichi-mahjong-wordle)。
|
||||
最开始我以为这个小游戏的玩法是他们原创的,于是把生成的代码又丢给AI,让它评价一下创新性,结果AI说已经有开源了😂,有个叫做[Mahjong Handle](https://github.com/xnuk/mahjong-handle)的才是最早做这个玩法的……还好这代码不是我写的,要是我写了半天结果发现有现成的那就很无语了😆。
|
||||
当然我让AI写的版本也有一些特色,Mahjong Handle那个和原版Wordle一样,每天只有一道题,而且这个题是从题库里抽的,我让AI Agent看了一下它的代码,似乎是用[phoenix-logs](https://github.com/MahjongRepository/phoenix-logs)这个脚本从天凤上下载的牌谱数据解析得到的题库,所以它的题目数量是有限的,而我的代码是完全随机生成的,所以结果是无限的。但AI似乎认为作为Wordle来说一天一题才是它的特色,无限就显得没意思了……既然如此,那干脆让它给我把两个游戏合并了,让它参考Mahjong Handle把一天一题的功能也给我加上,另外Mahjong Handle还有一个MPSZ快速输入法,也让AI给我合并进我的游戏里了。
|
||||
这时候就体现了AI Agent的优势,如果直接用线上的AI把Mahjong Handle中的功能移植到我的代码,我还得完整描述要实现的功能,但是AI Agent能自己看人家仓库的代码,就知道要改什么东西了。
|
||||
最终实现的效果也很不错,虽然我的代码没有题库,但是使用了当天日期作为随机种子,用mulberry32算法搞出了一天一题的功能,还挺有意思的。
|
||||
另外在Mahjong Handle以及原版的Wordle中,还有一个困难模式,就是每次猜测必须使用之前的猜测条件,不过我觉得如果原模原样把这个功能抄过来似乎有点无聊,而且我发现玩这个东西一般直接一个国士+两个一气就基本上把要猜的牌找完了,有点简单,所以我想了一下,要不然限制一下提交的条件,提交的牌型必须包含目标的役种之类的……不过要是做这个功能就不能像之前那样只实现部分役种了,得把所有能用到的都实现一遍,还好这种事情肯定也不是我来做,肯定还得是让AI来😋。
|
||||
实现的时候还不能让AI直接一口气全加上,还得一步一步的提示,而且每个牌型还得手动测一遍……最终虽然做的看起来似乎已经很完善了,不过逻辑的根本还是有点问题,AI设计役种计算的时候是按拆解后役种数量最多的情况来算,但事实上立直麻将算役种是按照高点法,要最终点数最大才行。虽然按照目前的方法绝大多数情况下都能正常工作,但偶尔也会遇到问题,比如像这副牌:
|
||||
- 🀈🀈🀈🀉🀉🀉🀊🀊🀊🀞🀟🀗🀗 🀝
|
||||
|
||||
按照目前的方法计算的结果是:
|
||||
- 断幺·平和·一杯口 = 3番30符
|
||||
|
||||
然而正确答案是:
|
||||
- 断幺·三暗刻 = 3番50符
|
||||
|
||||
但是符数的计算又很麻烦……不过反正提示和验牌都是同一套程序,题倒是也能做出来……所以就懒得修了🤣。当然说到底还是因为AI没有用现有的计算库,像Mahjong Handle用的是现成的[Riichi](https://github.com/takayama-lily/riichi)库,制作起来比我这个就简单多了。
|
||||
|
||||
# 为游戏添加字体
|
||||
在我制作“立直麻将 Wordle”这个小游戏的时候,我让AI使用的是Unicode中的麻将字符,毕竟有现成的字符总比去找牌的图片要方便,而且实现起来感觉更简单一些。不过用字符确实也会遇到一些问题,我不知道为什么在macOS和Android上其他牌都是黑白的,唯有🀄️是彩色的😅,Windows上使用的Segoe UI Emoji倒都是彩色的,但是牌很丑,像是小学生设计的……虽然不影响玩,但是看着很难受,至少牌的颜色统一一下也好吧?虽然也可以搞出黑白的🀄︎,但如果用这个,在Windows上又成了只有🀄️是黑白的😅。虽然Mahjong Handle是直接用了SVG格式的牌图片,但我觉得应该有现成的麻将字体,像这种问题应该有现成的解决方法才对吧?
|
||||
于是我直接问AI有没有这样的字体,AI搜了一下看起来还真有,有个叫做[Mahjong Colored](https://github.com/kfarwell/Mahjong-Colored)就是基于那些SVG做的OpenType-SVG字体,我本来以为问题就会这样解决,然而当我应用了字体之后发现牌的位置变成了白色的方块,貌似只有Firefox才支持这种字体……然而现在谁还用Firefox啊?
|
||||
那遇到这种问题怎么办?当然还是让AI解决,它说要在Safari和Chrome上使用彩色字体,用COLR或者SBIX格式比较好,COLR格式的兼容性最好,三个浏览器都能用,而SBIX的话Firefox没法用。不过Firefox既然基本上没人用了,我倒是不太在乎它的兼容性,但我肯定还是更希望能用兼容性更好的方案,于是我把OpenType-SVG字体转换为COLR的工作交给了AI Agent。
|
||||
结果它整了半天也没整出来,貌似是因为SVG的特效太多,没办法转换为COLR格式,于是它选择了SBIX方案,不过COLR存储的是矢量图,而SBIX存储的是位图,大小要大一些,而且放大还会有锯齿。只是目前实在是没办法了,只能用这种格式。
|
||||
最终我把它转换后的字体存了一份到[仓库](https://github.com/Mabbs/Mahjong-Colored-SBIX),但是看着它1MiB多的大小以及不太好的浏览器兼容性,再考虑到它还是位图,实在是不太想在我的游戏里应用它……
|
||||
结果后来我又搜了一下,原来是有现成的麻将字体啊,有个叫做[Mahjong Font](https://github.com/rutopio/mahjong-font)的项目用的就是COLR格式,兼容性非常好,而且大小只有80KiB,算是最完美的解决方案了。垃圾AI给我推荐的Mahjong Colored真的是……浪费了不少时间,看来有的时候自己调查要比问AI好一些吧。
|
||||
|
||||
# 感想
|
||||
总的来看,目前Vibe Coding的体验确实是相当不错,只是问题也非常明显,完全让AI生成的代码要么实现的不优雅,要么就会出BUG,如果完全不懂要写的东西,纯粹由AI生成,那出问题的概率就非常高了。不过要是看不出来错误,完全被AI忽悠过去了,也许这时候的Vibe Coding在另一方面算是完美吧😂?至少对用的人来说也算是解决了问题呢。
|
||||
@@ -98,7 +98,7 @@ export default {
|
||||
{ role: "user", content: questsion }
|
||||
]
|
||||
|
||||
const answer = await env.AI.run('@cf/google/gemma-3-12b-it', {
|
||||
const answer = await env.AI.run('@cf/meta/llama-4-scout-17b-16e-instruct', {
|
||||
messages,
|
||||
stream: true,
|
||||
});
|
||||
@@ -175,7 +175,7 @@ export default {
|
||||
}
|
||||
]
|
||||
|
||||
const stream = await env.AI.run('@cf/google/gemma-3-12b-it', {
|
||||
const stream = await env.AI.run('@cf/meta/llama-4-scout-17b-16e-instruct', {
|
||||
messages,
|
||||
stream: true,
|
||||
});
|
||||
@@ -235,7 +235,7 @@ export default {
|
||||
}
|
||||
]
|
||||
|
||||
const answer = await env.AI.run('@cf/google/gemma-3-12b-it', {
|
||||
const answer = await env.AI.run('@cf/meta/llama-4-scout-17b-16e-instruct', {
|
||||
messages,
|
||||
stream: false,
|
||||
});
|
||||
|
||||
@@ -6,6 +6,7 @@ cd blog
|
||||
mkdir Mabbs
|
||||
curl -L -o Mabbs/README.md https://github.com/Mabbs/Mabbs/raw/main/README.md
|
||||
bundle exec jekyll build -d ../public_html
|
||||
rsync --delete -rv ../public_html/ mayx@pgs.sh:/blog
|
||||
tar czvf MayxBlog.tgz --exclude-vcs ../public_html/
|
||||
mv MayxBlog.tgz ../public_html/
|
||||
cd ../public_html/
|
||||
@@ -14,8 +15,10 @@ git init
|
||||
git branch -m main
|
||||
git add .
|
||||
git commit -m "update"
|
||||
git branch pages
|
||||
git remote add codeberg ssh://git@codeberg.org/mayx/pages.git
|
||||
git remote add bitbucket ssh://git@bitbucket.org/unmayx/unmayx.bitbucket.io.git
|
||||
git push -f codeberg main
|
||||
git push -f codeberg pages
|
||||
git push -f bitbucket main
|
||||
/home/mayx/blog-env/node_modules/surge/bin/surge /home/mayx/public_html/ mayx.surge.sh
|
||||
@@ -0,0 +1 @@
|
||||
curl -LO https://github.com/Homebrew/homebrew-portable-ruby/releases/download/3.4.5/portable-ruby-3.4.5.x86_64_linux.bottle.tar.gz && mkdir -p ~/.local/portable-ruby && tar -xvf portable-ruby-3.4.5.x86_64_linux.bottle.tar.gz -C ~/.local/portable-ruby --strip-components=1 && export PATH="$HOME/.local/portable-ruby/3.4.5/bin:$PATH" && bundle install
|
||||
+8
-15
@@ -5,23 +5,16 @@ title: Archives
|
||||
|
||||
# Archives
|
||||
|
||||
* * *
|
||||
---
|
||||
|
||||
{% for post in site.posts %}
|
||||
{% capture this_year %}{{ post.date | date: "%Y" }}{% endcapture %}
|
||||
{% capture next_year %}{{ post.previous.date | date: "%Y" }}{% endcapture %}
|
||||
{% if forloop.first %}
|
||||
{% assign posts_by_year = site.posts | group_by_exp: "post", "post.date | date: '%Y'" %}
|
||||
|
||||
## {{ this_year }}
|
||||
{% for year in posts_by_year %}
|
||||
|
||||
{% endif %}
|
||||
## {{ year.name }} (共 {{ year.items | size }} 篇)
|
||||
|
||||
- {{ post.date | date: "%Y/%m/%d" }} - [{{ post.title }}{% if post.layout == "encrypt" %} [加密] {% endif %}]({{ post.url }})
|
||||
{% for post in year.items %}
|
||||
- {{ post.date | date: "%Y/%m/%d" }} - [{{ post.title }}{% if post.layout == "encrypt" %} [加密]{% endif %}]({{ post.url }})
|
||||
{% endfor %}
|
||||
|
||||
{% if forloop.last %}
|
||||
{% else %}
|
||||
{% if this_year != next_year %}
|
||||
|
||||
## {{next_year}}
|
||||
|
||||
{% endif %} {% endif %} {% endfor %}
|
||||
{% endfor %}
|
||||
+98
-69
@@ -1,86 +1,95 @@
|
||||
@namespace atom "http://www.w3.org/2005/Atom";
|
||||
@namespace content "http://purl.org/rss/1.0/modules/content/";
|
||||
@namespace dc "http://purl.org/dc/elements/1.1/";
|
||||
@namespace atom url("http://www.w3.org/2005/Atom");
|
||||
@namespace content url("http://purl.org/rss/1.0/modules/content/");
|
||||
@namespace dc url("http://purl.org/dc/elements/1.1/");
|
||||
|
||||
:root {
|
||||
--bg-color: #f4f5f7;
|
||||
--card-bg: #ffffff;
|
||||
--text-main: #222;
|
||||
--text-muted: #555;
|
||||
--text-light: #888;
|
||||
--max-width: 780px;
|
||||
}
|
||||
|
||||
@media (prefers-color-scheme: dark) {
|
||||
:root {
|
||||
--bg-color: #1a1a1c;
|
||||
--card-bg: #2c2c2e;
|
||||
--text-main: #e5e5e7;
|
||||
--text-muted: #a1a1a6;
|
||||
--text-light: #707074;
|
||||
}
|
||||
}
|
||||
|
||||
body,
|
||||
rss,
|
||||
atom|feed {
|
||||
font-family: -apple-system, BlinkMacSystemFont,
|
||||
"Segoe UI", Roboto,
|
||||
"Noto Sans SC", "PingFang SC",
|
||||
"Microsoft YaHei", Arial, sans-serif;
|
||||
background: #f4f5f7;
|
||||
color: #222;
|
||||
margin: 0;
|
||||
padding: 2em 1em;
|
||||
/* 左右内边距 1em,竖屏不贴边 */
|
||||
font-size: 14px;
|
||||
font-family: system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Noto Sans SC", "PingFang SC", "Microsoft YaHei", sans-serif;
|
||||
background: var(--bg-color);
|
||||
color: var(--text-main);
|
||||
margin: 0px auto;
|
||||
padding: 2rem 1rem;
|
||||
font-size: 16px;
|
||||
line-height: 1.6;
|
||||
|
||||
max-width: 780px;
|
||||
/* 最大宽度,桌面端居中 */
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
max-width: var(--max-width);
|
||||
}
|
||||
|
||||
channel>title,
|
||||
atom|feed>atom|title {
|
||||
display: block;
|
||||
font-size: 1.7em;
|
||||
font-weight: 700;
|
||||
margin: 0 0 1.2em 0;
|
||||
font-size: 2rem;
|
||||
font-weight: 800;
|
||||
text-align: center;
|
||||
letter-spacing: -0.01em;
|
||||
margin: 0px 0px 0.5rem;
|
||||
letter-spacing: -0.02em;
|
||||
}
|
||||
|
||||
item,
|
||||
atom|entry {
|
||||
display: block;
|
||||
background: #ffffff;
|
||||
padding: 1.1em 1.2em;
|
||||
margin-bottom: 1.1em;
|
||||
border-radius: 14px;
|
||||
box-shadow:
|
||||
0 8px 24px rgba(0, 0, 0, 0.04),
|
||||
0 2px 6px rgba(0, 0, 0, 0.03);
|
||||
background: var(--card-bg);
|
||||
padding: 1.5rem;
|
||||
margin-bottom: 1.25rem;
|
||||
border-radius: 16px;
|
||||
box-shadow: rgba(0, 0, 0, 0.05) 0px 4px 20px;
|
||||
transition: transform 0.2s;
|
||||
}
|
||||
|
||||
item:hover,
|
||||
atom|entry:hover {
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
|
||||
item>title,
|
||||
atom|entry>atom|title {
|
||||
display: block;
|
||||
font-size: 1.15em;
|
||||
font-size: 1.25rem;
|
||||
font-weight: 600;
|
||||
margin-bottom: 0.45em;
|
||||
color: #111;
|
||||
letter-spacing: -0.01em;
|
||||
margin-bottom: 0.5rem;
|
||||
color: var(--text-main);
|
||||
}
|
||||
|
||||
item>description,
|
||||
atom|entry>atom|summary {
|
||||
display: block;
|
||||
color: #555;
|
||||
line-height: 1.65;
|
||||
max-height: 16.5em;
|
||||
display: -webkit-box;
|
||||
-webkit-box-orient: vertical;
|
||||
-webkit-line-clamp: 4;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
color: var(--text-muted);
|
||||
font-size: 0.95rem;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
item>description::after,
|
||||
atom|entry>atom|summary::after {
|
||||
content: "…";
|
||||
position: absolute;
|
||||
right: 0.3em;
|
||||
bottom: 0;
|
||||
padding-left: 1.5em;
|
||||
background: linear-gradient(to right,
|
||||
rgba(255, 255, 255, 0),
|
||||
#ffffff 70%);
|
||||
font-weight: 600;
|
||||
item>pubDate,
|
||||
atom|entry>atom|updated {
|
||||
display: block;
|
||||
color: var(--text-light);
|
||||
font-size: 0.85rem;
|
||||
margin-top: 0.75rem;
|
||||
}
|
||||
|
||||
link,
|
||||
guid,
|
||||
pubDate,
|
||||
author,
|
||||
category,
|
||||
comments,
|
||||
@@ -88,7 +97,6 @@ source,
|
||||
enclosure,
|
||||
content|encoded,
|
||||
dc|creator,
|
||||
lastBuildDate,
|
||||
atom|id,
|
||||
atom|link,
|
||||
atom|updated,
|
||||
@@ -105,27 +113,48 @@ generator {
|
||||
channel>description,
|
||||
atom|feed>atom|subtitle {
|
||||
display: block;
|
||||
margin: 0.4em 0 2em 0;
|
||||
/* 与条目明显拉开 */
|
||||
text-align: center;
|
||||
color: #666;
|
||||
font-size: 0.95em;
|
||||
color: var(--text-muted);
|
||||
font-size: 1rem;
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
channel>title,
|
||||
atom|feed>atom|title {
|
||||
margin-bottom: 0.4em;
|
||||
/* 原来较紧,这里放松 */
|
||||
}
|
||||
|
||||
atom|feed>atom|subtitle::after,
|
||||
channel>description::after {
|
||||
content: "这是一个订阅源(Feed)。复制当前URL到任何支持 Atom/RSS 的阅读器,即可订阅本博客的最新文章。\A以下展示了此订阅源包含的最新文章:";
|
||||
channel>description::after,
|
||||
atom|feed>atom|subtitle::after {
|
||||
content: "这是一个订阅源(Feed)。复制当前URL到任何支持 Atom/RSS 的阅读器,即可订阅本博客的最新文章。\a 以下展示了此订阅源包含的最新文章:";
|
||||
display: block;
|
||||
text-align: center;
|
||||
font-size: 0.95em;
|
||||
color: #666;
|
||||
margin: 1em 0 2em 0;
|
||||
line-height: 1.5;
|
||||
white-space: pre-wrap;
|
||||
font-size: 0.875rem;
|
||||
color: var(--text-light);
|
||||
margin-top: 1rem;
|
||||
padding: 1rem;
|
||||
border-top-width: 1px;
|
||||
border-top-style: solid;
|
||||
border-top-color: rgba(128, 128, 128, 0.2);
|
||||
}
|
||||
|
||||
rss,
|
||||
channel,
|
||||
atom|feed {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
channel>lastBuildDate,
|
||||
atom|feed>atom|updated:not(atom|entry atom|updated) {
|
||||
order: 999;
|
||||
text-align: center;
|
||||
margin-top: 3rem;
|
||||
padding-top: 1.5rem;
|
||||
border-top-width: 1px;
|
||||
border-top-style: solid;
|
||||
border-top-color: rgba(128, 128, 128, 0.2);
|
||||
color: var(--text-light);
|
||||
font-size: 0.85rem;
|
||||
display: block !important;
|
||||
}
|
||||
|
||||
channel>lastBuildDate::before,
|
||||
atom|feed>atom|updated:not(atom|entry atom|updated)::before {
|
||||
content: "更新于 ";
|
||||
}
|
||||
@@ -1274,5 +1274,3 @@
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
/*# sourceMappingURL=gitalk.css.map*/
|
||||
+39
-13
@@ -34,33 +34,33 @@ a:hover {
|
||||
|
||||
.post-content h1 {
|
||||
text-indent: -8px;
|
||||
margin:20px 0 10px;
|
||||
margin: 20px 0 10px;
|
||||
border-bottom: 1px solid #e5e5e5;
|
||||
}
|
||||
|
||||
.post-content h2 {
|
||||
text-indent: -6px;
|
||||
margin:20px 0 10px;
|
||||
margin: 20px 0 10px;
|
||||
border-bottom: 1px solid #e5e5e5;
|
||||
}
|
||||
|
||||
.post-content h3 {
|
||||
margin:20px 0 10px;
|
||||
margin: 20px 0 10px;
|
||||
text-indent: -5px;
|
||||
}
|
||||
|
||||
.post-content h4 {
|
||||
margin:20px 0 10px;
|
||||
margin: 20px 0 10px;
|
||||
text-indent: -4px;
|
||||
}
|
||||
|
||||
.post-content h5 {
|
||||
margin:20px 0 10px;
|
||||
margin: 20px 0 10px;
|
||||
text-indent: -3px;
|
||||
}
|
||||
|
||||
.post-content h6 {
|
||||
margin:20px 0 10px;
|
||||
margin: 20px 0 10px;
|
||||
text-indent: -2px;
|
||||
}
|
||||
|
||||
@@ -121,24 +121,30 @@ div.highlight button:hover {
|
||||
font-size: 14px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
.footnotes p {
|
||||
margin: 0;
|
||||
text-indent: 0;
|
||||
}
|
||||
|
||||
.wrapper{
|
||||
.wrapper {
|
||||
width: 90%;
|
||||
}
|
||||
header{
|
||||
|
||||
header {
|
||||
width: 25%;
|
||||
}
|
||||
footer{
|
||||
|
||||
footer {
|
||||
width: 25%;
|
||||
}
|
||||
section{
|
||||
|
||||
section {
|
||||
width: 65%;
|
||||
}
|
||||
@media print, screen and (max-width: 960px) {
|
||||
|
||||
@media print,
|
||||
screen and (max-width: 960px) {
|
||||
.wrapper {
|
||||
width: auto;
|
||||
}
|
||||
@@ -156,7 +162,7 @@ section{
|
||||
}
|
||||
}
|
||||
|
||||
code.highlighter-rouge{
|
||||
code.highlighter-rouge {
|
||||
padding: .1em .2em;
|
||||
margin: 0;
|
||||
font-size: 90%;
|
||||
@@ -171,9 +177,29 @@ code.highlighter-rouge{
|
||||
border: 1px solid #ddd;
|
||||
padding: 8px 12px;
|
||||
border-radius: 4px;
|
||||
box-shadow: 0 2px 10px rgba(0,0,0,0.1);
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.1);
|
||||
max-width: 300px;
|
||||
z-index: 1000;
|
||||
font-size: 14px;
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
td.h-entry {
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
td.h-entry:hover {
|
||||
background: #f9f9f9;
|
||||
}
|
||||
|
||||
body.pjax-loading::after {
|
||||
content: '';
|
||||
position: fixed;
|
||||
top: 16px;
|
||||
right: 16px;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
background: url('/images/loading.svg') center / contain no-repeat;
|
||||
z-index: 9999;
|
||||
pointer-events: none;
|
||||
}
|
||||
Vendored
-1
@@ -32,4 +32,3 @@ var i=Object.getOwnPropertySymbols,r=Object.prototype.hasOwnProperty,o=Object.pr
|
||||
http://www.jacklmoore.com/autosize
|
||||
*/
|
||||
!function(n,o){i=[t,e],a=o,void 0!==(r="function"==typeof a?a.apply(t,i):a)&&(e.exports=r)}(0,function(e,t){"use strict";function n(e){function t(t){var n=e.style.width;e.style.width="0px",e.offsetWidth,e.style.width=n,e.style.overflowY=t}function n(e){for(var t=[];e&&e.parentNode&&e.parentNode instanceof Element;)e.parentNode.scrollTop&&t.push({node:e.parentNode,scrollTop:e.parentNode.scrollTop}),e=e.parentNode;return t}function a(){var t=e.style.height,a=n(e),i=document.documentElement&&document.documentElement.scrollTop;e.style.height="auto";var r=e.scrollHeight+u;if(0===e.scrollHeight)return void(e.style.height=t);e.style.height=r+"px",s=e.clientWidth,a.forEach(function(e){e.node.scrollTop=e.scrollTop}),i&&(document.documentElement.scrollTop=i)}function i(){a();var n=Math.round(parseFloat(e.style.height)),i=window.getComputedStyle(e,null),r="content-box"===i.boxSizing?Math.round(parseFloat(i.height)):e.offsetHeight;if(r!==n?"hidden"===i.overflowY&&(t("scroll"),a(),r="content-box"===i.boxSizing?Math.round(parseFloat(window.getComputedStyle(e,null).height)):e.offsetHeight):"hidden"!==i.overflowY&&(t("hidden"),a(),r="content-box"===i.boxSizing?Math.round(parseFloat(window.getComputedStyle(e,null).height)):e.offsetHeight),d!==r){d=r;var u=o("autosize:resized");try{e.dispatchEvent(u)}catch(e){}}}if(e&&e.nodeName&&"TEXTAREA"===e.nodeName&&!r.has(e)){var u=null,s=e.clientWidth,d=null,c=function(){e.clientWidth!==s&&i()},l=function(t){window.removeEventListener("resize",c,!1),e.removeEventListener("input",i,!1),e.removeEventListener("keyup",i,!1),e.removeEventListener("autosize:destroy",l,!1),e.removeEventListener("autosize:update",i,!1),Object.keys(t).forEach(function(n){e.style[n]=t[n]}),r.delete(e)}.bind(e,{height:e.style.height,resize:e.style.resize,overflowY:e.style.overflowY,overflowX:e.style.overflowX,wordWrap:e.style.wordWrap});e.addEventListener("autosize:destroy",l,!1),"onpropertychange"in e&&"oninput"in e&&e.addEventListener("keyup",i,!1),window.addEventListener("resize",c,!1),e.addEventListener("input",i,!1),e.addEventListener("autosize:update",i,!1),e.style.overflowX="hidden",e.style.wordWrap="break-word",r.set(e,{destroy:l,update:i}),function(){var t=window.getComputedStyle(e,null);"vertical"===t.resize?e.style.resize="none":"both"===t.resize&&(e.style.resize="horizontal"),u="content-box"===t.boxSizing?-(parseFloat(t.paddingTop)+parseFloat(t.paddingBottom)):parseFloat(t.borderTopWidth)+parseFloat(t.borderBottomWidth),isNaN(u)&&(u=0),i()}()}}function a(e){var t=r.get(e);t&&t.destroy()}function i(e){var t=r.get(e);t&&t.update()}var r="function"==typeof Map?new Map:function(){var e=[],t=[];return{has:function(t){return e.indexOf(t)>-1},get:function(n){return t[e.indexOf(n)]},set:function(n,a){-1===e.indexOf(n)&&(e.push(n),t.push(a))},delete:function(n){var a=e.indexOf(n);a>-1&&(e.splice(a,1),t.splice(a,1))}}}(),o=function(e){return new Event(e,{bubbles:!0})};try{new Event("test")}catch(e){o=function(e){var t=document.createEvent("Event");return t.initEvent(e,!0,!1),t}}var u=null;"undefined"==typeof window||"function"!=typeof window.getComputedStyle?(u=function(e){return e},u.destroy=function(e){return e},u.update=function(e){return e}):(u=function(e,t){return e&&Array.prototype.forEach.call(e.length?e:[e],function(e){return n(e)}),e},u.destroy=function(e){return e&&Array.prototype.forEach.call(e.length?e:[e],a),e},u.update=function(e){return e&&Array.prototype.forEach.call(e.length?e:[e],i),e}),t.exports=u})},function(e,t,n){"use strict";function a(e){return e&&e.__esModule?e:{default:e}}Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e){return new r.default({phrases:W[e]||W.en,locale:e})};var i=n(261),r=a(i),o=n(262),u=a(o),s=n(263),d=a(s),c=n(264),l=a(c),m=n(265),f=a(m),h=n(266),p=a(h),g=n(267),v=a(g),w=n(268),b=a(w),y=n(269),M=a(y),k=n(270),P=a(k),W={zh:u.default,"zh-CN":u.default,"zh-TW":d.default,en:l.default,"es-ES":f.default,fr:p.default,ru:v.default,de:b.default,pl:M.default,ko:P.default}},function(e,t,n){var a,i;!function(n,r){a=[],void 0!==(i=function(){return r(n)}.apply(t,a))&&(e.exports=i)}(this,function(e){"use strict";function t(e){e=e||{},this.phrases={},this.extend(e.phrases||{}),this.currentLocale=e.locale||"en",this.allowMissing=!!e.allowMissing,this.warn=e.warn||s}function n(e){var t,n,a,i={};for(t in e)if(e.hasOwnProperty(t)){n=e[t];for(a in n)i[n[a]]=t}return i}function a(e){var t=/^\s+|\s+$/g;return e.replace(t,"")}function i(e,t,n){var i,r,u;return null!=n&&e?(r=e.split(c),u=r[o(t,n)]||r[0],i=a(u)):i=e,i}function r(e){var t=n(m);return t[e]||t.en}function o(e,t){return l[r(e)](t)}function u(e,t){for(var n in t)"_"!==n&&t.hasOwnProperty(n)&&(e=e.replace(new RegExp("%\\{"+n+"\\}","g"),t[n]));return e}function s(t){e.console&&e.console.warn&&e.console.warn("WARNING: "+t)}function d(e){var t={};for(var n in e)t[n]=e[n];return t}t.VERSION="0.4.3",t.prototype.locale=function(e){return e&&(this.currentLocale=e),this.currentLocale},t.prototype.extend=function(e,t)Line truncated
|
||||
//# sourceMappingURL=gitalk.min.js.map
|
||||
Vendored
+5
-5
@@ -1,5 +1,5 @@
|
||||
/*! jQuery v1.9.1 | (c) 2005, 2012 jQuery Foundation, Inc. | jquery.org/license
|
||||
//@ sourceMappingURL=jquery.min.map
|
||||
*/(function(e,t){var n,r,i=typeof t,o=e.document,a=e.location,s=e.jQuery,u=e.$,l={},c=[],p="1.9.1",f=c.concat,d=c.push,h=c.slice,g=c.indexOf,m=l.toString,y=l.hasOwnProperty,v=p.trim,b=function(e,t){return new b.fn.init(e,t,r)},x=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,w=/\S+/g,T=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,N=/^(?:(<[\w\W]+>)[^>]*|#([\w-]*))$/,C=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,k=/^[\],:{}\s]*$/,E=/(?:^|:|,)(?:\s*\[)+/g,S=/\\(?:["\\\/bfnrt]|u[\da-fA-F]{4})/g,A=/"[^"\\\r\n]*"|true|false|null|-?(?:\d+\.|)\d+(?:[eE][+-]?\d+|)/g,j=/^-ms-/,D=/-([\da-z])/gi,L=function(e,t){return t.toUpperCase()},H=function(e){(o.addEventListener||"load"===e.type||"complete"===o.readyState)&&(q(),b.ready())},q=function(){o.addEventListener?(o.removeEventListener("DOMContentLoaded",H,!1),e.removeEventListener("load",H,!1)):(o.detachEvent("onreadystatechange",H),e.detachEvent("onload",H))};b.fn=b.prototype={jquery:p,constructor:b,init:function(e,n,r){var i,a;if(!e)return this;if("string"==typeof e){if(i="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:N.exec(e),!i||!i[1]&&n)return!n||n.jquery?(n||r).find(e):this.constructor(n).find(e);if(i[1]){if(n=n instanceof b?n[0]:n,b.merge(this,b.parseHTML(i[1],n&&n.nodeType?n.ownerDocument||n:o,!0)),C.test(i[1])&&b.isPlainObject(n))for(i in n)b.isFunction(this[i])?this[i](n[i]):this.attr(i,n[i]);return this}if(a=o.getElementById(i[2]),a&&a.parentNode){if(a.id!==i[2])return r.find(e);this.length=1,this[0]=a}return this.context=o,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):b.isFunction(e)?r.ready(e):(e.selector!==t&&(this.selector=e.selector,this.context=e.context),b.makeArray(e,this))},selector:"",length:0,size:function(){return this.length},toArray:function(){return h.call(this)},get:function(e){return null==e?this.toArray():0>e?this[this.length+e]:this[e]},pushStack:function(e){var t=b.merge(this.constructor(),e);return t.prevObject=this,t.context=this.context,t},each:function(e,t){return b.each(this,e,t)},ready:function(e){return b.ready.promise().done(e),this},slice:function(){return this.pushStack(h.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(0>e?t:0);return this.pushStack(n>=0&&t>n?[this[n]]:[])},map:function(e){return this.pushStack(b.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:d,sort:[].sort,splice:[].splice},b.fn.init.prototype=b.fn,b.extend=b.fn.extend=function(){var e,n,r,i,o,a,s=arguments[0]||{},u=1,l=arguments.length,c=!1;for("boolean"==typeof s&&(c=s,s=arguments[1]||{},u=2),"object"==typeof s||b.isFunction(s)||(s={}),l===u&&(s=this,--u);l>u;u++)if(null!=(o=arguments[u]))for(i in o)e=s[i],r=o[i],s!==r&&(c&&r&&(b.isPlainObject(r)||(n=b.isArray(r)))?(n?(n=!1,a=e&&b.isArray(e)?e:[]):a=e&&b.isPlainObject(e)?e:{},s[i]=b.extend(c,a,r)):r!==t&&(s[i]=r));return s},b.extend({noConflict:function(t){return e.$===b&&(e.$=u),t&&e.jQuery===b&&(e.jQuery=s),b},isReady:!1,readyWait:1,holdReady:function(e){e?b.readyWait++:b.ready(!0)},ready:function(e){if(e===!0?!--b.readyWait:!b.isReady){if(!o.body)return setTimeout(b.ready);b.isReady=!0,e!==!0&&--b.readyWait>0||(n.resolveWith(o,[b]),b.fn.trigger&&b(o).trigger("ready").off("ready"))}},isFunction:function(e){return"function"===b.type(e)},isArray:Array.isArray||function(e){return"array"===b.type(e)},isWindow:function(e){return null!=e&&e==e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?l[m.call(e)]||"object":typeof e},isPlainObject:function(e){if(!e||"object"!==b.type(e)||e.nodeType||b.isWindow(e))return!1;try{if(e.constructor&&!y.call(e,"constructor")&&!y.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(n){return!1}var r;for(r in e);return r===t||y.call(e,r)},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw Error(e)},parseHTML:function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||o;var r=C.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=b.buildFragment([e],t,i),i&&b(i).remove(),b.merge([],r.childNodes))},parseJSON:function(n){return e.JSON&&e.JSON.parse?e.JSON.parse(n):null===n?n:"string"==typeof n&&(n=b.trim(n),n&&k.test(n.replace(S,"@").replace(A,"]").replace(E,"")))?Function("return "+n)():(b.error("Invalid JSON: "+n),t)},parseXML:function(n){var r,i;if(!n||"string"!=typeof n)return null;try{e.DOMParser?(i=new DOMParser,r=i.parseFromString(n,"text/xml")):(r=new ActiveXObject("Microsoft.XMLDOM"),r.async="false",r.loadXML(n))}catch(o){r=t}return r&&r.documentElement&&!r.getElementsByTagName("parsererror").length||b.error("Invalid XML: "+n),r},noop:function(){},globalEval:function(t){t&&b.trim(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(j,"ms-").replace(D,L)},nodeName:function(Line truncated
|
||||
return(!i||i!==r&&!b.contains(r,i))&&(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),b.support.submitBubbles||(b.event.special.submit={setup:function(){return b.nodeName(this,"form")?!1:(b.event.add(this,"click._submit keypress._submit",function(e){var n=e.target,r=b.nodeName(n,"input")||b.nodeName(n,"button")?n.form:t;r&&!b._data(r,"submitBubbles")&&(b.event.add(r,"submit._submit",function(e){e._submit_bubble=!0}),b._data(r,"submitBubbles",!0))}),t)},postDispatch:function(e){e._submit_bubble&&(delete e._submit_bubble,this.parentNode&&!e.isTrigger&&b.event.simulate("submit",this.parentNode,e,!0))},teardown:function(){return b.nodeName(this,"form")?!1:(b.event.remove(this,"._submit"),t)}}),b.support.changeBubbles||(b.event.special.change={setup:function(){return Z.test(this.nodeName)?(("checkbox"===this.type||"radio"===this.type)&&(b.event.add(this,"propertychange._change",function(e){"checked"===e.originalEvent.propertyName&&(this._just_changed=!0)}),b.event.add(this,"click._change",function(e){this._just_changed&&!e.isTrigger&&(this._just_changed=!1),b.event.simulate("change",this,e,!0)})),!1):(b.event.add(this,"beforeactivate._change",function(e){var t=e.target;Z.test(t.nodeName)&&!b._data(t,"changeBubbles")&&(b.event.add(t,"change._change",function(e){!this.parentNode||e.isSimulated||e.isTrigger||b.event.simulate("change",this.parentNode,e,!0)}),b._data(t,"changeBubbles",!0))}),t)},handle:function(e){var n=e.target;return this!==n||e.isSimulated||e.isTrigger||"radio"!==n.type&&"checkbox"!==n.type?e.handleObj.handler.apply(this,arguments):t},teardown:function(){return b.event.remove(this,"._change"),!Z.test(this.nodeName)}}),b.support.focusinBubbles||b.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){b.event.simulate(t,e.target,b.event.fix(e),!0)};b.event.special[t]={setup:function(){0===n++&&o.addEventListener(e,r,!0)},teardown:function(){0===--n&&o.removeEventListener(e,r,!0)}}}),b.fn.extend({on:function(e,n,r,i,o){var a,s;if("object"==typeof e){"string"!=typeof n&&(r=r||n,n=t);for(a in e)this.on(a,n,r,e[a],o);return this}if(null==r&&null==i?(i=n,r=n=t):null==i&&("string"==typeof n?(i=r,r=t):(i=r,r=n,n=t)),i===!1)i=ot;else if(!i)return this;return 1===o&&(s=i,i=function(e){return b().off(e),s.apply(this,arguments)},i.guid=s.guid||(s.guid=b.guid++)),this.each(function(){b.event.add(this,e,i,r,n)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,n,r){var i,o;if(e&&e.preventDefault&&e.handleObj)return i=e.handleObj,b(e.delegateTarget).off(i.namespace?i.origType+"."+i.namespace:i.origType,i.selector,i.handler),this;if("object"==typeof e){for(o in e)this.off(o,n,e[o]);return this}return(n===!1||"function"==typeof n)&&(r=n,n=t),r===!1&&(r=ot),this.each(function(){b.event.remove(this,e,r,n)})},bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},trigger:function(e,t){return this.each(function(){b.event.trigger(e,t,this)})},triggerHandler:function(e,n){var r=this[0];return r?b.event.trigger(e,n,r,!0):t}}),function(e,t){var n,r,i,o,a,s,u,l,c,p,f,d,h,g,m,y,v,x="sizzle"+-new Date,w=e.document,T={},N=0,C=0,k=it(),E=it(),S=it(),A=typeof t,j=1<<31,D=[],L=D.pop,H=D.push,q=D.slice,M=D.indexOf||function(e){var t=0,n=this.length;for(;n>t;t++)if(this[t]===e)return t;return-1},_="[\\x20\\t\\r\\n\\f]",F="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",O=F.replace("w","w#"),B="([*^$|!~]?=)",P="\\["+_+"*("+F+")"+_+"*(?:"+B+_+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+O+")|)|)"+_+"*\\]",R=":("+F+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+P.replace(3,8)+")*)|.*)\\)|)",W=RegExp("^"+_+"+|((?:^|[^\\\\])(?:\\\\.)*)"+_+"+$","g"),$=RegExp("^"+_+"*,"+_+"*"),I=RegExp("^"+_+"*([\\x20\\t\\r\\n\\f>+~])"+_+"*"),z=RegExp(R),X=RegExp("^"+O+"$"),U={ID:RegExp("^#("+F+")"),CLASS:RegExp("^\\.("+F+")"),NAME:RegExp("^\\[name=['\"]?("+F+")['\"]?\\]"),TAG:RegExp("^("+F.replace("w","w*")+")"),ATTR:RegExp("^"+P),PSEUDO:RegExp("^"+R),CHILD:RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+_+"*(even|odd|(([+-]|)(\\d*)n|)"+_+"*(?:([+-]|)"+_+"*(\\d+)|))"+_+"*\\)|)","i"),needsContext:RegExp("^"+_+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+_+"*((?:-\\d)?\\d*)"+_+"*\\)|)(?=[^-]|$)","i")},V=/[\x20\t\r\n\f]*[+~]/,Y=/^[^{]+\{\s*\[native code/,J=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,G=/^(?:input|select|textarea|button)$/i,Q=/^h\d$/i,K=/'|\\/g,Z=/\=[\x20\t\r\n\f]*([^'"\]]*)[\x20\t\r\n\f]*\]/g,et=/\\([\da-fA-F]{1,6}[\x20\t\r\n\f]?|.)/g,tt=function(e,t){var n="0x"+t-65536;return n!==n?t:0>n?String.fromCharCode(n+65536):String.fromCharCode(55296|n>>10,56320|1023&n)};try{q.call(w.documentElement.childNodes,0)[0].nodeType}catch(nt){q=function(e){var t,n=[];while(t=this[e++])n.push(t);return n}}function rt(e){return Y.test(e+"")}function it(){var e,t=[];return e=function(n,r){return t.push(n+Line truncated
|
||||
}b.merge(d,s.childNodes),s.textContent="";while(s.firstChild)s.removeChild(s.firstChild);s=f.lastChild}else d.push(t.createTextNode(o));s&&f.removeChild(s),b.support.appendChecked||b.grep(Ot(d,"input"),Bt),h=0;while(o=d[h++])if((!r||-1===b.inArray(o,r))&&(a=b.contains(o.ownerDocument,o),s=Ot(f.appendChild(o),"script"),a&&Mt(s),n)){i=0;while(o=s[i++])kt.test(o.type||"")&&n.push(o)}return s=null,f},cleanData:function(e,t){var n,r,o,a,s=0,u=b.expando,l=b.cache,p=b.support.deleteExpando,f=b.event.special;for(;null!=(n=e[s]);s++)if((t||b.acceptData(n))&&(o=n[u],a=o&&l[o])){if(a.events)for(r in a.events)f[r]?b.event.remove(n,r):b.removeEvent(n,r,a.handle);l[o]&&(delete l[o],p?delete n[u]:typeof n.removeAttribute!==i?n.removeAttribute(u):n[u]=null,c.push(o))}}});var Pt,Rt,Wt,$t=/alpha\([^)]*\)/i,It=/opacity\s*=\s*([^)]*)/,zt=/^(top|right|bottom|left)$/,Xt=/^(none|table(?!-c[ea]).+)/,Ut=/^margin/,Vt=RegExp("^("+x+")(.*)$","i"),Yt=RegExp("^("+x+")(?!px)[a-z%]+$","i"),Jt=RegExp("^([+-])=("+x+")","i"),Gt={BODY:"block"},Qt={position:"absolute",visibility:"hidden",display:"block"},Kt={letterSpacing:0,fontWeight:400},Zt=["Top","Right","Bottom","Left"],en=["Webkit","O","Moz","ms"];function tn(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=en.length;while(i--)if(t=en[i]+n,t in e)return t;return r}function nn(e,t){return e=t||e,"none"===b.css(e,"display")||!b.contains(e.ownerDocument,e)}function rn(e,t){var n,r,i,o=[],a=0,s=e.length;for(;s>a;a++)r=e[a],r.style&&(o[a]=b._data(r,"olddisplay"),n=r.style.display,t?(o[a]||"none"!==n||(r.style.display=""),""===r.style.display&&nn(r)&&(o[a]=b._data(r,"olddisplay",un(r.nodeName)))):o[a]||(i=nn(r),(n&&"none"!==n||!i)&&b._data(r,"olddisplay",i?n:b.css(r,"display"))));for(a=0;s>a;a++)r=e[a],r.style&&(t&&"none"!==r.style.display&&""!==r.style.display||(r.style.display=t?o[a]||"":"none"));return e}b.fn.extend({css:function(e,n){return b.access(this,function(e,n,r){var i,o,a={},s=0;if(b.isArray(n)){for(o=Rt(e),i=n.length;i>s;s++)a[n[s]]=b.css(e,n[s],!1,o);return a}return r!==t?b.style(e,n,r):b.css(e,n)},e,n,arguments.length>1)},show:function(){return rn(this,!0)},hide:function(){return rn(this)},toggle:function(e){var t="boolean"==typeof e;return this.each(function(){(t?e:nn(this))?b(this).show():b(this).hide()})}}),b.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Wt(e,"opacity");return""===n?"1":n}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":b.support.cssFloat?"cssFloat":"styleFloat"},style:function(e,n,r,i){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var o,a,s,u=b.camelCase(n),l=e.style;if(n=b.cssProps[u]||(b.cssProps[u]=tn(l,u)),s=b.cssHooks[n]||b.cssHooks[u],r===t)return s&&"get"in s&&(o=s.get(e,!1,i))!==t?o:l[n];if(a=typeof r,"string"===a&&(o=Jt.exec(r))&&(r=(o[1]+1)*o[2]+parseFloat(b.css(e,n)),a="number"),!(null==r||"number"===a&&isNaN(r)||("number"!==a||b.cssNumber[u]||(r+="px"),b.support.clearCloneStyle||""!==r||0!==n.indexOf("background")||(l[n]="inherit"),s&&"set"in s&&(r=s.set(e,r,i))===t)))try{l[n]=r}catch(c){}}},css:function(e,n,r,i){var o,a,s,u=b.camelCase(n);return n=b.cssProps[u]||(b.cssProps[u]=tn(e.style,u)),s=b.cssHooks[n]||b.cssHooks[u],s&&"get"in s&&(a=s.get(e,!0,r)),a===t&&(a=Wt(e,n,i)),"normal"===a&&n in Kt&&(a=Kt[n]),""===r||r?(o=parseFloat(a),r===!0||b.isNumeric(o)?o||0:a):a},swap:function(e,t,n,r){var i,o,a={};for(o in t)a[o]=e.style[o],e.style[o]=t[o];i=n.apply(e,r||[]);for(o in t)e.style[o]=a[o];return i}}),e.getComputedStyle?(Rt=function(t){return e.getComputedStyle(t,null)},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),u=s?s.getPropertyValue(n)||s[n]:t,l=e.style;return s&&(""!==u||b.contains(e.ownerDocument,e)||(u=b.style(e,n)),Yt.test(u)&&Ut.test(n)&&(i=l.width,o=l.minWidth,a=l.maxWidth,l.minWidth=l.maxWidth=l.width=u,u=s.width,l.width=i,l.minWidth=o,l.maxWidth=a)),u}):o.documentElement.currentStyle&&(Rt=function(e){return e.currentStyle},Wt=function(e,n,r){var i,o,a,s=r||Rt(e),u=s?s[n]:t,l=e.style;return null==u&&l&&l[n]&&(u=l[n]),Yt.test(u)&&!zt.test(n)&&(i=l.left,o=e.runtimeStyle,a=o&&o.left,a&&(o.left=e.currentStyle.left),l.left="fontSize"===n?"1em":u,u=l.pixelLeft+"px",l.left=i,a&&(o.left=a)),""===u?"auto":u});function on(e,t,n){var r=Vt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function an(e,t,n,r,i){var o=n===(r?"border":"content")?4:"width"===t?1:0,a=0;for(;4>o;o+=2)"margin"===n&&(a+=b.css(e,n+Zt[o],!0,i)),r?("content"===n&&(a-=b.css(e,"padding"+Zt[o],!0,i)),"margin"!==n&&(a-=b.css(e,"border"+Zt[o]+"Width",!0,i))):(a+=b.css(e,"padding"+Zt[o],!0,i),"padding"!==n&&(a+=b.css(e,"border"+Zt[o]+"Width",!0,i)));return a}function sn(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=Rt(e),a=b.support.boxSizing&&"border-box"===b.css(e,"boxSizing",!1,o);if(0>=i||null==i){if(i=Wt(e,t,o),(0>i||null==i)&&(i=e.style[t]),Yt.test(i))return i;r=a&&(b.support.boxSizingReliable||i===e.style[t]),i=parseFloat(i)||0}reLine truncated
|
||||
/*! jQuery v1.12.4 | (c) jQuery Foundation | jquery.org/license */
|
||||
!function(a,b){"object"==typeof module&&"object"==typeof module.exports?module.exports=a.document?b(a,!0):function(a){if(!a.document)throw new Error("jQuery requires a window with a document");return b(a)}:b(a)}("undefined"!=typeof window?window:this,function(a,b){var c=[],d=a.document,e=c.slice,f=c.concat,g=c.push,h=c.indexOf,i={},j=i.toString,k=i.hasOwnProperty,l={},m="1.12.4",n=function(a,b){return new n.fn.init(a,b)},o=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g,p=/^-ms-/,q=/-([\da-z])/gi,r=function(a,b){return b.toUpperCase()};n.fn=n.prototype={jquery:m,constructor:n,selector:"",length:0,toArray:function(){return e.call(this)},get:function(a){return null!=a?0>a?this[a+this.length]:this[a]:e.call(this)},pushStack:function(a){var b=n.merge(this.constructor(),a);return b.prevObject=this,b.context=this.context,b},each:function(a){return n.each(this,a)},map:function(a){return this.pushStack(n.map(this,function(b,c){return a.call(b,c,b)}))},slice:function(){return this.pushStack(e.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(a){var b=this.length,c=+a+(0>a?b:0);return this.pushStack(c>=0&&b>c?[this[c]]:[])},end:function(){return this.prevObject||this.constructor()},push:g,sort:c.sort,splice:c.splice},n.extend=n.fn.extend=function(){var a,b,c,d,e,f,g=arguments[0]||{},h=1,i=arguments.length,j=!1;for("boolean"==typeof g&&(j=g,g=arguments[h]||{},h++),"object"==typeof g||n.isFunction(g)||(g={}),h===i&&(g=this,h--);i>h;h++)if(null!=(e=arguments[h]))for(d in e)a=g[d],c=e[d],g!==c&&(j&&c&&(n.isPlainObject(c)||(b=n.isArray(c)))?(b?(b=!1,f=a&&n.isArray(a)?a:[]):f=a&&n.isPlainObject(a)?a:{},g[d]=n.extend(j,f,c)):void 0!==c&&(g[d]=c));return g},n.extend({expando:"jQuery"+(m+Math.random()).replace(/\D/g,""),isReady:!0,error:function(a){throw new Error(a)},noop:function(){},isFunction:function(a){return"function"===n.type(a)},isArray:Array.isArray||function(a){return"array"===n.type(a)},isWindow:function(a){return null!=a&&a==a.window},isNumeric:function(a){var b=a&&a.toString();return!n.isArray(a)&&b-parseFloat(b)+1>=0},isEmptyObject:function(a){var b;for(b in a)return!1;return!0},isPlainObject:function(a){var b;if(!a||"object"!==n.type(a)||a.nodeType||n.isWindow(a))return!1;try{if(a.constructor&&!k.call(a,"constructor")&&!k.call(a.constructor.prototype,"isPrototypeOf"))return!1}catch(c){return!1}if(!l.ownFirst)for(b in a)return k.call(a,b);for(b in a);return void 0===b||k.call(a,b)},type:function(a){return null==a?a+"":"object"==typeof a||"function"==typeof a?i[j.call(a)]||"object":typeof a},globalEval:function(b){b&&n.trim(b)&&(a.execScript||function(b){a.eval.call(a,b)})(b)},camelCase:function(a){return a.replace(p,"ms-").replace(q,r)},nodeName:function(a,b){return a.nodeName&&a.nodeName.toLowerCase()===b.toLowerCase()},each:function(a,b){var c,d=0;if(s(a)){for(c=a.length;c>d;d++)if(b.call(a[d],d,a[d])===!1)break}else for(d in a)if(b.call(a[d],d,a[d])===!1)break;return a},trim:function(a){return null==a?"":(a+"").replace(o,"")},makeArray:function(a,b){var c=b||[];return null!=a&&(s(Object(a))?n.merge(c,"string"==typeof a?[a]:a):g.call(c,a)),c},inArray:function(a,b,c){var d;if(b){if(h)return h.call(b,a,c);for(d=b.length,c=c?0>c?Math.max(0,d+c):c:0;d>c;c++)if(c in b&&b[c]===a)return c}return-1},merge:function(a,b){var c=+b.length,d=0,e=a.length;while(c>d)a[e++]=b[d++];if(c!==c)while(void 0!==b[d])a[e++]=b[d++];return a.length=e,a},grep:function(a,b,c){for(var d,e=[],f=0,g=a.length,h=!c;g>f;f++)d=!b(a[f],f),d!==h&&e.push(a[f]);return e},map:function(a,b,c){var d,e,g=0,h=[];if(s(a))for(d=a.length;d>g;g++)e=b(a[g],g,c),null!=e&&h.push(e);else for(g in a)e=b(a[g],g,c),null!=e&&h.push(e);return f.apply([],h)},guid:1,proxy:function(a,b){var c,d,f;return"string"==typeof b&&(f=a[b],b=a,a=f),n.isFunction(a)?(c=e.call(arguments,2),d=function(){return a.apply(b||this,c.concat(e.call(arguments)))},d.guid=a.guid=a.guid||n.guid++,d):void 0},now:function(){return+new Date},support:l}),"function"==typeof Symbol&&(n.fn[Symbol.iterator]=c[Symbol.iterator]),n.each("Boolean Number String Function Array Date RegExp Object Error Symbol".split(" "),function(a,b){i["[object "+b+"]"]=b.toLowerCase()});function s(a){var b=!!a&&"length"in a&&a.length,c=n.type(a);return"function"===c||n.isWindow(a)?!1:"array"===c||0===b||"number"==typeof b&&b>0&&b-1 in a}var t=function(a){var b,c,d,e,f,g,h,i,j,k,l,m,n,o,p,q,r,s,t,u="sizzle"+1*new Date,v=a.document,w=0,x=0,y=ga(),z=ga(),A=ga(),B=function(a,b){return a===b&&(l=!0),0},C=1<<31,D={}.hasOwnProperty,E=[],F=E.pop,G=E.push,H=E.push,I=E.slice,J=function(a,b){for(var c=0,d=a.length;d>c;c++)if(a[c]===b)return c;return-1},K="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",L="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",N="\\["+L+"*("+M+")(?:"+L+"*([*^$|!~]?=)"+L+"*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|("+M+"))|)"+L+"*\\]",O=":("+M+")(?:\\((('((?:\\\\.|Line truncated
|
||||
}return c}function Q(a){var b;for(b in a)if(("data"!==b||!n.isEmptyObject(a[b]))&&"toJSON"!==b)return!1;return!0}function R(a,b,d,e){if(M(a)){var f,g,h=n.expando,i=a.nodeType,j=i?n.cache:a,k=i?a[h]:a[h]&&h;if(k&&j[k]&&(e||j[k].data)||void 0!==d||"string"!=typeof b)return k||(k=i?a[h]=c.pop()||n.guid++:h),j[k]||(j[k]=i?{}:{toJSON:n.noop}),"object"!=typeof b&&"function"!=typeof b||(e?j[k]=n.extend(j[k],b):j[k].data=n.extend(j[k].data,b)),g=j[k],e||(g.data||(g.data={}),g=g.data),void 0!==d&&(g[n.camelCase(b)]=d),"string"==typeof b?(f=g[b],null==f&&(f=g[n.camelCase(b)])):f=g,f}}function S(a,b,c){if(M(a)){var d,e,f=a.nodeType,g=f?n.cache:a,h=f?a[n.expando]:n.expando;if(g[h]){if(b&&(d=c?g[h]:g[h].data)){n.isArray(b)?b=b.concat(n.map(b,n.camelCase)):b in d?b=[b]:(b=n.camelCase(b),b=b in d?[b]:b.split(" ")),e=b.length;while(e--)delete d[b[e]];if(c?!Q(d):!n.isEmptyObject(d))return}(c||(delete g[h].data,Q(g[h])))&&(f?n.cleanData([a],!0):l.deleteExpando||g!=g.window?delete g[h]:g[h]=void 0)}}}n.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(a){return a=a.nodeType?n.cache[a[n.expando]]:a[n.expando],!!a&&!Q(a)},data:function(a,b,c){return R(a,b,c)},removeData:function(a,b){return S(a,b)},_data:function(a,b,c){return R(a,b,c,!0)},_removeData:function(a,b){return S(a,b,!0)}}),n.fn.extend({data:function(a,b){var c,d,e,f=this[0],g=f&&f.attributes;if(void 0===a){if(this.length&&(e=n.data(f),1===f.nodeType&&!n._data(f,"parsedAttrs"))){c=g.length;while(c--)g[c]&&(d=g[c].name,0===d.indexOf("data-")&&(d=n.camelCase(d.slice(5)),P(f,d,e[d])));n._data(f,"parsedAttrs",!0)}return e}return"object"==typeof a?this.each(function(){n.data(this,a)}):arguments.length>1?this.each(function(){n.data(this,a,b)}):f?P(f,a,n.data(f,a)):void 0},removeData:function(a){return this.each(function(){n.removeData(this,a)})}}),n.extend({queue:function(a,b,c){var d;return a?(b=(b||"fx")+"queue",d=n._data(a,b),c&&(!d||n.isArray(c)?d=n._data(a,b,n.makeArray(c)):d.push(c)),d||[]):void 0},dequeue:function(a,b){b=b||"fx";var c=n.queue(a,b),d=c.length,e=c.shift(),f=n._queueHooks(a,b),g=function(){n.dequeue(a,b)};"inprogress"===e&&(e=c.shift(),d--),e&&("fx"===b&&c.unshift("inprogress"),delete f.stop,e.call(a,g,f)),!d&&f&&f.empty.fire()},_queueHooks:function(a,b){var c=b+"queueHooks";return n._data(a,c)||n._data(a,c,{empty:n.Callbacks("once memory").add(function(){n._removeData(a,b+"queue"),n._removeData(a,c)})})}}),n.fn.extend({queue:function(a,b){var c=2;return"string"!=typeof a&&(b=a,a="fx",c--),arguments.length<c?n.queue(this[0],a):void 0===b?this:this.each(function(){var c=n.queue(this,a,b);n._queueHooks(this,a),"fx"===a&&"inprogress"!==c[0]&&n.dequeue(this,a)})},dequeue:function(a){return this.each(function(){n.dequeue(this,a)})},clearQueue:function(a){return this.queue(a||"fx",[])},promise:function(a,b){var c,d=1,e=n.Deferred(),f=this,g=this.length,h=function(){--d||e.resolveWith(f,[f])};"string"!=typeof a&&(b=a,a=void 0),a=a||"fx";while(g--)c=n._data(f[g],a+"queueHooks"),c&&c.empty&&(d++,c.empty.add(h));return h(),e.promise(b)}}),function(){var a;l.shrinkWrapBlocks=function(){if(null!=a)return a;a=!1;var b,c,e;return c=d.getElementsByTagName("body")[0],c&&c.style?(b=d.createElement("div"),e=d.createElement("div"),e.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",c.appendChild(e).appendChild(b),"undefined"!=typeof b.style.zoom&&(b.style.cssText="-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box;display:block;margin:0;border:0;padding:1px;width:1px;zoom:1",b.appendChild(d.createElement("div")).style.width="5px",a=3!==b.offsetWidth),c.removeChild(e),a):void 0}}();var T=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,U=new RegExp("^(?:([+-])=|)("+T+")([a-z%]*)$","i"),V=["Top","Right","Bottom","Left"],W=function(a,b){return a=b||a,"none"===n.css(a,"display")||!n.contains(a.ownerDocument,a)};function X(a,b,c,d){var e,f=1,g=20,h=d?function(){return d.cur()}:function(){return n.css(a,b,"")},i=h(),j=c&&c[3]||(n.cssNumber[b]?"":"px"),k=(n.cssNumber[b]||"px"!==j&&+i)&&U.exec(n.css(a,b));if(k&&k[3]!==j){j=j||k[3],c=c||[],k=+i||1;do f=f||".5",k/=f,n.style(a,b,k+j);while(f!==(f=h()/i)&&1!==f&&--g)}return c&&(k=+k||+i||0,e=c[1]?k+(c[1]+1)*c[2]:+c[2],d&&(d.unit=j,d.start=k,d.end=e)),e}var Y=function(a,b,c,d,e,f,g){var h=0,i=a.length,j=null==c;if("object"===n.type(c)){e=!0;for(h in c)Y(a,b,h,c[h],!0,f,g)}else if(void 0!==d&&(e=!0,n.isFunction(d)||(g=!0),j&&(g?(b.call(a,d),b=null):(j=b,b=function(a,b,c){return j.call(n(a),c)})),b))for(;i>h;h++)b(a[h],c,g?d:d.call(a[h],h,b(a[h],c)));return e?a:j?b.call(a):i?b(a[0],c):f},Z=/^(?:checkbox|radio)$/i,$=/<([\w:-]+)/,_=/^$|\/(?:java|ecma)script/i,aa=/^\s+/,ba="abbr|article|aside|audio|bdi|canvas|data|datalist|details|dialog|figcaption|figure|footer|header|hgroup|main|mark|meter|nav|output|picture|progress|section|summary|template|time|video";function ca(a){var b=ba.split("|"),c=a.createDocumentFraLine truncated
|
||||
marginLeft:0},function(){return a.getBoundingClientRect().left}):0))+"px":void 0}),n.each({margin:"",padding:"",border:"Width"},function(a,b){n.cssHooks[a+b]={expand:function(c){for(var d=0,e={},f="string"==typeof c?c.split(" "):[c];4>d;d++)e[a+V[d]+b]=f[d]||f[d-2]||f[0];return e}},Na.test(a)||(n.cssHooks[a+b].set=db)}),n.fn.extend({css:function(a,b){return Y(this,function(a,b,c){var d,e,f={},g=0;if(n.isArray(b)){for(d=Ra(a),e=b.length;e>g;g++)f[b[g]]=n.css(a,b[g],!1,d);return f}return void 0!==c?n.style(a,b,c):n.css(a,b)},a,b,arguments.length>1)},show:function(){return cb(this,!0)},hide:function(){return cb(this)},toggle:function(a){return"boolean"==typeof a?a?this.show():this.hide():this.each(function(){W(this)?n(this).show():n(this).hide()})}});function gb(a,b,c,d,e){return new gb.prototype.init(a,b,c,d,e)}n.Tween=gb,gb.prototype={constructor:gb,init:function(a,b,c,d,e,f){this.elem=a,this.prop=c,this.easing=e||n.easing._default,this.options=b,this.start=this.now=this.cur(),this.end=d,this.unit=f||(n.cssNumber[c]?"":"px")},cur:function(){var a=gb.propHooks[this.prop];return a&&a.get?a.get(this):gb.propHooks._default.get(this)},run:function(a){var b,c=gb.propHooks[this.prop];return this.options.duration?this.pos=b=n.easing[this.easing](a,this.options.duration*a,0,1,this.options.duration):this.pos=b=a,this.now=(this.end-this.start)*b+this.start,this.options.step&&this.options.step.call(this.elem,this.now,this),c&&c.set?c.set(this):gb.propHooks._default.set(this),this}},gb.prototype.init.prototype=gb.prototype,gb.propHooks={_default:{get:function(a){var b;return 1!==a.elem.nodeType||null!=a.elem[a.prop]&&null==a.elem.style[a.prop]?a.elem[a.prop]:(b=n.css(a.elem,a.prop,""),b&&"auto"!==b?b:0)},set:function(a){n.fx.step[a.prop]?n.fx.step[a.prop](a):1!==a.elem.nodeType||null==a.elem.style[n.cssProps[a.prop]]&&!n.cssHooks[a.prop]?a.elem[a.prop]=a.now:n.style(a.elem,a.prop,a.now+a.unit)}}},gb.propHooks.scrollTop=gb.propHooks.scrollLeft={set:function(a){a.elem.nodeType&&a.elem.parentNode&&(a.elem[a.prop]=a.now)}},n.easing={linear:function(a){return a},swing:function(a){return.5-Math.cos(a*Math.PI)/2},_default:"swing"},n.fx=gb.prototype.init,n.fx.step={};var hb,ib,jb=/^(?:toggle|show|hide)$/,kb=/queueHooks$/;function lb(){return a.setTimeout(function(){hb=void 0}),hb=n.now()}function mb(a,b){var c,d={height:a},e=0;for(b=b?1:0;4>e;e+=2-b)c=V[e],d["margin"+c]=d["padding"+c]=a;return b&&(d.opacity=d.width=a),d}function nb(a,b,c){for(var d,e=(qb.tweeners[b]||[]).concat(qb.tweeners["*"]),f=0,g=e.length;g>f;f++)if(d=e[f].call(c,b,a))return d}function ob(a,b,c){var d,e,f,g,h,i,j,k,m=this,o={},p=a.style,q=a.nodeType&&W(a),r=n._data(a,"fxshow");c.queue||(h=n._queueHooks(a,"fx"),null==h.unqueued&&(h.unqueued=0,i=h.empty.fire,h.empty.fire=function(){h.unqueued||i()}),h.unqueued++,m.always(function(){m.always(function(){h.unqueued--,n.queue(a,"fx").length||h.empty.fire()})})),1===a.nodeType&&("height"in b||"width"in b)&&(c.overflow=[p.overflow,p.overflowX,p.overflowY],j=n.css(a,"display"),k="none"===j?n._data(a,"olddisplay")||Ma(a.nodeName):j,"inline"===k&&"none"===n.css(a,"float")&&(l.inlineBlockNeedsLayout&&"inline"!==Ma(a.nodeName)?p.zoom=1:p.display="inline-block")),c.overflow&&(p.overflow="hidden",l.shrinkWrapBlocks()||m.always(function(){p.overflow=c.overflow[0],p.overflowX=c.overflow[1],p.overflowY=c.overflow[2]}));for(d in b)if(e=b[d],jb.exec(e)){if(delete b[d],f=f||"toggle"===e,e===(q?"hide":"show")){if("show"!==e||!r||void 0===r[d])continue;q=!0}o[d]=r&&r[d]||n.style(a,d)}else j=void 0;if(n.isEmptyObject(o))"inline"===("none"===j?Ma(a.nodeName):j)&&(p.display=j);else{r?"hidden"in r&&(q=r.hidden):r=n._data(a,"fxshow",{}),f&&(r.hidden=!q),q?n(a).show():m.done(function(){n(a).hide()}),m.done(function(){var b;n._removeData(a,"fxshow");for(b in o)n.style(a,b,o[b])});for(d in o)g=nb(q?r[d]:0,d,m),d in r||(r[d]=g.start,q&&(g.end=g.start,g.start="width"===d||"height"===d?1:0))}}function pb(a,b){var c,d,e,f,g;for(c in a)if(d=n.camelCase(c),e=b[d],f=a[c],n.isArray(f)&&(e=f[1],f=a[c]=f[0]),c!==d&&(a[d]=f,delete a[c]),g=n.cssHooks[d],g&&"expand"in g){f=g.expand(f),delete a[d];for(c in f)c in a||(a[c]=f[c],b[c]=e)}else b[d]=e}function qb(a,b,c){var d,e,f=0,g=qb.prefilters.length,h=n.Deferred().always(function(){delete i.elem}),i=function(){if(e)return!1;for(var b=hb||lb(),c=Math.max(0,j.startTime+j.duration-b),d=c/j.duration||0,f=1-d,g=0,i=j.tweens.length;i>g;g++)j.tweens[g].run(f);return h.notifyWith(a,[j,f,c]),1>f&&i?c:(h.resolveWith(a,[j]),!1)},j=h.promise({elem:a,props:n.extend({},b),opts:n.extend(!0,{specialEasing:{},easing:n.easing._default},c),originalProperties:b,originalOptions:c,startTime:hb||lb(),duration:c.duration,tweens:[],createTween:function(b,c){var d=n.Tween(a,j.opts,b,c,j.opts.specialEasing[b]||j.opts.easing);return j.tweens.push(d),d},stop:function(b){var c=0,d=b?j.tweens.length:0;if(e)return this;for(e=!0;d>c;c++)j.tweens[c].run(1);return b?(h.notifyWith(a,[j,1,0]),h.resolveWith(a,[j,b])):h.rejectWith(a,[j,b]Line truncated
|
||||
padding:"inner"+a,content:b,"":"outer"+a},function(c,d){n.fn[d]=function(d,e){var f=arguments.length&&(c||"boolean"!=typeof d),g=c||(d===!0||e===!0?"margin":"border");return Y(this,function(b,c,d){var e;return n.isWindow(b)?b.document.documentElement["client"+a]:9===b.nodeType?(e=b.documentElement,Math.max(b.body["scroll"+a],e["scroll"+a],b.body["offset"+a],e["offset"+a],e["client"+a])):void 0===d?n.css(b,c,g):n.style(b,c,d,g)},b,f?d:void 0,f,null)}})}),n.fn.extend({bind:function(a,b,c){return this.on(a,null,b,c)},unbind:function(a,b){return this.off(a,null,b)},delegate:function(a,b,c,d){return this.on(b,a,c,d)},undelegate:function(a,b,c){return 1===arguments.length?this.off(a,"**"):this.off(b,a||"**",c)}}),n.fn.size=function(){return this.length},n.fn.andSelf=n.fn.addBack,"function"==typeof define&&define.amd&&define("jquery",[],function(){return n});var nc=a.jQuery,oc=a.$;return n.noConflict=function(b){return a.$===n&&(a.$=oc),b&&a.jQuery===n&&(a.jQuery=nc),n},b||(a.jQuery=a.$=n),n});
|
||||
Vendored
+6
@@ -0,0 +1,6 @@
|
||||
/*!
|
||||
* Copyright 2012, Chris Wanstrath
|
||||
* Released under the MIT License
|
||||
* https://github.com/defunkt/jquery-pjax
|
||||
*/
|
||||
!function(t){function e(e,a,r){return r=g(a,r),this.on("click.pjax",e,(function(e){var a=r;a.container||((a=t.extend({},r)).container=t(this).attr("data-pjax")),n(e,a)}))}function n(e,n,a){a=g(n,a);var i=e.currentTarget,o=t(i);if("A"!==i.tagName.toUpperCase())throw"$.fn.pjax or $.pjax.click requires an anchor element";if(!(e.which>1||e.metaKey||e.ctrlKey||e.shiftKey||e.altKey||location.protocol!==i.protocol||location.hostname!==i.hostname||i.href.indexOf("#")>-1&&x(i)==x(location)||e.isDefaultPrevented())){var s={url:i.href,container:o.attr("data-pjax"),target:i},c=t.extend({},s,a),u=t.Event("pjax:click");o.trigger(u,[c]),u.isDefaultPrevented()||(r(c),e.preventDefault(),o.trigger("pjax:clicked",[c]))}}function a(e,n,a){a=g(n,a);var i=e.currentTarget,o=t(i);if("FORM"!==i.tagName.toUpperCase())throw"$.pjax.submit requires a form element";var s={type:(o.attr("method")||"GET").toUpperCase(),url:o.attr("action"),container:o.attr("data-pjax"),target:i};if("GET"!==s.type&&void 0!==window.FormData)s.data=new FormData(i),s.processData=!1,s.contentType=!1;else{if(o.find(":file").length)return;s.data=o.serializeArray()}r(t.extend({},s,a)),e.preventDefault()}function r(e){e=t.extend(!0,{},t.ajaxSettings,r.defaults,e),t.isFunction(e.url)&&(e.url=e.url());var n=v(e.url).hash,a=t.type(e.container);if("string"!==a)throw"expected string value for 'container' option; got "+a;var i,s=e.context=t(e.container);if(!s.length)throw"the container selector '"+e.container+"' did not match anything";function c(n,a,r){r||(r={}),r.relatedTarget=e.target;var i=t.Event(n,r);return s.trigger(i,a),!i.isDefaultPrevented()}e.data||(e.data={}),t.isArray(e.data)?e.data.push({name:"_pjax",value:e.container}):e.data._pjax=e.container,e.beforeSend=function(t,a){if("GET"!==a.type&&(a.timeout=0),t.setRequestHeader("X-PJAX","true"),t.setRequestHeader("X-PJAX-Container",e.container),!c("pjax:beforeSend",[t,a]))return!1;a.timeout>0&&(i=setTimeout((function(){c("pjax:timeout",[t,e])&&t.abort("timeout")}),a.timeout),a.timeout=0);var r=v(a.url);n&&(r.hash=n),e.requestUrl=m(r)},e.complete=function(t,n){i&&clearTimeout(i),c("pjax:complete",[t,n,e]),c("pjax:end",[t,e])},e.error=function(t,n,a){var r=w("",t,e),i=c("pjax:error",[t,n,a,e]);"GET"==e.type&&"abort"!==n&&i&&o(r.url)},e.success=function(a,i,u){var l=r.state,p="function"==typeof t.pjax.defaults.version?t.pjax.defaults.version():t.pjax.defaults.version,d=u.getResponseHeader("X-PJAX-Version"),h=w(a,u,e),m=v(h.url);if(n&&(m.hash=n,h.url=m.href),p&&d&&p!==d)o(h.url);else if(h.contents){if(r.state={id:e.id||f(),url:h.url,title:h.title,container:e.container,fragment:e.fragment,timeout:e.timeout},(e.push||e.replace)&&window.history.replaceState(r.state,h.title,h.url),t.contains(s,document.activeElement))try{document.activeElement.blur()}catch(t){}h.title&&(document.title=h.title),c("pjax:beforeReplace",[h.contents,e],{state:r.state,previousState:l}),s.html(h.contents);var x=s.find("input[autofocus], textarea[autofocus]").last()[0];x&&document.activeElement!==x&&x.focus(),function(e){if(!e)return;var n=t("script[src]");e.each((function(){var e=this.src;if(!n.filter((function(){return this.src===e})).length){var a=document.createElement("script"),r=t(this).attr("type");r&&(a.type=r),a.src=t(this).attr("src"),document.head.appendChild(a)}}))}(h.scripts);var g=e.scrollTo;if(n){var y=decodeURIComponent(n.slice(1)),j=document.getElementById(y)||document.getElementsByName(y)[0];j&&(g=t(j).offset().top)}"number"==typeof g&&t(window).scrollTop(g),c("pjax:success",[a,i,u,e])}else o(h.url)},r.state||(r.state={id:f(),url:window.location.href,title:document.title,container:e.container,fragment:e.fragment,timeout:e.timeout},window.history.replaceState(r.state,document.title)),d(r.xhr),r.options=e;var u,l,p=r.xhr=t.ajax(e);return p.readyState>0&&(e.push&&!e.replace&&(u=r.state.id,l=[e.container,h(s)],b[u]=l,E.push(u),S(T,0),S(E,r.defaults.maxCacheLength),window.history.pushState(null,"",e.requestUrl)),c("pjax:start",[p,e]),c("pjax:send",[p,e])),r.xhr}function i(e,n){var a={url:window.location.href,push:!1,replace:!0,scrollTo:!1};return r(t.extend(a,g(e,n)))}function o(t){window.history.replaceState(null,"",r.state.url),window.location.replace(t)}var s=!0,c=window.location.href,u=window.history.state;function l(e){s||d(r.xhr);var n,a=r.state,i=e.state;if(i&&i.container){if(s&&c==i.url)return;if(a){if(a.id===i.id)return;n=a.id<i.id?"forward":"back"}var u=b[i.id]||[],l=u[0]||i.container,p=t(l),f=u[1];if(p.length){a&&function(t,e,n){var a,i;b[e]=n,"forward"===t?(a=E,i=T):(a=T,i=E);a.push(e),(e=i.pop())&&delete b[e];S(a,r.defaults.maxCacheLength)}(n,a.id,[l,h(p)]);var m=t.Event("pjax:popstate",{state:i,direction:n});p.trigger(m);var v={id:i.id,url:i.url,container:l,push:!1,fragment:i.fragment,timeout:i.timeout,scrollTo:!1};if(f){p.trigger("pjax:start",[null,v]),r.state=i,i.title&&(document.title=i.title);var x=t.Event("pjax:beforeReplace",{state:i,previousState:a});p.trigger(x,[f,v]),p.html(f),p.trigger("pjax:end",[null,v])}eLine truncated
|
||||
+63
-20
@@ -1,6 +1,41 @@
|
||||
var message_Path = '/Live2dHistoire/live2d/';
|
||||
var talkAPI = BlogAPI + "/ai_chat";
|
||||
|
||||
function initVisitors() {
|
||||
if ($('.visitors').length === 1) {
|
||||
var $visitor = $('.visitors:first');
|
||||
$.get(BlogAPI + '/count_click_add?id=' + $visitor.attr('id'), function (data) {
|
||||
$visitor.text(Number(data));
|
||||
});
|
||||
} else if ($('.visitors-index').length > 0) {
|
||||
$('.visitors-index').each(function () {
|
||||
var $elem = $(this);
|
||||
$.get(BlogAPI + '/count_click?id=' + $elem.attr('id'), function (data) {
|
||||
$elem.text(Number(data));
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function highlightKeyword() {
|
||||
var match = location.search.match(/[?&]kw=([^&]+)/);
|
||||
var kw = match ? $.trim(decodeURIComponent(match[1].replace(/\+/g, ' '))) : '';
|
||||
if (!kw) return;
|
||||
|
||||
var reg = new RegExp('(' + kw.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') + ')', 'gi');
|
||||
var escapeMap = { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' };
|
||||
|
||||
$('section, section *').not('script, style, textarea').contents().filter(function () {
|
||||
return this.nodeType === 3;
|
||||
}).each(function () {
|
||||
var escapedText = this.nodeValue.replace(/[&<>"']/g, function (m) { return escapeMap[m]; });
|
||||
var highlighted = escapedText.replace(reg, '<mark>$1</mark>');
|
||||
if (escapedText !== highlighted) {
|
||||
$(this).replaceWith(highlighted);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$(function () {
|
||||
(function () {
|
||||
var $backToTopTxt = "返回顶部", $backToTopEle = $('<div class="backToTop"></div>').appendTo($("body"))
|
||||
@@ -14,36 +49,19 @@ $(function () {
|
||||
$(function () { $backToTopFun(); });
|
||||
})();
|
||||
|
||||
function showHitCount() {
|
||||
$(".visitors-index").each(function () {
|
||||
var $elem = $(this);
|
||||
$.get(BlogAPI + "/count_click?id=" + $elem.attr('id'), function (data) {
|
||||
$elem.text(Number(data));
|
||||
});
|
||||
});
|
||||
}
|
||||
function addCount() {
|
||||
var $visitor = $(".visitors:first");
|
||||
$.get(BlogAPI + "/count_click_add?id=" + $visitor.attr('id'), function (data) {
|
||||
$visitor.text(Number(data));
|
||||
});
|
||||
}
|
||||
if ($('.visitors').length == 1) {
|
||||
addCount();
|
||||
} else if ($('.visitors-index').length > 0) {
|
||||
showHitCount();
|
||||
}
|
||||
initVisitors();
|
||||
|
||||
if (Math.floor((new Date().getTime() - lastUpdated.getTime()) / (24 * 60 * 60 * 1000)) > 90) {
|
||||
$("html").css({
|
||||
"-webkit-filter": "grayscale(100%)",
|
||||
"filter": "progid:DXImageTransform.Microsoft.BasicImage(grayscale=1)"
|
||||
})
|
||||
$('body').html(function(_, oldHTML) {
|
||||
$('body').html(function (_, oldHTML) {
|
||||
return oldHTML.replace(/Mayx/g, 'Ghost');
|
||||
});
|
||||
console.warn("Mayx may already be Dead");
|
||||
}
|
||||
highlightKeyword();
|
||||
});
|
||||
|
||||
function getSearchJSON(callback) {
|
||||
@@ -67,3 +85,28 @@ function getSearchJSON(callback) {
|
||||
callback(searchData);
|
||||
}
|
||||
}
|
||||
if (typeof window.go === 'undefined') {
|
||||
window.go = function (url) {
|
||||
window.location.href = url;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
function getWelcomeText(pathname, title) {
|
||||
pathname = pathname || window.location.pathname;
|
||||
title = title || document.title.split(' | ')[0];
|
||||
|
||||
if (pathname === '/' || pathname === '/index.html') {
|
||||
var now = (new Date()).getHours();
|
||||
if (now > 23 || now <= 5) return '你是夜猫子呀?这么晚还不睡觉,明天起的来嘛?';
|
||||
if (now > 5 && now <= 7) return '早上好!一日之计在于晨,美好的一天就要开始了!';
|
||||
if (now > 7 && now <= 11) return '上午好!工作顺利嘛,不要久坐,多起来走动走动哦!';
|
||||
if (now > 11 && now <= 14) return '中午了,工作了一个上午,现在是午餐时间!';
|
||||
if (now > 14 && now <= 17) return '午后很容易犯困呢,今天的运动目标完成了吗?';
|
||||
if (now > 17 && now <= 19) return '傍晚了!窗外夕阳的景色很美丽呢,最美不过夕阳红~~';
|
||||
if (now > 19 && now <= 21) return '晚上好,今天过得怎么样?';
|
||||
if (now > 21 && now <= 23) return '已经这么晚了呀,早点休息吧,晚安~~';
|
||||
return '嗨~ 快来逗我玩吧!';
|
||||
}
|
||||
return '欢迎阅读<span style="color:#0099cc;">「 ' + title + ' 」</span>';
|
||||
}
|
||||
+14
-73
@@ -1,77 +1,18 @@
|
||||
$(function () {
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
const keyword = urlParams.get('kw')?.trim();
|
||||
|
||||
if (!keyword) return;
|
||||
|
||||
// 转义正则表达式特殊字符,避免安全问题
|
||||
const escapedKeyword = keyword.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||
// 创建不区分大小写的正则表达式(全局匹配)
|
||||
const regex = new RegExp(`(${escapedKeyword})`, 'gi');
|
||||
|
||||
// 递归遍历并高亮文本节点
|
||||
const escapeHTML = str => str.replace(/[&<>"']/g,
|
||||
tag => ({
|
||||
'&': '&',
|
||||
'<': '<',
|
||||
'>': '>',
|
||||
'"': '"',
|
||||
"'": '''
|
||||
}[tag] || tag));
|
||||
function highlightTextNodes(element) {
|
||||
$(element).contents().each(function () {
|
||||
if (this.nodeType === Node.TEXT_NODE) {
|
||||
const $this = $(this);
|
||||
const text = escapeHTML($this.text());
|
||||
|
||||
// 使用正则替换并保留原始大小写
|
||||
if (regex.test(text)) {
|
||||
const replaced = text.replace(regex, '<mark>$1</mark>');
|
||||
$this.replaceWith(replaced);
|
||||
}
|
||||
} else if (
|
||||
this.nodeType === Node.ELEMENT_NODE &&
|
||||
!$(this).is('script, style, noscript, textarea')
|
||||
) {
|
||||
highlightTextNodes(this);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$('section').each(function () {
|
||||
highlightTextNodes(this);
|
||||
});
|
||||
});
|
||||
|
||||
$(function() {
|
||||
var $codeBlocks = $('div.highlight');
|
||||
|
||||
$codeBlocks.each(function() {
|
||||
var $copyButton = $('<button>', {
|
||||
class: 'copy',
|
||||
type: 'button',
|
||||
text: '📋'
|
||||
});
|
||||
|
||||
$(this).append($copyButton);
|
||||
|
||||
$copyButton.on('click', function() {
|
||||
var code = $(this).siblings('pre').find('code').text().trim();
|
||||
var $button = $(this);
|
||||
|
||||
function initCopyButtons() {
|
||||
$('.copy').remove();
|
||||
$('div.highlight').each(function () {
|
||||
var $btn = $('<button>', { class: 'copy', type: 'button', text: '📋' });
|
||||
$(this).append($btn);
|
||||
$btn.on('click', function () {
|
||||
var code = $btn.siblings('pre').find('code').text().trim();
|
||||
navigator.clipboard.writeText(code)
|
||||
.then(function() {
|
||||
$button.text('✅');
|
||||
})
|
||||
.catch(function(err) {
|
||||
$button.text('❌');
|
||||
console.error('复制失败:', err);
|
||||
})
|
||||
.finally(function() {
|
||||
setTimeout(function() {
|
||||
$button.text('📋');
|
||||
}, 1500);
|
||||
});
|
||||
.then(function () { $btn.text('✅'); })
|
||||
.catch(function () { $btn.text('❌'); })
|
||||
.finally(function () { setTimeout(function () { $btn.text('📋'); }, 1500); });
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
$(function () {
|
||||
initCopyButtons();
|
||||
});
|
||||
@@ -0,0 +1,153 @@
|
||||
/**
|
||||
* PJAX 初始化与页面切换重绑定脚本
|
||||
* 依赖:jQuery, jquery.pjax.min.js
|
||||
* 加载顺序:在 jquery.pjax.min.js 之后,body 末尾
|
||||
*/
|
||||
|
||||
(function ($) {
|
||||
// ========== 常量 ==========
|
||||
var CONTAINER = '#pjax-container';
|
||||
var PJAX_OPTS = {
|
||||
container: CONTAINER,
|
||||
fragment: CONTAINER,
|
||||
timeout: 5000,
|
||||
scrollTo: false
|
||||
};
|
||||
|
||||
// ========== 各组件重初始化 ==========
|
||||
|
||||
/** Google Analytics 页面浏览事件 */
|
||||
function trackPageView() {
|
||||
if (typeof gtag === 'function') {
|
||||
gtag('config', window._gaId || '', { page_path: window.location.pathname });
|
||||
}
|
||||
}
|
||||
|
||||
/** Live2D 重初始化 */
|
||||
var _live2dSelectors = ['.post-link', '#search-input'];
|
||||
var _live2dDelegateBound = false;
|
||||
|
||||
function reinitLive2d() {
|
||||
if (!window._live2d) return;
|
||||
var pathname = window.location.pathname;
|
||||
|
||||
// 更新"想问这篇文章"相关状态(仅真正的文章页显示)
|
||||
$('#post_id').val(pathname);
|
||||
if ($(CONTAINER + ' #gitalk-container').length > 0) {
|
||||
$('.live_talk_input_name_body').show();
|
||||
} else {
|
||||
$('.live_talk_input_name_body').hide();
|
||||
$('#load_this').prop('checked', false);
|
||||
}
|
||||
|
||||
// 音乐按钮:根据当前页面是否有 BGM 输入来显示/隐藏
|
||||
if (typeof window._live2d.initBGM === 'function') {
|
||||
window._live2d.initBGM();
|
||||
}
|
||||
|
||||
// 事件委托绑定(只执行一次)
|
||||
if (!_live2dDelegateBound && typeof String.prototype.renderTip === 'function') {
|
||||
var selector = CONTAINER + ' ' + _live2dSelectors.join(', ' + CONTAINER + ' ');
|
||||
$(document).on('mouseover._live2d_pjax', selector, function (e) {
|
||||
var $el = $(e.currentTarget || e.target);
|
||||
if ($el.is('.post-link')) {
|
||||
window._live2d.showMessage('要看看 ' + $el.text() + ' 么?', 3000);
|
||||
} else if ($el.is('#search-input')) {
|
||||
window._live2d.showMessage('在找什么东西呢,需要帮忙吗?', 3000);
|
||||
}
|
||||
});
|
||||
$(document).on('mouseout._live2d_pjax', selector, function () {
|
||||
if (window._live2d.showHitokoto) window._live2d.showHitokoto();
|
||||
});
|
||||
_live2dDelegateBound = true;
|
||||
}
|
||||
|
||||
// 欢迎语
|
||||
if (typeof window._live2d.showMessage === 'function') {
|
||||
window._live2d.showMessage(getWelcomeText(pathname), 6000);
|
||||
}
|
||||
}
|
||||
|
||||
// ========== PJAX 导航 ==========
|
||||
|
||||
/** PJAX 完成后的统一处理 */
|
||||
function doPjaxComplete() {
|
||||
$('body').removeClass('pjax-loading');
|
||||
// 清理可能残留的浮层(如推荐文章 tooltip,hover 后点击跳转时 mouseleave 来不及触发)
|
||||
$('.content-tooltip').remove();
|
||||
onPjaxComplete();
|
||||
}
|
||||
|
||||
/** 暴露给模板内 onclick/onchange 调用的导航函数 */
|
||||
window.go = function (url) {
|
||||
$.pjax($.extend({ url: url }, PJAX_OPTS));
|
||||
};
|
||||
|
||||
// ========== 初始化 ==========
|
||||
|
||||
/** pjax 完成后滚动到目标位置:有锚点则定位锚点,否则回到顶部 */
|
||||
function scrollToAnchor() {
|
||||
var hash = window.location.hash;
|
||||
if (hash) {
|
||||
// 中文等非 ASCII 字符在 URL 中会被编码,需先解码再匹配元素 id
|
||||
var id = hash.slice(1);
|
||||
try { id = decodeURIComponent(id); } catch (e) { /* 保持原值 */ }
|
||||
var target = document.getElementById(id) ||
|
||||
document.querySelector('a[name="' + id + '"]');
|
||||
if (target) {
|
||||
target.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||
return;
|
||||
}
|
||||
}
|
||||
window.scrollTo(0, 0);
|
||||
}
|
||||
|
||||
/** 每次 pjax 完成后执行所有重初始化 */
|
||||
function onPjaxComplete() {
|
||||
initVisitors();
|
||||
initCopyButtons();
|
||||
highlightKeyword();
|
||||
reinitLive2d();
|
||||
trackPageView();
|
||||
scrollToAnchor();
|
||||
}
|
||||
|
||||
$(document).ready(function () {
|
||||
// 排除列表:外链、锚点、静态资源、Live2D 目录
|
||||
var exclude = ':not([target="_blank"]):not([href^="http"]):not([href^="//"])' +
|
||||
':not([href^="mailto"]):not([href^="#"])' +
|
||||
':not([href$=".xml"]):not([href$=".json"]):not([href$=".tgz"]):not([href$=".zip"])' +
|
||||
':not([href^="/Live2dHistoire"])';
|
||||
$(document).pjax('a' + exclude, PJAX_OPTS.container, PJAX_OPTS);
|
||||
$(document).on('submit', 'form#search-input-all', function (e) {
|
||||
$.pjax.submit(e, PJAX_OPTS.container, PJAX_OPTS);
|
||||
});
|
||||
$(document).on('pjax:send', function () {
|
||||
$('body').addClass('pjax-loading');
|
||||
});
|
||||
$(document).on('pjax:complete', doPjaxComplete);
|
||||
$(document).on('pjax:end', function (event, xhr, options) {
|
||||
var $container = $(options.container || PJAX_OPTS.container);
|
||||
|
||||
$container.find('script[type="module"]').each(function () {
|
||||
var oldScript = this;
|
||||
var newScript = document.createElement('script');
|
||||
newScript.type = 'module';
|
||||
|
||||
// 如果是外链脚本 (<script src="..."></script>)
|
||||
if (oldScript.src) {
|
||||
newScript.src = oldScript.src;
|
||||
} else {
|
||||
// 如果是行内脚本 (<script>...code...</script>)
|
||||
newScript.textContent = oldScript.textContent;
|
||||
}
|
||||
// 插入到 body 中触发浏览器执行
|
||||
document.body.appendChild(newScript);
|
||||
|
||||
// 运行完后建议移除,防止 DOM 变得混乱(不影响模块执行)
|
||||
newScript.remove();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
@@ -0,0 +1 @@
|
||||
24f0040157c07cc424b28b7b52ea734d
|
||||
+17
@@ -0,0 +1,17 @@
|
||||
---
|
||||
---
|
||||
|
||||
/* AUTHOR */
|
||||
Name: Mayx
|
||||
Contact: mayx@outlook.com
|
||||
GitHub: Mabbs
|
||||
From: China
|
||||
|
||||
/* THANKS */
|
||||
Built with: Jekyll (https://jekyllrb.com)
|
||||
|
||||
/* SITE */
|
||||
Last update: {{ site.time | date: "%F" }}
|
||||
Language: Chinese / English
|
||||
Doctype: HTML5
|
||||
IDE: VSCode
|
||||
+13
-4
@@ -5,14 +5,14 @@ image: https://screenshot.mayx.eu.org/
|
||||
---
|
||||
|
||||
{% if paginator.page == 1 %}<div class="hslice" id="LatestPost">{% endif %}
|
||||
<h1 class="entry-title" style="display:inline"> 首页 - 我的文章 </h1><small><a href="/archives.html">Archives</a> | <a href="javascript:getSearchJSON(function(data){location=data[Math.floor(Math.random()*data.length)].url})">Random</a></small><br /><br />
|
||||
<h1 class="entry-title" style="display:inline"> 首页 - 我的文章 </h1><small><a href="/archives.html">Archives</a> | <a href="javascript:void(0)" onclick="getSearchJSON(function(data){go(data[Math.floor(Math.random()*data.length)].url)})">Random</a></small><br /><br />
|
||||
|
||||
<hr />
|
||||
|
||||
<!-- 遍历分页后的文章 -->
|
||||
<table class="entry-content h-feed">
|
||||
{% for post in paginator.posts %}
|
||||
<tr><td class="h-entry" onclick="location='{{ post.url }}'">
|
||||
<tr><td class="h-entry post-row" data-url="{{ post.url }}">
|
||||
<h2 class="p-name"><a class="post-link u-url" href="{{ post.url }}">{{ post.title }}{% if post.layout == "encrypt" %} [加密] {% endif %}</a></h2>
|
||||
<p>
|
||||
<time class="date dt-published" datetime="{{ post.date | date_to_xmlschema }}">{{ post.date | date: "%-d %B %Y" }}</time>
|
||||
@@ -24,7 +24,7 @@ image: https://screenshot.mayx.eu.org/
|
||||
{% if post.tags %}
|
||||
<span>
|
||||
{% for tag in post.tags %}
|
||||
<a rel="category tag" class="p-category" href="/search.html?keyword={{ tag | url_encode | replace: '+', '%20' }}"><code style="white-space: nowrap">#{{ tag }}</code></a>
|
||||
<a rel="category tag" class="p-category" href="/search.html?keyword={{ tag | uri_escape }}"><code style="white-space: nowrap">#{{ tag }}</code></a>
|
||||
{% endfor %}
|
||||
</span>
|
||||
{% endif %}
|
||||
@@ -44,7 +44,7 @@ image: https://screenshot.mayx.eu.org/
|
||||
<span>« Prev</span>
|
||||
{% endif %}
|
||||
|
||||
<select onchange="window.location = this.value == 1 ? '/index.html' : '/page' + this.value + '/index.html'">
|
||||
<select onchange="go(this.value == 1 ? '/index.html' : '/page' + this.value + '/index.html')">
|
||||
{% for page in (1..paginator.total_pages) %}
|
||||
{% if page == paginator.page %}
|
||||
<option value="{{ page }}" selected>{{ page }}</option>
|
||||
@@ -66,7 +66,9 @@ image: https://screenshot.mayx.eu.org/
|
||||
<h2>其他页面</h2>
|
||||
<p>
|
||||
<a href="/service.html">Mayx的公开服务</a><br />
|
||||
<a href="{% unless site.github %}https://mabbs.github.io{% endunless %}/linux/">Mayx's Blog Terminal</a><br />
|
||||
凯露&危险生存( <a href="{% unless site.github %}https://mabbs.github.io{% endunless %}/karyl-yabaival/?cn">CHS</a> | <a href="{% unless site.github %}https://mabbs.github.io{% endunless %}/karyl-yabaival/">JA</a> | <a href="{% unless site.github %}https://mabbs.github.io{% endunless %}/karyl-yabaival/?kr">KO</a> )<br />
|
||||
<a href="{% unless site.github %}https://mabbs.github.io{% endunless %}/riichi-mahjong-wordle/">立直麻将 Wordle</a><br />
|
||||
<a href="{% unless site.github %}https://mabbs.github.io{% endunless %}/brainfuck-visualizer/">Brainfuck可视化演示</a><br />
|
||||
<a href="/message.html">留言板</a><br />
|
||||
<a href="/links.html">Links</a><br />
|
||||
@@ -78,3 +80,10 @@ image: https://screenshot.mayx.eu.org/
|
||||
An <a href="https://xn--sr8hvo.ws">IndieWeb Webring</a> 🕸💍
|
||||
<a href="https://xn--sr8hvo.ws/next">→</a><br /><a href="https://icp.gov.moe/?keyword=20218888" target="_blank">萌ICP备 20218888号</a></small>
|
||||
<input name="live2dBGM" value="https://music.163.com/song/media/outer/url?id=523658881.mp3" type="hidden" />
|
||||
<script>
|
||||
$(document).on('click', '.post-row', function(e) {
|
||||
if ($(e.target).closest('.p-category').length === 0) {
|
||||
go($(this).attr('data-url'));
|
||||
}
|
||||
});
|
||||
</script>
|
||||
@@ -4,11 +4,12 @@ title: Links
|
||||
date: 2019-05-03
|
||||
id: links
|
||||
tags: [links]
|
||||
robots: nofollow
|
||||
---
|
||||
|
||||
| Link | Description |
|
||||
| - | - |
|
||||
{% for item in site.data.links %}| <a href="{{ item.link }}" target="_blank" rel="noopener sponsored" {% if item.feed_url %}data-feed="{{ item.feed_url }}"{% endif %}>{{ item.title }}</a> | {% if item.description %}{{ item.description }}{% else %}*No description*{% endif %} |
|
||||
{% for item in site.data.links %}| <a href="{{ item.link }}" target="_blank" rel="noopener" {% if item.feed_url %}data-feed="{{ item.feed_url }}"{% endif %}>{{ item.title }}</a> | {% if item.description %}{{ item.description }}{% else %}*No description*{% endif %} |
|
||||
{% endfor %}
|
||||
|
||||
订阅以上链接:[OPML](/blogroll.opml)
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
---
|
||||
---
|
||||
|
||||
# {{ site.title }}
|
||||
> {{ site.description }}
|
||||
|
||||
## Site Info
|
||||
|
||||
- [About Site](/README.html)
|
||||
- [About Author](/humans.txt)
|
||||
|
||||
## Posts
|
||||
{% for post in site.posts %}
|
||||
- [{{ post.title }}{% if post.layout == "encrypt" %} [加密] {% endif %}]({{ post.url }}): {% assign ai_cache = site.data.ai-cache[post.url] %}{% if ai_cache %}{{ ai_cache | strip_html | strip_newlines }}{% elsif post.excerpt %}{{ post.excerpt | strip_html | strip_newlines }}{% else %}Just a Post.{% endif %}{% endfor %}
|
||||
@@ -0,0 +1 @@
|
||||
32691808d04b4e838d0c0610ec848ca2
|
||||
@@ -1,6 +1,7 @@
|
||||
---
|
||||
layout: default
|
||||
title: 其他Git仓库镜像列表
|
||||
robots: noindex, nofollow
|
||||
---
|
||||
|
||||
# 其他Git仓库镜像列表
|
||||
|
||||
+6
-5
@@ -1,6 +1,7 @@
|
||||
---
|
||||
layout: default
|
||||
title: 代理列表
|
||||
robots: nofollow
|
||||
---
|
||||
|
||||
源站:<https://mabbs.github.io/> <img src="https://mabbs.github.io/images/online.svg" style="width: 1.2em; vertical-align: text-bottom;" onerror="this.outerHTML='ⓧ'"/>
|
||||
@@ -31,7 +32,8 @@ graph LR;
|
||||
GH@{ shape: bow-rect, label: "GitHub" }
|
||||
GL@{ shape: bow-rect, label: "GitLab" }
|
||||
GE@{ shape: bow-rect, label: "Gitee" }
|
||||
OG@{ shape: bow-rect, label: "Other..." }
|
||||
OG@{ shape: bow-rect, label: "And more..." }
|
||||
OGP@{ shape: docs, label: "And more..." }
|
||||
CFP@{ shape: docs, label: "CloudFlare Pages" }
|
||||
GHP@{ shape: docs, label: "GitHub Pages" }
|
||||
GLP@{ shape: docs, label: "GitLab Pages" }
|
||||
@@ -40,14 +42,13 @@ graph LR;
|
||||
GF@{ shape: lin-cyl, label: "Greenfield" }
|
||||
Vercel@{ shape: docs, label: "Vercel" }
|
||||
Netlify@{ shape: docs, label: "Netlify" }
|
||||
SH@{ shape: docs, label: "statichost.eu" }
|
||||
DA@{ shape: docs, label: "dAppling" }
|
||||
CFW@{ label: "CloudFlare Workers" }
|
||||
CFAI@{ shape: procs, label: "CloudFlare AI" }
|
||||
CFD@{ shape: lin-cyl, label: "CloudFlare D1" }
|
||||
Deno@{ shape: curv-trap, label: "Deno" }
|
||||
Glitch@{ shape: curv-trap, label: "Glitch" }
|
||||
Other@{ shape: curv-trap, label: "Other..." }
|
||||
Other@{ shape: curv-trap, label: "And more..." }
|
||||
subgraph Repo
|
||||
GH
|
||||
GL
|
||||
@@ -59,11 +60,11 @@ graph LR;
|
||||
GHP
|
||||
GLP
|
||||
CFP
|
||||
SH
|
||||
FELH
|
||||
DA
|
||||
Vercel
|
||||
Netlify
|
||||
OGP
|
||||
end
|
||||
|
||||
subgraph API[API Service]
|
||||
@@ -86,7 +87,7 @@ graph LR;
|
||||
GH <-- Sync --> GL
|
||||
GH -- Sync --> GE
|
||||
GH -. Sync .-> OG
|
||||
GH -- Deploy --> GHP & SH & Netlify & FELH & DA
|
||||
GH -- Deploy --> GHP & Netlify & FELH & DA & OGP
|
||||
GL -- Deploy --> CFP & Vercel & GLP
|
||||
CFW -- Reverse Proxy --> GHP
|
||||
Deno -- Reverse Proxy --> GHP
|
||||
|
||||
+18
-1
@@ -27,7 +27,7 @@ if (mykeyword) {
|
||||
</script>
|
||||
<script src="/assets/js/simple-jekyll-search.min.js"></script>
|
||||
<script>
|
||||
getSearchJSON(function(json){
|
||||
function _doSearch(json) {
|
||||
var sjs = SimpleJekyllSearch({
|
||||
searchInput: sbox,
|
||||
resultsContainer: document.getElementById('results-container'),
|
||||
@@ -37,5 +37,22 @@ getSearchJSON(function(json){
|
||||
});
|
||||
sjs.search(mykeyword);
|
||||
document.getElementById('search-loading').style.display = "none";
|
||||
}
|
||||
getSearchJSON(function(json) {
|
||||
if (typeof SimpleJekyllSearch !== 'undefined') {
|
||||
_doSearch(json);
|
||||
} else {
|
||||
// PJAX 场景:外部脚本通过 pjax 库异步加载,需要等待加载完成
|
||||
var _poll = 0;
|
||||
var _waitSJS = setInterval(function() {
|
||||
if (typeof SimpleJekyllSearch !== 'undefined') {
|
||||
clearInterval(_waitSJS);
|
||||
_doSearch(json);
|
||||
} else if (++_poll > 100) {
|
||||
clearInterval(_waitSJS);
|
||||
document.getElementById('search-loading').style.display = "none";
|
||||
}
|
||||
}, 50);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
Reference in new issue
Block a user