1/** 2 * @fileoverview æ ¸å¿èæ¬ï¼è´è´£å è½½åæ¨¡åä¸å¨ææ¢é¡µãæå徿 æ°æ®å¹¶è§¦å渲æã䏻颿§ä»¶ä¸ä¸è¨æ¸²æï¼ä»¥åååè¿ç§»ãSW ç§»é¤çä»»å¡ 3 * @author dsy4567 4 * @license 5 * Copyright (c) 2022-2026 dsy4567 6 * SPDX-License-Identifier: MIT 7 */ 8 9// @ts-check 10"use strict"; 11 12const /** @type {Record<string, string[]>} */ å è½½æ¸ å = { 13 "/": ["home"], 14 "/blog": ["blog"], 15 "/friends": ["friends"], 16 }, 17 gr_sitekey = "6Ldo1dIkAAAAAM_2VtEneT3l7AE25HdWU45x03ng", 18 ç§»å¨ç«¯çé¢æå¤§å®½åº¦ = 1080; 19let è·¯å¾ = è·åæ¸ çåå½åè·¯å¾(), 20 æ£å¨å¨æå è½½ = false; 21 22//#region å 载模åã卿å è½½ 23async function å 载模å() { 24 è·¯å¾ = è·åæ¸ çåä¸çº§è·¯å¾(); 25 let è·¯å¾2 = è·åæ¸ çåå½åè·¯å¾(); 26 for (const s of å è½½æ¸ å[è·¯å¾] || []) { 27 const i = import(`/js/${s}.js`); 28 await schedulerYield(); 29 (await i).main(è·¯å¾2); 30 } 31 è·¯å¾ = è·¯å¾2; 32} 33/** 卿å è½½å 容ç¼åï¼é®ä¸ºãæ¸ çåçè·¯å¾ä¸å«æ¥è¯¢å符串ãï¼å¼ä¸ºå¹é å°çæ£æä¸æ é¢ï¼ä» åäºå åï¼é¡µé¢å ³éæ¶éä¼è¯éæ¯ */ 34const 卿å è½½ç¼å = /** @type {Map<string, { æ£æ: string, æ é¢: string }>} */ (new Map()); 35/** @param {{ href: string; popstate?: boolean, replaceState?: boolean }} å ç´ */ 36function 卿å è½½(å ç´ ) { 37 if (æ£å¨å¨æå è½½) { 38 open(å ç´ .href, "_self"); 39 return æ¾ç¤ºæéèè¿åº¦æ¡(false); 40 } 41 const ç®æ url = new URL(å ç´ .href, location.href), 42 é® = æ¸ çè·¯å¾(ç®æ url.pathname); 43 æ£å¨å¨æå è½½ = true; 44 已触å卿å è½½ = true; 45 æ¾ç¤ºæéèè¿åº¦æ¡(true); 46 47 gd("robots", true)?.setAttribute("content", ""); 48 49 /** å°åå¾ç页颿£æåºç¨å°å½å页é¢ï¼æ´æ°åå²ç¶æãæ é¢ãæ£æå¹¶å 载模å @param {string} æ£æ @param {string} æ é¢ */ 50 const åºç¨æ£æ = (æ£æ, æ é¢) => { 51 if (å ç´ .replaceState) history.replaceState({ è·¯å¾: é® }, "", å ç´ .href); 52 else if (!å ç´ .popstate) history.pushState({ è·¯å¾: é® }, "", å ç´ .href); 53 document.title = æ é¢ || "dsy4567 çå°ç«"; 54 dispatchEvent(URLåçååäºä»¶); 55 try { 56 let å³ = qs("main > .å³", true); 57 if (!å³) return; 58 // åè¿/åéå¯¼èªæ¶ï¼æ»å¨ä½ç½®ç±æµè§å¨æå岿¡ç®èªè¡æ¢å¤ï¼è¿éä¸åå¹²é¢ï¼å¦å伿已æ¢å¤çä½ç½®é¡¶åé¡¶é¨ï¼ 59 // ä½å¸¦ hash æ¶æµè§å¨æ æ³å®ä½å¨ææ¢å ¥åæåºç°çéç¹ï¼ä»éèªè¡å¤ç 60 if (!å ç´ .popstate && !location.hash) åå°é¡¶é¨(); 61 卿å è½½èªå¢è®¡æ°å¨++; 62 å³.innerHTML = æ£æ; 63 å 载模å().finally(() => { 64 æ£å¨å¨æå è½½ = false; 65 66 if (location.hash) { 67 schedulerYield(); 68 69 let /** @type {Element | null} */ ç®æ = null, 70 éæ©å¨ = `[id="${decodeURI(location.hash.substring(1))}"]`; 71 // æ»å¨å°hashä½ç½® 72 // ä¸è½éè¿èµå¼ location.hashï¼ç½®ç©ºåæ¢å¤ï¼è§¦åæ»å¨ï¼èµå¼ hash å±äº fragment 导èªï¼ 73 // ä¼ push æ°å岿¡ç®ï¼æ¢æ±¡æåéæ ï¼ä¹ä¼æ¸ 空åè¿æ ï¼å¯¼è´åéååè¿æé®åç°ï¼ 74 try { 75 ç®æ = å³.querySelector(éæ©å¨); 76 ç®æ ?.nextElementSibling?.classList.add("æ è®°"); 77 ç®æ ?.scrollIntoView({ 78 behavior: "smooth", 79 }); 80 } catch (e) { 81 console.error(e); 82 } 83 if (!ç®æ ) console.warn("æ¾ä¸å°å ç´ ", éæ©å¨); 84 } 85 86 渲æå¾æ (); 87 }); 88 } catch (e) { 89 console.error(e); 90 open(å ç´ .href, "_self"); 91 æ¾ç¤ºæéèè¿åº¦æ¡(false); 92 } 93 }; 94 95 // å½ä¸ç¼ååä¸ååèµ·è¯·æ± 96 const ç¼å = 卿å è½½ç¼å.get(é®); 97 if (ç¼å) return åºç¨æ£æ(ç¼å.æ£æ, ç¼å.æ é¢); 98 99 fetch(å ç´ .href) 100 .then(res => { 101 // æ ¡éªååºç±»åï¼è¯·æ±å¤±è´¥ãæå¹¶é HTML ææ¡£ï¼å¦å é¾å¾çãéæèµæºçï¼æ¶åºæç»ï¼ 102 // é¿å å°é HTML å 容å½ä½é¡µé¢æ£æå¨æå è½½ 103 if (!res.ok || !res.headers.get("content-type")?.toLowerCase().includes("html")) { 104 // æ¤æ¶åªæ¶å°äºååºå¤´ï¼æ£æè¿æ²¡ä¸è½½å®ï¼å¯¹å¤§æä»¶ï¼å缩å ãè§é¢çï¼ç«å³åæ¶ååºä½ï¼ 105 // é¿å æç¥ä¸æ¯ HTML è¿ææ´ä¸ªæä»¶æä¸æ¥ 106 res.body?.cancel().catch(() => {}); 107 throw new Error("卿å 载失败: ååºç±»åé HTML"); 108 } 109 return res.text(); 110 }) 111 .then(html => { 112 let m = html.match(/<!-- BEGIN MAIN -->.+<!-- END MAIN -->/s), 113 mt = html.match(/<title>.+<\/title>/s); 114 if (!m) throw new Error("卿å 载失败: å¹é ç»æä¸ºç©º"); 115 const æ¡ç® = { 116 æ£æ: m[0], 117 æ é¢: mt ? mt[0].replaceAll("<title>", "").replaceAll("</title>", "") : "", 118 }; 119 卿å è½½ç¼å.set(é®, æ¡ç®); 120 åºç¨æ£æ(æ¡ç®.æ£æ, æ¡ç®.æ é¢); 121 }) 122 .catch(e => { 123 console.error(e); 124 // ç®æ å¯è½æ¯æµè§å¨ç´æ¥ä¸è½½çæä»¶ï¼é¡µé¢ä¸ä¼è·³èµ°ï¼ï¼éå¤ä½ç¶æï¼ 125 // å¦ååç»ææç«å 龿¥ç¹å»é½ä¼éåææ´é¡µè·³è½¬ 126 æ£å¨å¨æå è½½ = false;
127 æ¾ç¤ºæéèè¿åº¦æ¡(false); 128 open(å ç´ .href, "_self"); 129 }); 130} 131//#endregion 132 133//#region 导åºåå 载模å 134_global["main.js"] = () => ({ 135 loaded, 136 DOMContentLoaded, 137 è·¯å¾, 138 徿 , 139 æ£å¨å¨æå è½½, 140 å 载模å, 141 卿å è½½, 142}); 143 144å 载模å(); 145//#endregion 146 147//#region ç½æäºé³ä¹ 148ç½é¡µè®¿é®è ä¸ä¸ºç¬è« && import("./ncm.js"); 149//#endregion 150 151//#region ä¸»é¢ 152fetch("/json/theme.json") 153 .then( 154 res => 155 new Promise((resolve, reject) => { 156 å»¶è¿æ§è¡("å ³é®ä»»å¡å®æ", () => resolve(res.json()), 3); 157 }) 158 ) 159 .then( 160 /** @type {Record<string, string>} */ 主é¢è¡¨ => { 161 const æ§ä»¶å®¹å¨ = gd("䏻颿§ä»¶", true), 162 主é¢å®¹å¨ = gd("ææä¸»é¢", true); 163 if (!æ§ä»¶å®¹å¨ || !主é¢å®¹å¨) return; 164 165 const f = () => { 166 //#region 第ä¸è¡ï¼èæ¯æ¨¡å¼åæ¢ãèªå®ä¹å¼ºè°è²è°è²ç 167 /** @type {HTMLButtonElement} */ 168 let æ¨¡å¼æé® = ce("button"); 169 æ¨¡å¼æé®.id = "èæ¯æ¨¡å¼"; 170 const æ´æ°æ¨¡å¼æé® = () => { 171 const æ¨¡å¼ = 读åèæ¯æ¨¡å¼(); 172 æ¨¡å¼æé®.title = "èæ¯: " + æ¨¡å¼ + (æ¨¡å¼ === "èªå¨" ? "ï¼è·éç³»ç»ï¼" : ""); 173 }; 174 æ¨¡å¼æé®.onclick = () => { 175 // èªå¨ â æµ è² â æ·±è² å¾ªç¯ 176 const å表 = /** @type {("èªå¨" | "æµ è²" | "æ·±è²")[]} */ ([ 177 "èªå¨", 178 "æµ è²", 179 "æ·±è²", 180 ]); 181 const ä¸ä¸ä¸ª = å表[(å表.indexOf(读åèæ¯æ¨¡å¼()) + 1) % å表.length]; 182 åºç¨èæ¯æ¨¡å¼(ä¸ä¸ä¸ª); 183 æ´æ°æ¨¡å¼æé®(); 184 æç¤º("èæ¯æ¨¡å¼: " + ä¸ä¸ä¸ª); 185 }; 186 æ´æ°æ¨¡å¼æé®(); 187 æ§ä»¶å®¹å¨.append(æ¨¡å¼æé®); 188 189 /** @type {HTMLButtonElement} */ 190 let è°è²çæé® = ce("button"); 191 è°è²çæé®.title = "èªå®ä¹å¼ºè°è²"; 192 è°è²çæé®.role = "radio"; 193 è°è²çæé®.ariaChecked = "false"; 194 è°è²çæé®.innerHTML = 195 "<svg class='ç¹å°å°ºå¯¸' data-icon='è°è²ç'></svg><input aria-label='èªå®ä¹å¼ºè°è²è°è²ç' style='opacity:0;pointer-events:none;position:absolute;top:0;width:0;height:0' tabindex='-1' id='èªå®ä¹å¼ºè°è²' type='color' />"; 196 è°è²çæé®.onclick = () => { 197 let è¾å ¥ = /** @type {HTMLInputElement} */ (gd("èªå®ä¹å¼ºè°è²", true)); 198 if (!è¾å ¥) return; 199 è¾å ¥.value = 读å强è°è²().toLowerCase(); 200 è¾å ¥.click(); 201 è¾å ¥.onchange = () => { 202 åºç¨å¼ºè°è²(è¾å ¥.value); 203 忥é䏿(); 204 æç¤º("已忢èªå®ä¹å¼ºè°è²"); 205 }; 206 }; 207 æ§ä»¶å®¹å¨.append(è°è²çæé®); 208 //#endregion 209 210 //#region 䏿¹ï¼é¢è®¾å¼ºè°è²è²æ¿ 211 /** æ ¹æ®å½å强è°è²é«äº®å¯¹åºè²æ¿ï¼ä¸ºèªå®ä¹è²æ¶é«äº®è°è²ç */ 212 const 忥é䏿 = () => { 213 const å½å = 读å强è°è²(); 214 let å½ä¸é¢è®¾ = false;
215 主é¢å®¹å¨.querySelectorAll("button").forEach(å ç´ => { 216 const å½ä¸ = å ç´ .dataset.hex === å½å; 217 å ç´ .ariaChecked = "" + å½ä¸; 218 if (å½ä¸) å½ä¸é¢è®¾ = true; 219 }); 220 è°è²çæé®.ariaChecked = "" + !å½ä¸é¢è®¾; 221 }; 222 /** @type {HTMLButtonElement[]} */ 223 let å¾ æ·»å å ç´ = []; 224 Object.entries(主é¢è¡¨).forEach(([åå, hex]) => { 225 /** @type {HTMLButtonElement} */ 226 let btn = ce("button"); 227 btn.dataset.hex = hex; 228 btn.style.backgroundColor = hex; 229 btn.title = "强è°è²: " + åå; 230 btn.role = "radio"; 231 btn.ariaChecked = "false"; 232 btn.onclick = () => { 233 åºç¨å¼ºè°è²(hex); 234 忥é䏿(); 235 æç¤º("å·²åæ¢å¼ºè°è²: " + åå); 236 }; 237 å¾ æ·»å å ç´ .push(btn); 238 }); 239 主é¢å®¹å¨.append(...å¾ æ·»å å ç´ ); 240 忥é䏿(); 241 //#endregion 242 243 // 渲æå¾æ (); 244 // æ¤åæå®å ç´ æ¸²ææ¥âæ²¡æç¶èç¹âï¼æ ¹å æ¯å¤ä¸ªâ渲æå¾æ âè°ç¨å¹¶åæ¶ï¼ 245 // 弿¥åæ¹å¤çä¼å¤çå°å·²è¢«æ¿æ¢èè±ç¦»ææ¡£çå ç´ ï¼ç°å·²å¨â渲æå¾æ âå è·³è¿ 246 渲æå¾æ ({ 247 è¦æ¸²æå¾æ çå ç´ : è°è²çæé®.getElementsByTagName("svg"), 248 }); 249 }; 250 gd("忢䏻é¢")?.addEventListener("mousemove", f, { once: true }); 251 } 252 ) 253 .catch(e => console.error(e)); 254//#endregion 255 256//#region 徿 257fetch("/json/icon.json") 258 .then( 259 res => 260 new Promise((resolve, reject) => { 261 å»¶è¿æ§è¡( 262 "DOMContentLoaded", 263 () => { 264 resolve(res.json()); 265 }, 266 1 267 ); 268 }) 269 ) 270 .then(j => { 271 徿 = j; 272 渲æå¾æ (); 273 }) 274 .catch(e => console.error(e)); 275//#endregion 276 277(async () => { 278 //#region ä¸è¨ 279 const è·åä¸è¨ = (/** @type {"text" | "json"} */ jsonç±»å) => 280 fetch("https://dsy4567.icu/api/hitokoto?c=a&c=b&encode=json").then( 281 res => 282 new Promise((resolve, reject) => { 283 å»¶è¿æ§è¡( 284 "å ³é®ä»»å¡å®æ", 285 () => { 286 resolve(/** @type {ä¸è¨å¥å} */ res[jsonç±»å]()); 287 }, 288 2 289 ); 290 }) 291 ); 292 293 try { 294 let ä¸è¨å ç´ = gd("ä¸è¨", true), 295 è¯å¥ = ce("span"), 296 ä½è = ce("span"), 297 // @ts-ignore 298 /** @type {HTMLAnchorElement | null} */ 龿¥ = qs("#ä¸è¨+a"), 299 ç¼åä¸è¨ = localStorage.getItem("ç¼åä¸è¨"), 300 /** @type {ä¸è¨å¥å} */ ä¸è¨json; 301 if (!ä¸è¨å ç´ || !龿¥) return; 302 try { 303 if (ç¼åä¸è¨) ç¼åä¸è¨ = JSON.parse(ç¼åä¸è¨); 304 } catch (e) { 305 ç¼åä¸è¨ = null; 306 } 307 308 await schedulerYield(); 309 ä¸è¨json = ç¼åä¸è¨ || (await è·åä¸è¨("json")); 310 await schedulerYield(); 311 è¯å¥.innerText = ä¸è¨json.hitokoto; 312 è¯å¥.classList.add("è¯å¥"); 313 ä½è .innerText = `ââ ${ä¸è¨json.from_who || ""} ã${ä¸è¨json.from || "æªç¥"}ã`; 314 ä½è .classList.add("ä½è "); 315 ä¸è¨å ç´ .innerHTML = ""; 316 ä¸è¨å ç´ .append(è¯å¥, ä½è ); 317 龿¥.href = "https://hitokoto.cn/?uuid=" + ä¸è¨json.uuid; 318 319 setTimeout(async () => { 320 try { 321 localStorage.setItem("ç¼åä¸è¨", await è·åä¸è¨("text")); 322 } catch (e) { 323 console.error(e); 324 } 325 }, 3000); 326 } catch (e) { 327 console.error(e); 328 } 329 //#endregion 330})(); 331 332//#region å ³æ³¨è¢«å ³æ³¨ç é¾ 333/** å° GitHub ä¸ªäººä¿¡æ¯æ¸²æå°ãå ³æ³¨è¢«å ³æ³¨ç é¾ãå ç´ @param {{ following: number, followers: number, created_at: string }} ä¸ªäººä¿¡æ¯ */ 334const 渲æä¸ªäººä¿¡æ¯ = ä¸ªäººä¿¡æ¯ => { 335 const å ³æ³¨è¢«å ³æ³¨ç é¾ = gd("å ³æ³¨è¢«å ³æ³¨ç é¾"); 336 if ( 337 !å ³æ³¨è¢«å ³æ³¨ç é¾ || 338 typeof 个人信æ¯.following !== "number" || 339 typeof 个人信æ¯.followers !== "number" || 340 typeof 个人信æ¯.created_at !== "string" 341 ) 342 return; 343 å ³æ³¨è¢«å ³æ³¨ç é¾.innerText = ` å ³æ³¨: ${个人信æ¯.following} | è¢«å ³æ³¨: ${ 344 个人信æ¯.followers 345 } | ç é¾: ${new Date().getFullYear() - new Date(个人信æ¯.created_at).getFullYear()}å¹´ `; 346}; 347 348// ç¼åé®ï¼GitHub 个人信æ¯ï¼å½ä¸æ¶å ç«å³æ¸²æï¼ååå°é黿忿°æ°æ®è¦ç 349const 个人信æ¯ç¼åé® = "ç¼å个人信æ¯"; 350try { 351 const ç¼åä¸ªäººä¿¡æ¯ = JSON.parse(localStorage.getItem(个人信æ¯ç¼åé®) || "null"); 352 if (ç¼å个人信æ¯) 渲æä¸ªäººä¿¡æ¯(ç¼å个人信æ¯); 353} catch (e) { 354 // ç¼åæåï¼å¦æå¨æ¹åï¼æ¶å¿½ç¥ï¼çå¾ ä¸é¢çæåç»æ 355 console.error(e); 356} 357 358fetch("https://api.github.com/users/dsy4567") 359 .then( 360 res => 361 new Promise((resolve, reject) => { 362 å»¶è¿æ§è¡( 363 "å ³é®ä»»å¡å®æ", 364 () => { 365 resolve(res.json()); 366 }, 367 2 368 ); 369 }) 370 ) 371 .then(ä¸ªäººä¿¡æ¯ => { 372 // æåæåå³åå ¥ç¼åå¹¶ç«å³æ´æ°é¡µé¢ï¼æå失败æ¶ä¿çç¼åå 容ï¼ç»§ç»å±ç¤ºæ§æ°æ® 373 try { 374 localStorage.setItem(个人信æ¯ç¼åé®, JSON.stringify(个人信æ¯)); 375 } catch (e) { 376 console.error(e); 377 } 378 渲æä¸ªäººä¿¡æ¯(个人信æ¯); 379 }) 380 .catch(e => console.error(e)); 381//#endregion 382 383å»¶è¿æ§è¡( 384 "å ³é®ä»»å¡å®æ", 385 () => { 386 try { 387 //#region æ ¸å¿å ç´ ãäºä»¶ãåä½cssç 388 gd("åå°é¡¶é¨")?.addEventListener("click", åå°é¡¶é¨); 389 gd("åç线")?.addEventListener("click", () => { 390 document.body.classList.toggle("宽å±"); 391 }); 392 //#endregion 393 394 //#region reCAPTCHA è·åé®ç®±/tg
395 [gd("çµåé®ç®±"), gd("tg")].forEach(å ç´ => { 396 å ç´ ?.addEventListener("click", äºä»¶ => { 397 äºä»¶.preventDefault(); 398 if (gd("recaptcha")) return; 399 let div = æ·»å æ¬æµ®å¡ç( 400 ` 401 <div id="g-recaptcha"></div><br /> 402 <button id="recaptcha">å¼å§äººæºéªè¯/æäº¤</button> 403 <button id="close_recaptcha">å ³é</button> 404 <a href="https://qwq.dsy4567.icu/api/getemail">卿°æ ç¾é¡µéªè¯</a><br/> 405 è¦æ¥ç dsy4567 ççµåé®ç®±å°å/TG ç¨æ·åï¼è¯·éè¿ reCAPTCHA 人æºéªè¯ã<br /> 406 ç»§ç»æ¥ççµåé®ç®±å°åå³ä»£è¡¨æ¨åæä¸å dsy4567<br /> 407 åé广å/è¦é¥/é童工/çå¸çåå¾é®ä»¶ã`, 408 // @ts-ignore 409 äºä»¶.pageX, 410 // @ts-ignore 411 äºä»¶.pageY, 412 false 413 ); 414 æ·»å èæ¬("https://www.recaptcha.net/recaptcha/api.js?render=explicit", null) 415 .then(() => { 416 gd("close_recaptcha")?.addEventListener("click", () => { 417 div.remove(); 418 }); 419 gd("recaptcha")?.addEventListener("click", async äºä»¶ => { 420 const gr = gd("g-recaptcha"); 421 if (!gr) return; 422 try { 423 const åå¤ = grecaptcha.getResponse(); 424 if (!åå¤) throw new Error(); 425 gr.innerHTML = await ( 426 await fetch( 427 "https://qwq.dsy4567.icu/api/getemail?g-recaptcha-response=" + 428 åå¤ 429 ) 430 ).text(); 431 gr.focus(); 432 } catch (e) { 433 gr.tabIndex = 0; 434 gr.focus(); 435 grecaptcha.render("g-recaptcha", { 436 sitekey: gr_sitekey, 437 theme: matchMedia("(prefers-color-scheme: dark)").matches 438 ? "dark" 439 : "light", 440 }); 441 } 442 }); 443 }) 444 .catch(() => { 445 console.error("æ æ³å è½½ reCAPTCHA"); 446 open("https://qwq.dsy4567.icu/api/getemail", "_blank"); 447 div.remove(); 448 }); 449 }); 450 }); 451 //#endregion 452 453 //#region 夿¡ 454 let fuck = gd("fuck"); 455 if (fuck) 456 fuck.innerText = 457 ["\u4f60\u5988", "\u5c3c\u739b", "\u4f60\u5927\u7237", "\u5bc4\u5427"][ 458 éæºå«é¶èªç¶æ°(3) 459 ] || "\u4f60\u5988"; 460 //#endregion 461 462 //#region å¯¼èªæ ãæ é¢é«äº® 463 464 /** è®°å½ä¸ä¸æ¬¡è§¦åæ ·å¼åæ¢æ¶çæ»å¨ä½ç½®ï¼ä½ä¸ºç´¯è®¡æ»å¨å¹ 度çåºåï¼ä¸å¨æ¯æ¬¡æ»å¨æ¶æ´æ°ï¼ */ 465 let scrollTop = 0, 466 /** 467 * å½åå¯¼èªæ çæ¾ç¤ºæ¨¡å¼ 468 * - -1ï¼åå§ç¶æï¼å°æªå¤æè¿ï¼ 469 * - 0ï¼é¡µé¢ä½äºé¡¶é¨ï¼æ¾ç¤ºé¡¶é¨æ ·å¼ï¼ 470 * - 1ï¼å䏿»å¨ï¼éèå¯¼èªæ ï¼ 471 * - 2ï¼å䏿»å¨ï¼æ¾ç¤ºå¯¼èªæ ï¼ä½ä¸å«é¡¶é¨æ ·å¼ï¼ 472 */ 473 ç¶æ = -1; 474 let é¡¶é¨ä¸å®èå´ä¸éèéå¼ = 494; 475 476 /** è§¦åæ ·å¼åæ¢æéçæå°æ»å¨å¹ 度ï¼pxï¼ï¼é¿å å°å¹ æ»å¨é¢ç¹åæ¢å¯¼è´å¯¼èªæ æå¨ */ 477 const æ»å¨éå¼ = 25; 478 const ç±»å表 = document.body.classList; 479 480 /** 481 * 馿¬¡ç嬿»å¨åçå»¶è¿æ¶é¿ï¼æ¯«ç§ï¼ï¼é¦å±ï¼å«å¨ææ¢é¡µéå»ºæ£æï¼æé´æµè§å¨å¯è½æ´¾åæ»å¨äºä»¶ï¼ 482 * æ¤æ¶è¯»å scrollY ä¼å¼ºå¶åæ¥å¸å±èå¼åéæï¼æ å»¶è¿æ³¨åçå¬å¨ï¼æé´çæ»å¨äºä»¶ä¸å¾å¿½ç¥ 483 */ 484 const æ»å¨çå¬å»¶è¿ = 3000; 485 486 /** 487 * æ é¢é«äº®å¤å®çº¿æå¨çè§å£é«åº¦ç¾åæ¯ï¼æ é¢é¡¶ç«¯è¶ è¿è¯¥çº¿å³è§ä¸ºâå·²æ»è¿âï¼ 488 * åæåä¸ä¸ªå·²æ»è¿çæ é¢ä½ä¸ºå½åé 读ä½ç½®ï¼å¯è§éè¦è°æ´ï¼ 489 */ 490 const æ»å¨é«äº®è§å£ç¾åæ¯ = 0.65; 491 /** åä¸é«äº®çæ é¢éæ©å¨ï¼ä¸ global-nfp.css ä¸ ::before çæ ·å¼è§åä¿æä¸è´ */ 492 const æ é¢éæ©å¨ = ":is(h1, h2, h3, h4, h5, h6):not(:has(svg))"; 493 494 // æ»å¨ä¸é¼ æ åèªç»´æ¤ä¸ä¸ªé«äº®ç±»ï¼äºä¸å¹²æ°ï¼å æ¤æ éå¨ä¸¤è ä¹é´åç«äºä»²è£ 495 /** ä¸ä¸æ¬¡è¢«æ»å¨é»è¾é«äº®çæ é¢ @type {Element | null} */ 496 let 䏿¬¡æ»å¨é«äº®æ é¢ = null; 497 /** ä¸ä¸æ¬¡è¢«é¼ æ é»è¾é«äº®çæ é¢ @type {Element | null} */ 498 let 䏿¬¡é¼ æ é«äº®æ é¢ = null; 499 /** åä¸é«äº®çæ é¢å ç´ å表ç¼å @type {Element[]} */ 500 let æ é¢å ç´ å表 = []; 501 /** æ é¢å ç´ å表æ¯å¦ä»ä¸æ£æä¸è´ï¼æ£æåèç¹åååç½®å¦ */ 502 let æ é¢åè¡¨ææ = false;
503 504 /** 505 * å½åæ£æå åä¸é«äº®çæ é¢å ç´ åè¡¨ï¼æ£æåååèªå¨éæ°è·å 506 * æ£æå¸¸ç±å ¶ä»æ¨¡å弿¥åå ¥ï¼å¦ blog.js æåå®æç« åææ¿æ¢å è½½æç¤ºï¼ï¼ 507 * æ¢é¡µè®¡æ°å¨æ æ³é¢ç¥è¿ç§è¿å°åå ¥ï¼æ ç±è§å¯æ£æåèç¹ååç MutationObserver ç½®å¦ 508 * @returns {Element[]} 509 */ 510 const åæ é¢å ç´ å表 = () => { 511 if (æ é¢å表ææ) return æ é¢å ç´ å表; 512 æ é¢åè¡¨ææ = true; 513 æ é¢å ç´ å表 = Array.from( 514 qs("main > .å³", true)?.querySelectorAll(æ é¢éæ©å¨) || [] 515 ); 516 // ä¸éç½® 䏿¬¡æ»å¨é«äº®æ é¢/䏿¬¡é¼ æ é«äº®æ é¢ï¼æ£æå±é¨å¢å æ¶æ§é«äº®èç¹å¯è½ä»å¨ææ¡£ä¸ï¼ 517 // ä¿çå¼ç¨æè½è®© 忢æ é¢é«äº® ä»å®èº«ä¸ç§»é¤é«äº®ç±» 518 return æ é¢å ç´ å表; 519 }; 520 521 /** 522 * ææä¸ªé«äº®ç±»ä»æ§ç®æ è¿ç§»å°æ°ç®æ ï¼æ°æ§ç¸åæ¶ä¸åä»»ä½äº 523 * @param {"é«äº®-æ»å¨" | "é«äº®-é¼ æ "} ç±»å 524 * @param {Element | null} æ§ç®æ 525 * @param {Element | null} æ°ç®æ 526 * @returns {Element | null} æ°ç®æ 527 */ 528 const 忢æ é¢é«äº® = (ç±»å, æ§ç®æ , æ°ç®æ ) => { 529 if (æ§ç®æ === æ°ç®æ ) return æ°ç®æ ; 530 æ§ç®æ ?.classList.remove(ç±»å); 531 æ°ç®æ ?.classList.add(ç±»å); 532 return æ°ç®æ ; 533 }; 534 535 setTimeout(() => { 536 const çªå£å°ºå¯¸åå = () => { 537 if (document.body.clientWidth <= ç§»å¨ç«¯çé¢æå¤§å®½åº¦) 538 é¡¶é¨ä¸å®èå´ä¸éèéå¼ = 539 qs("main > .å³")?.offsetTop || é¡¶é¨ä¸å®èå´ä¸éèéå¼; 540 }; 541 addEventListener("resize", çªå£å°ºå¯¸åå); 542 çªå£å°ºå¯¸åå(); 543 544 /** æ ¹æ®å½åæ»å¨ä½ç½®æ´æ°å¯¼èªæ çæ¾ç¤ºæ¨¡å¼ */ 545 const æ´æ°å¯¼èªæ = () => { 546 const å½åæ»å¨ä½ç½® = scrollY; 547 548 // æ åµä¸ï¼æ»å¨å°é¡µé¢é¡¶é¨ï¼scrollTop <= é¡¶é¨ä¸å®èå´ä¸éèéå¼ - 64ï¼ä¸å½åç¶æä¸æ¯âé¡¶é¨â 549 if (å½åæ»å¨ä½ç½® <= é¡¶é¨ä¸å®èå´ä¸éèéå¼ - 64) { 550 if (ç¶æ !== 0) { 551 ç±»å表.add("é¡¶é¨"); 552 ç±»å表.remove("éèå¯¼èªæ "); 553 ç¶æ = 0; 554 } 555 scrollTop = 0; 556 } 557 // æ åµäºï¼å䏿»å¨ä¸ç´¯è®¡å¹ åº¦è¶ è¿éå¼ï¼ç¶æä¸æ¯âéèå¯¼èªæ â 558 else if (å½åæ»å¨ä½ç½® - scrollTop > æ»å¨éå¼) { 559 if (ç¶æ !== 1) { 560 ç±»å表.remove("é¡¶é¨"); 561 ç±»å表.add("éèå¯¼èªæ "); 562 ç¶æ = 1; 563 } 564 scrollTop = å½åæ»å¨ä½ç½®; 565 } 566 // æ åµä¸ï¼å䏿»å¨ä¸ç´¯è®¡å¹ åº¦è¶ è¿éå¼ï¼ç¶æä¸æ¯âæ¾ç¤ºå¯¼èªæ â 567 else if (scrollTop - å½åæ»å¨ä½ç½® > æ»å¨éå¼) { 568 if (ç¶æ !== 2) { 569 ç±»å表.remove("é¡¶é¨", "éèå¯¼èªæ "); 570 ç¶æ = 2; 571 } 572 scrollTop = å½åæ»å¨ä½ç½®; 573 } 574 }; 575 576 /** é«äº®å¤å®çº¿ä¸æ¹æåä¸ä¸ªæ é¢ï¼ä½ä¸ºå½åé 读ä½ç½® */ 577 const æ´æ°æ»å¨é«äº® = () => { 578 const å¤å®çº¿ = innerHeight * æ»å¨é«äº®è§å£ç¾åæ¯; 579 /** @type {Element | null} */ 580 let å½ä¸ = null; 581 // æ é¢å¨ææ¡£ä¸èªä¸è䏿åï¼é¡ºåºè¯»ååæ å³å¯ï¼getBoundingClientRect åªè¯»ä¸åï¼ 582 // ç»ä¸è¯»å®åæ¹ç±»åï¼é¿å éå ç´ è¯»å交æ¿é æçå¸å±æå¨ 583 for (const æ é¢ of åæ é¢å ç´ å表()) { 584 if (æ é¢.getBoundingClientRect().top > å¤å®çº¿) break; 585 å½ä¸ = æ é¢; 586 } 587 䏿¬¡æ»å¨é«äº®æ é¢ = 忢æ é¢é«äº®("é«äº®-æ»å¨", 䏿¬¡æ»å¨é«äº®æ é¢, å½ä¸); 588 }; 589 590 /** é«äº®å æ 䏿¹æè¿çæ é¢ï¼å æ ä½äºæææ é¢ä¹ä¸æ¶æ¸ é¤é«äº® @param {number} å æ Y */ 591 const æ´æ°é¼ æ é«äº® = å æ Y => { 592 /** @type {Element | null} */ 593 let å½ä¸ = null; 594 for (const æ é¢ of åæ é¢å ç´ å表()) { 595 if (æ é¢.getBoundingClientRect().top > å æ Y) break; 596 å½ä¸ = æ é¢; 597 } 598 // å½ä¸ä¸º nullï¼å æ å¨æææ é¢ä¹ä¸ï¼æ¶ï¼åæ¢æ é¢é«äº® ä¼é¡ºå¸¦ç§»é¤æ§ç®æ çé«äº® 599 䏿¬¡é¼ æ é«äº®æ é¢ = 忢æ é¢é«äº®("é«äº®-é¼ æ ", 䏿¬¡é¼ æ é«äº®æ é¢, å½ä¸); 600 }; 601 602 // rAF èæµï¼ä¸å¸§å 夿¬¡è§¦ååªæ§è¡ä¸æ¬¡ï¼å¯¼èªæ 䏿 é¢é«äº®å ±ç¨å䏿¬¡å¸§åè° 603 let å·²æé = false;
604 /** æå¯¼èªæ 䏿»å¨é«äº®çæ´æ°åå¹¶å°åä¸å¸§æ§è¡ */ 605 const æéæ´æ° = () => { 606 if (å·²æé) return; 607 å·²æé = true; 608 requestAnimationFrame(() => { 609 å·²æé = false; 610 æ´æ°å¯¼èªæ (); 611 æ´æ°æ»å¨é«äº®(); 612 }); 613 }; 614 addEventListener( 615 "scroll", 616 () => { 617 // console.log("onscroll"); 618 æéæ´æ°(); 619 }, 620 { passive: true } 621 ); 622 623 // è§å¯æ£æåèç¹å¢å ï¼è¦çæ¢é¡µä»¥å¤çåå ¥ï¼å«å ¶ä»æ¨¡åç弿¥åå ¥ä¸å±é¨è¿½å ï¼ï¼ 624 // æ£æå ç´ èªèº«ä¸éæ¢é¡µæ¿æ¢ï¼å¨ææ¢é¡µåªæ¿æ¢å ¶ innerHTMLï¼ï¼æ å¯é¿æè§å¯ï¼ 625 // ä¸åªè§å¯åèç¹ãä¸è§å¯å±æ§ï¼é¿å é«äº®ç±»åçå¢å åè¿æ¥è§¦åè§å¯å¨ 626 const æ£æå ç´ = qs("main > .å³", true); 627 if (æ£æå ç´ ) 628 new MutationObserver(() => { 629 æ é¢åè¡¨ææ = false; 630 // æ£æåå ¥æ¶ç¨æ·æªå¿ 伿»å¨æç§»å¨é¼ æ ï¼è¿éè¡¥ä¸æ¬¡æ´æ°ï¼é¿å é«äº®é¿æ¶é´ç¼ºå¸ 631 æéæ´æ°(); 632 }).observe(æ£æå ç´ , { childList: true, subtree: true }); 633 634 let é¼ æ å·²æé = false, 635 å æ Y = 0; 636 // ç¨ pointermove èé mousemoveï¼é¤é¼ æ å¤è¿è½è¦çæåç¬çæ¬æµ®ï¼ 637 // è¿æ»¤ pointerType æé¤è§¦æ¸ï¼è§¦æ¸æå¨ä¸åä¸é«äº®ï¼è§¦æ¸ä¹æ²¡æçæ£çãæ¬æµ®ãï¼ 638 addEventListener( 639 "pointermove", 640 äºä»¶ => { 641 if (äºä»¶.pointerType !== "mouse" && äºä»¶.pointerType !== "pen") return; 642 å æ Y = äºä»¶.clientY; 643 if (é¼ æ å·²æé) return; 644 é¼ æ å·²æé = true; 645 requestAnimationFrame(() => { 646 é¼ æ å·²æé = false; 647 æ´æ°é¼ æ é«äº®(å æ Y); 648 }); 649 }, 650 { passive: true } 651 ); 652 }, æ»å¨çå¬å»¶è¿); 653 //#endregion 654 655 //#region å廿å¼å¾ç/å¤å¶ä»£ç 656 addEventListener("dblclick", äºä»¶ => { 657 // å廿å¼å¾ç 658 const /** @type {HTMLImageElement | undefined} */ t1 = 659 // @ts-ignore 660 äºä»¶.target?.tagName === "IMG" 661 ? äºä»¶.target 662 : // @ts-ignore 663 äºä»¶.target?.parentElement.tagName === "IMG" 664 ? // @ts-ignore 665 äºä»¶?.target.parentElement 666 : undefined; 667 if (t1) return open(t1.src, "_blank"); 668 669 // å¤å¶ä»£ç 670 const /** @type {HTMLImageElement | undefined} */ t2 = 671 // @ts-ignore 672 äºä»¶.target?.classList.contains("hljs") 673 ? äºä»¶.target 674 : // @ts-ignore 675 äºä»¶.target?.parentElement.classList.contains("hljs") 676 ? // @ts-ignore 677 äºä»¶?.target.parentElement 678 : undefined; 679 if (t2) { 680 t2.classList.add("å·²å¤å¶"); 681 setTimeout(() => { 682 t2?.classList.remove("å·²å¤å¶"); 683 }, 3000); 684 navigator.clipboard.writeText(t2.innerText); 685 äºä»¶.preventDefault(); 686 } 687 }); 688 //#endregion 689 690 //#region å¼å ¥ç»è®¡èæ¬ 691 import("./analytics.js"); 692 //#endregion 693 } catch (e) { 694 console.error(e); 695 } 696 }, 697 3 698); 699 700addEventListener("copy", () => { 701 æç¤º("å¤å¶æå"); 702}); 703addEventListener("popstate", äºä»¶ => { 704 // hash ååæ§è¡é»è®¤è¡ä¸º 705 if (è·åæ¸ çåå½åè·¯å¾() === è·¯å¾ || äºä»¶.state?.è·¯å¾ === è·¯å¾) return äºä»¶.preventDefault(); 706 卿å è½½({ 707 href: location.href, 708 popstate: true, 709 }); 710}); 711/** ç¨äºä»¶å§æç»ä¸å¤ç卿å è½½é¾æ¥çç¹å»ï¼é¿å ç»æ¯ä¸ªé¾æ¥åç¬ç»å®çå¬å¨åéå */ 712addEventListener("click", äºä»¶ => { 713 const ç®æ = äºä»¶.target; 714 if (!(ç®æ instanceof Element)) return; 715 const a = ç®æ .closest("a"); 716 if (!a) return; 717 // ä¸è½½é¾æ¥ã以åæå®äºé _self æå¼æ¹å¼ç龿¥äº¤ç»æµè§å¨èªè¡å¤çï¼ä¸åèµ·å¨æå è½½è¯·æ± 718 if (a.hasAttribute("download") || (a.target && a.target !== "_self")) return; 719 720 const æ¬ç« = location.host, 721 å½åè·¯å¾ = location.pathname; 722 723 if (a.pathname === å½åè·¯å¾ && a.hash) return; 724 else if (a.host === æ¬ç«) { 725 äºä»¶.preventDefault(); 726 卿å è½½(a); 727 } else a.target = "_blank"; 728}); 729 730//#region ååè¿ç§» 731// ååè¿ç§»ï¼é .icu ååèªå¨è·³è½¬å°æ°åå dsy4567.icu 732// æµç¨ï¼ 733// 1. ç¬è« / æ¬å°ç¯å¢ / 已卿°ååï¼ä¸éå仿§ååè·³æ¥ï¼â ä¸åä»»ä½å¤ç 734// 2. å仿§ååè·³æ¥ï¼URL 带 from-non-icu-tldï¼â 卿°ååä¸å¼¹ãååååãæ¨ªå¹ 735// 3. ç¨æ·éæ©è¿ãä¸è·³è½¬ãï¼URL åæ°æ localStorage ç no-redirectï¼â ä» å¼¹æ¨ªå¹ æç¤ºæ°åå 736// 4. å ¶ä½æ åµ â èªå¨è·³è½¬å¹¶å¨ URL æºå¸¦æ¥æºåæ°ï¼ä¾æ°åå页é¢å¼¹ãååååãæ¨ªå¹ 737å»¶è¿æ§è¡( 738 "å ³é®ä»»å¡å®æ", 739 () => { 740 try { 741 // æææ¹åå å¨ URL 坿¬ä¸è¿è¡ï¼æåç»ä¸çæ 742 let U = new URL(location.href); 743 // å é¤è¿ç§»æµç¨ä¸ç¨ç URL åæ°ï¼ 744 // from-hostnameï¼æ¥æºååï¼ãfrom-non-icu-tldï¼æ¥èªé .icu ååï¼ãno-redirectï¼ç¨æ·éæ©ä¸è·³è½¬ï¼ 745 const å é¤urlåæ° = () => { 746 U.searchParams.delete("from-hostname"); 747 U.searchParams.delete("from-non-icu-tld"); 748 U.searchParams.delete("no-redirect"); 749 }; 750 const æ¬å°åå = ["dev.dsy4567.icu", "localhost"]; 751 const æ¯å¦ä¸ºçº¯ip = /** @param {string} hostname */ hostname => { 752 return hostname.split(".").every(p => {
753 const n = Number(p); 754 return Number.isInteger(n) && n >= 0 && n <= 255 && String(n) === p; 755 }); 756 }; 757 758 // æ¯å¦å仿§ååè·³æ¥ï¼URL 带 from-non-icu-tld æ è®°ï¼ 759 const æ¥èªæ§åå = JSON.parse(U.searchParams.get("from-non-icu-tld") || "false"); 760 761 // å·²å¨ dsy4567.icuï¼å«åååï¼æé»ååååä¸åæ éå¤çï¼ 762 // ä¾å¤ï¼å仿§ååè·³æ¥ç请æ±éæ¾è¡ï¼å¦å䏿¹æ åµ C æ°¸è¿ä¸ä¼æ§è¡ 763 if ( 764 (location.hostname.endsWith("dsy4567.icu") && !æ¥èªæ§åå) || 765 location.hostname.endsWith(".ts.net") || // Tailscale 766 æ¬å°åå.includes(location.hostname) || 767 æ¯å¦ä¸ºçº¯ip(location.hostname) 768 ) 769 return; 770 771 // æ åµ Aï¼ç¨æ·å·²éæ©ãä¸è·³è½¬ãâ ä» å¼¹æ¨ªå¹ æç¤ºï¼ä¸å¼ºå¶è·³è½¬ 772 // æ¥èªæ§ååæ¶ä¸éç¨ï¼æ¤æ¶å·²å¨æ°ååä¸ï¼å¼¹ãè¿ç§»è³æ°ååãæ¨ªå¹ 没ææä¹ 773 if ( 774 !æ¥èªæ§åå && 775 ç½é¡µè®¿é®è ä¸ä¸ºç¬è« && 776 (JSON.parse(U.searchParams.get("no-redirect") || "false") || 777 JSON.parse(localStorage.getItem("no-redirect") || "false")) 778 ) { 779 // æä¹ åéæ©ï¼ä¹åå³ä½¿ URL ä¸å¸¦ no-redirect ä¹ä¸åèªå¨è·³è½¬ 780 localStorage.setItem("no-redirect", "true"); 781 // å¼¹æ¨ªå¹ ï¼å¹¶ææ¨ªå¹ å 龿¥æåæ°ååçåè·¯å¾é¡µé¢ 782 let æ¨ªå¹ = æ·»å æ¨ªå¹ ( 783 'æ¬ç«å·²è¿ç§»è³æ°åå dsy4567.icuï¼æ¨å¯ä»¥<a href="#">è®¿é®æ°åå</a>' 784 ), 785 a = æ¨ªå¹ .querySelector("a"); 786 å é¤urlåæ°(); 787 if (a?.href && a?.hostname) { 788 a.href = U.href; 789 a.hostname = "dsy4567.icu"; 790 } 791 } else if (!æ¥èªæ§åå) { 792 // æ åµ Bï¼é»è®¤èªå¨è·³è½¬å°æ°åå 793 if (ç½é¡µè®¿é®è ä¸ä¸ºç¬è«) { 794 // å¨ URL ä¸è®°å½æ¥æºä¿¡æ¯ï¼ä¾æ°åå页é¢å¼¹ãååååãæ¨ªå¹ ä½¿ç¨ 795 U.searchParams.set("from-non-icu-tld", "true"); 796 U.searchParams.set("from-hostname", location.hostname); 797 } else å é¤urlåæ°(); 798 799 U.hostname = "dsy4567.icu"; 800 location.href = U.href; 801 } 802 803 // æ åµ Cï¼å仿§ååè·³æ¥ï¼URL 带 from-non-icu-tldãfrom-hostnameï¼â 卿°ååä¸å¼¹ãååååãæ¨ªå¹ 804 let ååå = U.searchParams.get("from-hostname"); 805 if (ç½é¡µè®¿é®è ä¸ä¸ºç¬è« && æ¥èªæ§åå) { 806 let æ¨ªå¹ = æ·»å æ¨ªå¹ ('æ¬ç«å·²è¿ç§»è³æ°ååï¼æ¨ä¹å¯ä»¥<a href="#">访é®ååå</a>'), 807 a = æ¨ªå¹ .querySelector("a"); 808 å é¤urlåæ°(); 809 // ç»åè·³é¾æ¥å¸¦ä¸ no-redirect=trueï¼ç¨æ·ç¹åååååä¸ä¼å被èªå¨è·³åï¼é¿å 两个ååäºç¸éå®å 810 U.searchParams.set("no-redirect", "true"); 811 if (ååå && a?.href && a?.hostname) { 812 a.href = U.href; 813 a.hostname = ååå; 814 } 815 } 816 // æ¸ çè¾ å©åæ°å¹¶åæ¥å°å°åæ ï¼replaceState ä¸ä¼æ°å¢åå²è®°å½ï¼ 817 å é¤urlåæ°(); 818 history.replaceState(history.state, "", U.href); 819 } catch (e) { 820 console.error(e); 821 } 822 }, 823 3 824); 825//#endregion 826 827//#region localStorageãSW管ç 828å»¶è¿æ§è¡( 829 "å ³é®ä»»å¡å®æ", 830 () => { 831 try { 832 // æ¸ çæ§ç主é¢é®ï¼æ§æ¨¡å为å¤é®åå¨ï¼å·²è¢«ä¸¤çº§æ¨¡ååä»£ï¼ 833 ["theme", "主é¢è²", "主é¢è²h", "主é¢è²s", "主é¢è²l", "éæè²", "åä½è²"].forEach(é® => 834 localStorage.removeItem(é®) 835 ); 836 837 // "serviceWorker" in navigator && navigator.serviceWorker.register("/sw.js"); 838 839 // ç§»é¤ Service Worker å¹¶æ¸ çç¼å 840 async function removeServiceWorker() { 841 if ("serviceWorker" in navigator) { 842 // 1. è·åæææ³¨å 843 const registrations = await navigator.serviceWorker.getRegistrations(); 844 845 // 2. é个注é 846 for (let registration of registrations) await registration.unregister(); 847 848 // 3. æ¸ çææç¼å 849 const cacheNames = await caches.keys(); 850 await Promise.all(cacheNames.map(name => caches.delete(name))); 851 console.log("Service Worker 已移é¤ï¼ç¼åå·²æ¸ ç©º"); 852 } 853 } 854 855 removeServiceWorker().catch(e => console.error(e)); 856 } catch (e) { 857 console.error(e); 858 } 859 }, 860 3 861); 862//#endregion 863 864export {};
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.