<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>FullFinger&#39;s blog</title>
    <link>https://full-finger.github.io/</link>
    <description>Recent content on FullFinger&#39;s blog</description>
    <generator>Hugo</generator>
    <language>zh-cn</language>
    <lastBuildDate>Mon, 23 Mar 2026 22:05:45 +0800</lastBuildDate>
    <atom:link href="https://full-finger.github.io/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>光学性质计算</title>
      <link>https://full-finger.github.io/post/26032201/</link>
      <pubDate>Sun, 22 Mar 2026 20:30:00 +0800</pubDate>
      <guid>https://full-finger.github.io/post/26032201/</guid>
      <description>通过简单的振子模型来估计硅酸盐玻璃的折射率等光学性质</description>
    </item>
    <item>
      <title>Hello World!</title>
      <link>https://full-finger.github.io/post/helloworld/</link>
      <pubDate>Tue, 22 Oct 2019 18:46:47 +0800</pubDate>
      <guid>https://full-finger.github.io/post/helloworld/</guid>
      <description>&lt;p&gt;这是一篇测试的文章，您不必理会其内容&lt;/p&gt;</description>
    </item>
    <item>
      <title></title>
      <link>https://full-finger.github.io/readme/</link>
      <pubDate>Mon, 01 Jan 0001 00:00:00 +0000</pubDate>
      <guid>https://full-finger.github.io/readme/</guid>
      <description>&lt;h1 id=&#34;欢迎&#34;&gt;欢迎&lt;/h1&gt;&#xA;&lt;p&gt;&lt;img src=&#34;https://img.shields.io/badge/%E4%BD%A0%E5%A5%BD!-orangeorange.svg?style=social&#34; alt=&#34;欢迎语1&#34;&gt;&lt;br&gt;&#xA;&lt;img src=&#34;https://img.shields.io/badge/Hello!-orangeorange.svg?style=social&#34; alt=&#34;欢迎语2&#34;&gt;&lt;br&gt;&#xA;&lt;img src=&#34;https://img.shields.io/badge/Ciallo%EF%BD%9E%28%E2%88%A0%E3%83%BB%CF%89%3C%29%E2%8C%92%E2%98%85-orange?style=social&#34; alt=&#34;欢迎语3&#34;&gt;&lt;br&gt;&#xA;&lt;img src=&#34;https://img.shields.io/badge/%E3%81%93%E3%82%93%E3%81%AB%E3%81%A1%E3%81%AF!-orangeorange.svg?style=social&#34; alt=&#34;欢迎语4&#34;&gt;&lt;/p&gt;&#xA;&#xD;&#xA;&lt;div class=&#34;gh-heatmap-wrap&#34;&gt;&#xD;&#xA;  &lt;div class=&#34;gh-heatmap-card&#34;&gt;&#xD;&#xA;    &lt;div class=&#34;gh-heatmap-header&#34;&gt;&#xD;&#xA;      &lt;h3 class=&#34;gh-heatmap-title&#34;&gt;GitHub&lt;/h3&gt;&#xD;&#xA;      &lt;span class=&#34;gh-heatmap-stats&#34;&gt;&#xD;&#xA;        过去一年 &lt;strong id=&#34;gh-stats-count&#34;&gt;--&lt;/strong&gt; 次贡献&#xD;&#xA;      &lt;/span&gt;&#xD;&#xA;    &lt;/div&gt;&#xD;&#xA;    &lt;div class=&#34;gh-heatmap-body&#34; id=&#34;gh-heatmap-body&#34;&gt;&#xD;&#xA;      &#xD;&#xA;      &lt;div id=&#34;gh-skeleton&#34; class=&#34;gh-skeleton&#34;&gt;&#xD;&#xA;        &lt;div class=&#34;gh-skeleton-header&#34;&gt;&#xD;&#xA;          &lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&#xD;&#xA;        &lt;/div&gt;&#xD;&#xA;        &lt;div class=&#34;gh-skeleton-grid&#34;&gt;&#xD;&#xA;          &lt;div class=&#34;gh-skeleton-side&#34;&gt;&#xD;&#xA;            &lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&lt;span&gt;&lt;/span&gt;&#xD;&#xA;          &lt;/div&gt;&#xD;&#xA;          &lt;div class=&#34;gh-skeleton-cells&#34; id=&#34;gh-skel-cells&#34;&gt;&lt;/div&gt;&#xD;&#xA;        &lt;/div&gt;&#xD;&#xA;      &lt;/div&gt;&#xD;&#xA;      &lt;svg id=&#34;gh-svg&#34; class=&#34;gh-heatmap-svg&#34; preserveAspectRatio=&#34;xMidYMid meet&#34; style=&#34;opacity:0&#34;&gt;&lt;/svg&gt;&#xD;&#xA;    &lt;/div&gt;&#xD;&#xA;    &lt;div class=&#34;gh-heatmap-footer&#34;&gt;&#xD;&#xA;      &lt;div class=&#34;gh-heatmap-legend&#34;&gt;&#xD;&#xA;        &lt;span&gt;少&lt;/span&gt;&#xD;&#xA;        &lt;div class=&#34;gh-legend-cell&#34; style=&#34;--o:0.05&#34;&gt;&lt;/div&gt;&#xD;&#xA;        &lt;div class=&#34;gh-legend-cell&#34; style=&#34;--o:0.25&#34;&gt;&lt;/div&gt;&#xD;&#xA;        &lt;div class=&#34;gh-legend-cell&#34; style=&#34;--o:0.5&#34;&gt;&lt;/div&gt;&#xD;&#xA;        &lt;div class=&#34;gh-legend-cell&#34; style=&#34;--o:0.75&#34;&gt;&lt;/div&gt;&#xD;&#xA;        &lt;div class=&#34;gh-legend-cell&#34; style=&#34;--o:1&#34;&gt;&lt;/div&gt;&#xD;&#xA;        &lt;span&gt;多&lt;/span&gt;&#xD;&#xA;      &lt;/div&gt;&#xD;&#xA;    &lt;/div&gt;&#xD;&#xA;  &lt;/div&gt;&#xD;&#xA;  &lt;div id=&#34;gh-tooltip&#34; class=&#34;gh-tooltip&#34;&gt;&#xD;&#xA;    &lt;div class=&#34;gh-tooltip__arrow&#34;&gt;&lt;/div&gt;&#xD;&#xA;    &lt;div class=&#34;gh-tooltip__body&#34;&gt;&lt;/div&gt;&#xD;&#xA;  &lt;/div&gt;&#xD;&#xA;&lt;/div&gt;&#xD;&#xA;&#xD;&#xA;&lt;style&gt;&#xD;&#xA;  .gh-heatmap-wrap { position: relative; margin: 20px 0; }&#xD;&#xA;&#xD;&#xA;  .gh-heatmap-card {&#xD;&#xA;    background: rgba(255,255,255,0.7);&#xD;&#xA;    backdrop-filter: blur(10px);&#xD;&#xA;    -webkit-backdrop-filter: blur(10px);&#xD;&#xA;    border: 1px solid rgba(0,0,0,0.08);&#xD;&#xA;    border-radius: 16px;&#xD;&#xA;    padding: 14px 18px;&#xD;&#xA;    box-shadow: 0 8px 32px rgba(0,0,0,0.08);&#xD;&#xA;  }&#xD;&#xA;  [data-color-mode=&#34;dark&#34;] .gh-heatmap-card {&#xD;&#xA;    background: rgba(17,24,39,0.96);&#xD;&#xA;    border-color: rgba(148,163,184,0.25);&#xD;&#xA;    box-shadow: 0 10px 32px rgba(0,0,0,0.65);&#xD;&#xA;  }&#xD;&#xA;&#xD;&#xA;  .gh-heatmap-header {&#xD;&#xA;    display: flex; align-items: baseline;&#xD;&#xA;    justify-content: space-between;&#xD;&#xA;    margin-bottom: 8px; gap: 10px;&#xD;&#xA;  }&#xD;&#xA;  .gh-heatmap-title {&#xD;&#xA;    font-size: 1.1rem; font-weight: 600;&#xD;&#xA;    margin: 0; color: inherit; letter-spacing: 0.5px;&#xD;&#xA;  }&#xD;&#xA;  .gh-heatmap-stats {&#xD;&#xA;    font-size: 0.8rem; color: inherit;&#xD;&#xA;    opacity: 0.6; white-space: nowrap;&#xD;&#xA;  }&#xD;&#xA;  .gh-heatmap-stats strong {&#xD;&#xA;    color: #239a3b; font-weight: 700; opacity: 1;&#xD;&#xA;  }&#xD;&#xA;&#xD;&#xA;  .gh-heatmap-body {&#xD;&#xA;  overflow-x: auto; overflow-y: hidden;&#xD;&#xA;  margin: 0 -12px; padding: 0 12px;&#xD;&#xA;  position: relative;&#xD;&#xA;  height: 110px; &#xD;&#xA;}&#xD;&#xA;.gh-heatmap-svg {&#xD;&#xA;  width: 100%; height: auto;&#xD;&#xA;  display: block;&#xD;&#xA;  transition: opacity 0.4s ease;&#xD;&#xA;  position: relative;&#xD;&#xA;}&#xD;&#xA;&#xD;&#xA;.gh-skeleton {&#xD;&#xA;  position: absolute;&#xD;&#xA;  top: 0; left: 40px; right: 40px;&#xD;&#xA;  transition: opacity 0.3s ease;&#xD;&#xA;}&#xD;&#xA;&#xD;&#xA;  .gh-skeleton-header {&#xD;&#xA;    display: flex; gap: 14px;&#xD;&#xA;    margin-bottom: 4px; padding: 4px 0 2px 0;&#xD;&#xA;  }&#xD;&#xA;  .gh-skeleton-header span {&#xD;&#xA;    width: 28px; height: 10px; border-radius: 3px;&#xD;&#xA;    background: currentColor; opacity: 0.08;&#xD;&#xA;    animation: ghPulse 1.5s ease-in-out infinite;&#xD;&#xA;    flex-shrink: 0;&#xD;&#xA;  }&#xD;&#xA;  .gh-skeleton-header span:nth-child(2) { animation-delay: 0.1s; }&#xD;&#xA;  .gh-skeleton-header span:nth-child(3) { animation-delay: 0.2s; }&#xD;&#xA;  .gh-skeleton-header span:nth-child(4) { animation-delay: 0.3s; }&#xD;&#xA;  .gh-skeleton-header span:nth-child(5) { animation-delay: 0.4s; }&#xD;&#xA;  .gh-skeleton-header span:nth-child(6) { animation-delay: 0.5s; }&#xD;&#xA;&#xD;&#xA;  .gh-skeleton-grid {&#xD;&#xA;    display: flex; gap: 3px;&#xD;&#xA;  }&#xD;&#xA;  .gh-skeleton-side {&#xD;&#xA;    display: flex; flex-direction: column; gap: 3px;&#xD;&#xA;    flex-shrink: 0; margin-left: -28px;&#xD;&#xA;  }&#xD;&#xA;  .gh-skeleton-side span {&#xD;&#xA;    width: 24px; height: 11px; border-radius: 2px;&#xD;&#xA;    background: currentColor; opacity: 0.06;&#xD;&#xA;    animation: ghPulse 1.5s ease-in-out infinite;&#xD;&#xA;    flex-shrink: 0;&#xD;&#xA;  }&#xD;&#xA;  .gh-skeleton-side span:nth-child(odd) { opacity: 0; }&#xD;&#xA;&#xD;&#xA;  .gh-skeleton-cells {&#xD;&#xA;    flex: 1;&#xD;&#xA;    display: grid;&#xD;&#xA;    grid-template-columns: repeat(53, 11px);&#xD;&#xA;    grid-template-rows: repeat(7, 11px);&#xD;&#xA;    gap: 3px;&#xD;&#xA;  }&#xD;&#xA;  .gh-skel-cell {&#xD;&#xA;    width: 11px; height: 11px; border-radius: 2px;&#xD;&#xA;    background: currentColor; opacity: 0.06;&#xD;&#xA;    animation: ghPulse 1.5s ease-in-out infinite;&#xD;&#xA;  }&#xD;&#xA;&#xD;&#xA;   &#xD;&#xA;  @media (max-width: 640px) {&#xD;&#xA;    .gh-skeleton-cells {&#xD;&#xA;      grid-template-rows: repeat(14, 11px);&#xD;&#xA;    }&#xD;&#xA;    .gh-skeleton-side {&#xD;&#xA;       &#xD;&#xA;    }&#xD;&#xA;    .gh-skeleton-side span {&#xD;&#xA;      display: block;&#xD;&#xA;    }&#xD;&#xA;    .gh-skeleton-side span:nth-child(odd) {&#xD;&#xA;      display: none;&#xD;&#xA;    }&#xD;&#xA;  }&#xD;&#xA;&#xD;&#xA;  @keyframes ghPulse {&#xD;&#xA;    0%, 100% { opacity: 0.06; }&#xD;&#xA;    50%      { opacity: 0.14; }&#xD;&#xA;  }&#xD;&#xA;&#xD;&#xA;  .gh-skeleton.hidden {&#xD;&#xA;    opacity: 0;&#xD;&#xA;    pointer-events: none;&#xD;&#xA;  }&#xD;&#xA;&#xD;&#xA;   &#xD;&#xA;  .gh-heatmap-footer { display: flex; justify-content: flex-end; margin-top: 10px; }&#xD;&#xA;  .gh-heatmap-legend {&#xD;&#xA;    display: flex; align-items: center;&#xD;&#xA;    gap: 5px; font-size: 0.75rem; color: inherit; opacity: 0.6;&#xD;&#xA;  }&#xD;&#xA;  .gh-legend-cell {&#xD;&#xA;    width: 11px; height: 11px; border-radius: 2px;&#xD;&#xA;    background: #239a3b; opacity: var(--o); flex-shrink: 0;&#xD;&#xA;  }&#xD;&#xA;&#xD;&#xA;   &#xD;&#xA;  .gh-tooltip {&#xD;&#xA;    position: fixed; pointer-events: none;&#xD;&#xA;    z-index: 1000; display: none;&#xD;&#xA;  }&#xD;&#xA;  .gh-tooltip.show { display: block; }&#xD;&#xA;  .gh-tooltip__body {&#xD;&#xA;    background: rgba(30,30,30,0.95); backdrop-filter: blur(12px);&#xD;&#xA;    border-radius: 8px; padding: 8px 12px;&#xD;&#xA;    font-size: 0.75rem; font-weight: 500; color: #fff;&#xD;&#xA;    white-space: nowrap; box-shadow: 0 4px 16px rgba(0,0,0,0.25);&#xD;&#xA;    position: relative;&#xD;&#xA;  }&#xD;&#xA;  [data-color-mode=&#34;dark&#34;] .gh-tooltip__body {&#xD;&#xA;    background: rgba(17,24,39,0.95);&#xD;&#xA;  }&#xD;&#xA;&#xD;&#xA;  .gh-tooltip__arrow {&#xD;&#xA;    position: absolute; left: 50%;&#xD;&#xA;    width: 0; height: 0; border-style: solid;&#xD;&#xA;    transform: translateX(-50%);&#xD;&#xA;  }&#xD;&#xA;&#xD;&#xA;  .gh-tooltip.above .gh-tooltip__arrow {&#xD;&#xA;    top: 100%;&#xD;&#xA;    border-width: 6px 6px 0 6px;&#xD;&#xA;    border-color: rgba(30,30,30,0.95) transparent transparent transparent;&#xD;&#xA;    margin-top: -1px;&#xD;&#xA;  }&#xD;&#xA;  [data-color-mode=&#34;dark&#34;] .gh-tooltip.above .gh-tooltip__arrow {&#xD;&#xA;    border-color: rgba(17,24,39,0.95) transparent transparent transparent;&#xD;&#xA;  }&#xD;&#xA;&#xD;&#xA;  .gh-tooltip.below .gh-tooltip__arrow {&#xD;&#xA;    bottom: 100%;&#xD;&#xA;    border-width: 0 6px 6px 6px;&#xD;&#xA;    border-color: transparent transparent rgba(30,30,30,0.95) transparent;&#xD;&#xA;    margin-bottom: -1px;&#xD;&#xA;  }&#xD;&#xA;  [data-color-mode=&#34;dark&#34;] .gh-tooltip.below .gh-tooltip__arrow {&#xD;&#xA;    border-color: transparent transparent rgba(17,24,39,0.95) transparent;&#xD;&#xA;  }&#xD;&#xA;&#xD;&#xA;  .gh-tooltip.above.show { animation: ghFadeIn 150ms ease-out; }&#xD;&#xA;  .gh-tooltip.below.show { animation: ghFadeInBelow 150ms ease-out; }&#xD;&#xA;&#xD;&#xA;  @keyframes ghFadeIn {&#xD;&#xA;    from { opacity: 0; transform: translateY(-4px); }&#xD;&#xA;    to   { opacity: 1; transform: translateY(0); }&#xD;&#xA;  }&#xD;&#xA;  @keyframes ghFadeInBelow {&#xD;&#xA;    from { opacity: 0; transform: translateY(4px); }&#xD;&#xA;    to   { opacity: 1; transform: translateY(0); }&#xD;&#xA;  }&#xD;&#xA;&#xD;&#xA;  .heatmap-cell {&#xD;&#xA;    transition: opacity 150ms, filter 150ms;&#xD;&#xA;    cursor: default;&#xD;&#xA;  }&#xD;&#xA;  .heatmap-cell:hover {&#xD;&#xA;    opacity: 1 !important;&#xD;&#xA;    filter: drop-shadow(0 2px 6px rgba(35,154,59,0.4));&#xD;&#xA;  }&#xD;&#xA;&lt;/style&gt;&#xD;&#xA;&#xD;&#xA;&lt;script&gt;&#xD;&#xA;(function () {&#xD;&#xA;  &#39;use strict&#39;;&#xD;&#xA;&#xD;&#xA;  const NS = &#39;http://www.w3.org/2000/svg&#39;;&#xD;&#xA;  const CELL = 11, GAP = 3;&#xD;&#xA;  const LEVEL_OPACITY = [0.05, 0.25, 0.5, 0.75, 1.0];&#xD;&#xA;  const MONTHS = [&#39;Jan&#39;,&#39;Feb&#39;,&#39;Mar&#39;,&#39;Apr&#39;,&#39;May&#39;,&#39;Jun&#39;,&#39;Jul&#39;,&#39;Aug&#39;,&#39;Sep&#39;,&#39;Oct&#39;,&#39;Nov&#39;,&#39;Dec&#39;];&#xD;&#xA;  const DAYS_7  = [&#39;&#39;, &#39;Mon&#39;, &#39;&#39;, &#39;Wed&#39;, &#39;&#39;, &#39;Fri&#39;, &#39;&#39;];&#xD;&#xA;  const DAYS_14 = [&#39;&#39;, &#39;Mon&#39;, &#39;&#39;, &#39;Tue&#39;, &#39;&#39;, &#39;Wed&#39;, &#39;&#39;, &#39;Thu&#39;, &#39;&#39;, &#39;Fri&#39;, &#39;&#39;, &#39;Sat&#39;, &#39;&#39;, &#39;Sun&#39;];&#xD;&#xA;  const LABEL_OFFSET = 28, HEADER_OFFSET = 16;&#xD;&#xA;  const MOBILE_BREAKPOINT = 640;&#xD;&#xA;&#xD;&#xA;  const svg = document.getElementById(&#39;gh-svg&#39;);&#xD;&#xA;  const statsCount = document.getElementById(&#39;gh-stats-count&#39;);&#xD;&#xA;  const tooltip = document.getElementById(&#39;gh-tooltip&#39;);&#xD;&#xA;  const tooltipBody = tooltip.querySelector(&#39;.gh-tooltip__body&#39;);&#xD;&#xA;  const tooltipArrow = tooltip.querySelector(&#39;.gh-tooltip__arrow&#39;);&#xD;&#xA;  const skeleton = document.getElementById(&#39;gh-skeleton&#39;);&#xD;&#xA;  const skelCells = document.getElementById(&#39;gh-skel-cells&#39;);&#xD;&#xA;&#xD;&#xA;  let contributions = [];&#xD;&#xA;  let dataLoaded = false;&#xD;&#xA;&#xD;&#xA;  &#xD;&#xA;  function buildSkeletonCells() {&#xD;&#xA;    skelCells.innerHTML = &#39;&#39;;&#xD;&#xA;    const rows = getRows();&#xD;&#xA;    &#xD;&#xA;    const cols = rows === 14 ? 27 : 53;&#xD;&#xA;    skelCells.style.gridTemplateRows = `repeat(${rows}, 11px)`;&#xD;&#xA;    skelCells.style.gridTemplateColumns = `repeat(${cols}, 11px)`;&#xD;&#xA;    for (let i = 0; i &lt; cols * rows; i++) {&#xD;&#xA;      const d = document.createElement(&#39;div&#39;);&#xD;&#xA;      d.className = &#39;gh-skel-cell&#39;;&#xD;&#xA;      d.style.animationDelay = (Math.random() * 1.5).toFixed(2) + &#39;s&#39;;&#xD;&#xA;      skelCells.appendChild(d);&#xD;&#xA;    }&#xD;&#xA;  }&#xD;&#xA;&#xD;&#xA;  &#xD;&#xA;  function buildSkeletonSide() {&#xD;&#xA;    const side = skeleton.querySelector(&#39;.gh-skeleton-side&#39;);&#xD;&#xA;    side.innerHTML = &#39;&#39;;&#xD;&#xA;    const rows = getRows();&#xD;&#xA;    for (let i = 0; i &lt; rows; i++) {&#xD;&#xA;      const span = document.createElement(&#39;span&#39;);&#xD;&#xA;      &#xD;&#xA;      if (i % 2 === 0) {&#xD;&#xA;        span.style.opacity = &#39;0&#39;;&#xD;&#xA;        span.style.height = &#39;11px&#39;;&#xD;&#xA;      }&#xD;&#xA;      side.appendChild(span);&#xD;&#xA;    }&#xD;&#xA;  }&#xD;&#xA;&#xD;&#xA;  buildSkeletonSide();&#xD;&#xA;  buildSkeletonCells();&#xD;&#xA;&#xD;&#xA;  function isDark() {&#xD;&#xA;    return document.documentElement.getAttribute(&#39;data-color-mode&#39;) === &#39;dark&#39;;&#xD;&#xA;  }&#xD;&#xA;  function labelColor() {&#xD;&#xA;    return isDark() ? &#39;rgba(255,255,255,0.55)&#39; : &#39;rgba(0,0,0,0.4)&#39;;&#xD;&#xA;  }&#xD;&#xA;  function cellColor(level) {&#xD;&#xA;    return `rgba(35,154,59,${LEVEL_OPACITY[Math.min(level, 4)]})`;&#xD;&#xA;  }&#xD;&#xA;&#xD;&#xA;  function getRows() {&#xD;&#xA;    return window.innerWidth &lt;= MOBILE_BREAKPOINT ? 14 : 7;&#xD;&#xA;  }&#xD;&#xA;  function getDays() {&#xD;&#xA;    return getRows() === 14 ? DAYS_14 : DAYS_7;&#xD;&#xA;  }&#xD;&#xA;  function weeks() {&#xD;&#xA;    return Math.ceil(contributions.length / getRows());&#xD;&#xA;  }&#xD;&#xA;  function svgSize() {&#xD;&#xA;    return {&#xD;&#xA;      w: LABEL_OFFSET + weeks() * (CELL + GAP),&#xD;&#xA;      h: HEADER_OFFSET + getRows() * (CELL + GAP),&#xD;&#xA;    };&#xD;&#xA;  }&#xD;&#xA;&#xD;&#xA;  async function fetchData(retries = 3) {&#xD;&#xA;    const controller = new AbortController();&#xD;&#xA;    const timeout = setTimeout(() =&gt; controller.abort(), 8000);&#xD;&#xA;    try {&#xD;&#xA;      const res = await fetch(&#xD;&#xA;        `https://github-contributions-api.jogruber.de/v4/full-finger?y=last`,&#xD;&#xA;        { signal: controller.signal }&#xD;&#xA;      );&#xD;&#xA;      clearTimeout(timeout);&#xD;&#xA;      if (!res.ok) throw new Error(res.status);&#xD;&#xA;      return res.json();&#xD;&#xA;    } catch (e) {&#xD;&#xA;      clearTimeout(timeout);&#xD;&#xA;      if (retries &gt; 0) {&#xD;&#xA;        await new Promise(r =&gt; setTimeout(r, 2000));&#xD;&#xA;        return fetchData(retries - 1);&#xD;&#xA;      }&#xD;&#xA;      throw e;&#xD;&#xA;    }&#xD;&#xA;  }&#xD;&#xA;&#xD;&#xA;  function buildMonthLabels() {&#xD;&#xA;    const rows = getRows();&#xD;&#xA;    const labels = [];&#xD;&#xA;    let last = -1;&#xD;&#xA;    for (let w = 0; w &lt; weeks(); w++) {&#xD;&#xA;      const idx = w * rows;&#xD;&#xA;      if (idx &gt;= contributions.length) break;&#xD;&#xA;      const m = new Date(contributions[idx].date).getMonth();&#xD;&#xA;      if (m !== last) {&#xD;&#xA;        labels.push({ text: MONTHS[m], x: LABEL_OFFSET + w * (CELL + GAP) });&#xD;&#xA;        last = m;&#xD;&#xA;      }&#xD;&#xA;    }&#xD;&#xA;    if (labels.length &gt;= 2 &amp;&amp; labels[1].x - labels[0].x &lt; 40) {&#xD;&#xA;      labels.shift();&#xD;&#xA;    }&#xD;&#xA;    return labels;&#xD;&#xA;  }&#xD;&#xA;&#xD;&#xA;  function render() {&#xD;&#xA;    if (!dataLoaded || contributions.length === 0) return;&#xD;&#xA;&#xD;&#xA;    const rows = getRows();&#xD;&#xA;    const days = getDays();&#xD;&#xA;    const { w, h } = svgSize();&#xD;&#xA;    svg.setAttribute(&#39;viewBox&#39;, `0 0 ${w} ${h}`);&#xD;&#xA;    svg.innerHTML = &#39;&#39;;&#xD;&#xA;&#xD;&#xA;    const bodyEl = document.getElementById(&#39;gh-heatmap-body&#39;);&#xD;&#xA;    bodyEl.style.height = h + &#39;px&#39;;&#xD;&#xA;&#xD;&#xA;    const fill = labelColor();&#xD;&#xA;&#xD;&#xA;    buildMonthLabels().forEach(({ text, x }) =&gt; {&#xD;&#xA;      const el = document.createElementNS(NS, &#39;text&#39;);&#xD;&#xA;      el.setAttribute(&#39;x&#39;, x);&#xD;&#xA;      el.setAttribute(&#39;y&#39;, 11);&#xD;&#xA;      el.setAttribute(&#39;font-size&#39;, 10);&#xD;&#xA;      el.setAttribute(&#39;fill&#39;, fill);&#xD;&#xA;      el.textContent = text;&#xD;&#xA;      svg.appendChild(el);&#xD;&#xA;    });&#xD;&#xA;&#xD;&#xA;    days.forEach((d, i) =&gt; {&#xD;&#xA;      if (!d) return;&#xD;&#xA;      const el = document.createElementNS(NS, &#39;text&#39;);&#xD;&#xA;      el.setAttribute(&#39;x&#39;, 0);&#xD;&#xA;      el.setAttribute(&#39;y&#39;, HEADER_OFFSET + i * (CELL + GAP) + CELL - 1);&#xD;&#xA;      el.setAttribute(&#39;font-size&#39;, 9);&#xD;&#xA;      el.setAttribute(&#39;fill&#39;, fill);&#xD;&#xA;      el.textContent = d;&#xD;&#xA;      svg.appendChild(el);&#xD;&#xA;    });&#xD;&#xA;&#xD;&#xA;    contributions.forEach((day, idx) =&gt; {&#xD;&#xA;      const col = Math.floor(idx / rows);&#xD;&#xA;      const row = idx % rows;&#xD;&#xA;      const rect = document.createElementNS(NS, &#39;rect&#39;);&#xD;&#xA;      rect.setAttribute(&#39;x&#39;, LABEL_OFFSET + col * (CELL + GAP));&#xD;&#xA;      rect.setAttribute(&#39;y&#39;, HEADER_OFFSET + row * (CELL + GAP));&#xD;&#xA;      rect.setAttribute(&#39;width&#39;, CELL);&#xD;&#xA;      rect.setAttribute(&#39;height&#39;, CELL);&#xD;&#xA;      rect.setAttribute(&#39;rx&#39;, 2);&#xD;&#xA;      rect.setAttribute(&#39;ry&#39;, 2);&#xD;&#xA;      rect.setAttribute(&#39;class&#39;, &#39;heatmap-cell&#39;);&#xD;&#xA;      rect.setAttribute(&#39;fill&#39;, cellColor(day.level));&#xD;&#xA;      rect.dataset.date = day.date;&#xD;&#xA;      rect.dataset.count = day.count;&#xD;&#xA;      svg.appendChild(rect);&#xD;&#xA;    });&#xD;&#xA;  }&#xD;&#xA;&#xD;&#xA;  &#xD;&#xA;  function transitionIn() {&#xD;&#xA;    skeleton.classList.add(&#39;hidden&#39;);&#xD;&#xA;    setTimeout(() =&gt; {&#xD;&#xA;      skeleton.style.display = &#39;none&#39;;&#xD;&#xA;      svg.style.opacity = &#39;1&#39;;&#xD;&#xA;    }, 300);&#xD;&#xA;  }&#xD;&#xA;&#xD;&#xA;  function formatDate(str) {&#xD;&#xA;    const d = new Date(str);&#xD;&#xA;    return `${d.getFullYear()}年${d.getMonth() + 1}月${d.getDate()}日`;&#xD;&#xA;  }&#xD;&#xA;&#xD;&#xA;  function showTooltip(e) {&#xD;&#xA;    const rect = e.target;&#xD;&#xA;    if (!rect.dataset.date) return;&#xD;&#xA;    const count = parseInt(rect.dataset.count, 10);&#xD;&#xA;    tooltipBody.textContent = count &gt; 0&#xD;&#xA;      ? `${formatDate(rect.dataset.date)}: ${count} 次贡献`&#xD;&#xA;      : `${formatDate(rect.dataset.date)}: 无贡献`;&#xD;&#xA;    tooltip.classList.add(&#39;show&#39;);&#xD;&#xA;    const cellRect = rect.getBoundingClientRect();&#xD;&#xA;    const tipRect = tooltip.getBoundingClientRect();&#xD;&#xA;    const gap = 8, margin = 8;&#xD;&#xA;    let x = cellRect.left + cellRect.width / 2 - tipRect.width / 2;&#xD;&#xA;    let y = cellRect.top - tipRect.height - gap;&#xD;&#xA;    let above = true;&#xD;&#xA;    x = Math.max(margin, Math.min(x, window.innerWidth - tipRect.width - margin));&#xD;&#xA;    if (y &lt; margin) {&#xD;&#xA;      y = cellRect.bottom + gap;&#xD;&#xA;      above = false;&#xD;&#xA;    }&#xD;&#xA;    tooltip.style.left = x + &#39;px&#39;;&#xD;&#xA;    tooltip.style.top = y + &#39;px&#39;;&#xD;&#xA;    tooltip.classList.toggle(&#39;above&#39;, above);&#xD;&#xA;    tooltip.classList.toggle(&#39;below&#39;, !above);&#xD;&#xA;    const arrowX = cellRect.left + cellRect.width / 2 - x;&#xD;&#xA;    tooltipArrow.style.left = arrowX + &#39;px&#39;;&#xD;&#xA;  }&#xD;&#xA;&#xD;&#xA;  function hideTooltip() {&#xD;&#xA;    tooltip.classList.remove(&#39;show&#39;);&#xD;&#xA;  }&#xD;&#xA;&#xD;&#xA;  svg.addEventListener(&#39;mouseover&#39;, (e) =&gt; {&#xD;&#xA;    if (e.target.classList.contains(&#39;heatmap-cell&#39;)) showTooltip(e);&#xD;&#xA;  });&#xD;&#xA;  svg.addEventListener(&#39;mouseout&#39;, (e) =&gt; {&#xD;&#xA;    if (e.target.classList.contains(&#39;heatmap-cell&#39;)) hideTooltip(e);&#xD;&#xA;  });&#xD;&#xA;&#xD;&#xA;  new MutationObserver(render).observe(document.documentElement, {&#xD;&#xA;    attributes: true,&#xD;&#xA;    attributeFilter: [&#39;data-color-mode&#39;],&#xD;&#xA;  });&#xD;&#xA;&#xD;&#xA;  let lastRows = getRows();&#xD;&#xA;  window.addEventListener(&#39;resize&#39;, () =&gt; {&#xD;&#xA;    const current = getRows();&#xD;&#xA;    if (current !== lastRows) {&#xD;&#xA;      lastRows = current;&#xD;&#xA;      &#xD;&#xA;      if (!dataLoaded) {&#xD;&#xA;        buildSkeletonCells();&#xD;&#xA;        buildSkeletonSide();&#xD;&#xA;      }&#xD;&#xA;      render();&#xD;&#xA;    }&#xD;&#xA;  });&#xD;&#xA;&#xD;&#xA;  fetchData()&#xD;&#xA;    .then((data) =&gt; {&#xD;&#xA;      statsCount.textContent = data.total.lastYear;&#xD;&#xA;      contributions = data.contributions;&#xD;&#xA;      dataLoaded = true;&#xD;&#xA;      render();&#xD;&#xA;      transitionIn();&#xD;&#xA;    })&#xD;&#xA;    .catch(() =&gt; {&#xD;&#xA;      statsCount.textContent = &#39;加载失败&#39;;&#xD;&#xA;      skeleton.classList.add(&#39;hidden&#39;);&#xD;&#xA;      setTimeout(() =&gt; { skeleton.style.display = &#39;none&#39;; }, 300);&#xD;&#xA;    });&#xD;&#xA;&#xD;&#xA;})();&#xD;&#xA;&lt;/script&gt;&#xD;&#xA;&#xA;&lt;p&gt;19岁，是学生&lt;/p&gt;</description>
    </item>
  </channel>
</rss>
