diff options
Diffstat (limited to 'content')
-rw-r--r-- | content/about/contact.md | 4 | ||||
-rw-r--r-- | content/about/rss.md | 7 | ||||
-rw-r--r-- | content/book-reviews/tous-les-hommes-sont-mortels.fr.md | 55 | ||||
-rw-r--r-- | content/cal/_index.html | 68 | ||||
-rw-r--r-- | content/cal/lunar.js | 522 | ||||
-rw-r--r-- | content/misc/books.md | 2 | ||||
-rw-r--r-- | content/posts/2025-02-23-last-post.md | 67 | ||||
-rw-r--r-- | content/sw-notes/ssh-timeout.md | 20 |
8 files changed, 737 insertions, 8 deletions
diff --git a/content/about/contact.md b/content/about/contact.md index f4312fa..23686d5 100644 --- a/content/about/contact.md +++ b/content/about/contact.md @@ -12,6 +12,10 @@ work, contact my [professional email][work-mail]. If you are or want to be a friend, contact my [personal email][perso-mail]. If in doubt, use the first one. +**WARNING**: As of 2025-04-20, loang.net's mail server is *not* working properly. +I can receive, but not send email from there. +Please direct your email to the disroot one instead. + [work-mail]: mailto:huyngo@disroot.org [perso-mail]: mailto:xarvos@loang.net diff --git a/content/about/rss.md b/content/about/rss.md index 7633059..1246751 100644 --- a/content/about/rss.md +++ b/content/about/rss.md @@ -22,13 +22,6 @@ feeds here: - [German](/de/posts/index.xml) - [Vietnamese](/vi/posts/index.xml) -## TIL (Today I learned) - -- [English](/en/til/index.xml) -- [French](/fr/til/index.xml) -- [German](/de/til/index.xml) -- [Vietnamese](/vi/til/index.xml) - ## Book reviews - [English](/en/book-reviews/index.xml) diff --git a/content/book-reviews/tous-les-hommes-sont-mortels.fr.md b/content/book-reviews/tous-les-hommes-sont-mortels.fr.md new file mode 100644 index 0000000..1ccf02e --- /dev/null +++ b/content/book-reviews/tous-les-hommes-sont-mortels.fr.md @@ -0,0 +1,55 @@ +--- +categories: ["book review"] +title: "Tous les hommes sont mortels" +date: 2025-02-08 +tags: [existentialisme] +isbn: 9782700232707 +book: "Tous les hommes sont mortels" +authors: + - Simone de Beauvoir +genres: + - philosophie +lang: fr +layout: books +--- + +## Commentaires + +J'ai lit ce livre avec si beaucoup de pauses longues que je le trouve difficile +à se souvenir tous les détails. Ce n'est pas qu'il est trop difficile à lire +ou ennuyeux, c'était toute ma faute. En tout cas, c'est un livre qui pose des +questions intéressantes des conditions humaines, la vie et la mort, et surtout +dans une manière approchable. En voyant l'ennui de l'homme qui abandonna le +monde des mortels, on trouve notre voie, on apprend qu'est-ce que c'est un +homme mortel. + +## Sommaire (spoiler) + +C'est des histoires de Fosca Raymond, qui fut né au 15e siècle. Comme un des +dirigeants, il chercha le pouvoir, et il accepta un offre de l'immortalité, +qui, selon lui au moment, lui donna la chance de gagner contre ses ennemis. +Mais il expériença bientôt la première malédiction de l'immortalité : la mort +de ceux qu'il aime. Quoi qu'il fasse, il ne puisse pas les sauver de leur +destin. Ils moururent de la plague, dans la guèrre, ou de vieillesse. +C'est pire, ceux qu'il aimait, ils le déteste. Ils le déteste pour saisir +d'eux leurs choix, leur liberté. Il pensa qu'il les protégeait de la mort, +mais comme résultat il ne les laissait vivre. + +Un peu siècles plus tard, Fosca accepta le fait qu'il ne peux pas vaincre le +monde malgré son immortalité. Il essaya rentre parmi les mortels. Et il +réalisa qu'il ne le puisse plus faire : il n'était plus un homme. Un homme vit +et meurt. Lui, il ne fasse ni les deux. Il ne puisse plus percevoir le monde +comme un homme, il ne puisse plus comprendre ce que les autres voulurent, et il +est tout seul parmi les mortels. + +Il ne voyait pas pourquoi les hommes luttait. Ils ne achevera jamais l'idéal. +Et quand on gagne, on va simplement exiger pour de plus. Mais c'est être un +homme mortel : on lutte pour le présent. Pour toujours, on est vainqueurs; +demain, on continuera lutter. + +Régine le rencontra et elle voulait l'aimer et être aimée par lui. Elle rêvait +de vivre pour toujours dans son mémoir. Mais elle n'était pas sa première. +Fosca a aimé une femme, Marianne, si beaucoup il essayait de conserver sa +mémoir à l'avenir. Mais elle était dans le passé. Elle ne vit dans le +présent. Il ne peut pas la prendre avec lui. Elle va enfin s'évanouir dans le +passé. diff --git a/content/cal/_index.html b/content/cal/_index.html new file mode 100644 index 0000000..9bbb4fd --- /dev/null +++ b/content/cal/_index.html @@ -0,0 +1,68 @@ +--- +title: Calendar +disable_feed: true +--- + +<noscript> + This calendar works locally in your browser and requires JavaScript to remain serverless +</noscript> +<div> + <label> + Solar date: + <input id="solar-date" type="date" /> + </label> + <button id="nav-today">Today</button> +</div> +<div id="lunar-solar-cal"> + <div id="solar-cal"> + <div id="month-year-row"> + <div id="solar-month-vi" lang=vi></div> + <div id="solar-year"></div> + <div id="solar-month-en"></div> + </div> + <hr> + <div id="day-area" lang=vi> + <button id="nav-day-before"> + <span class="sr-only">Ngày trước</span> + </button> + <div> + <div id="solar-day"></div> + <div id="special-day-vi"></div> + </div> + <button id="nav-day-after"> + <span class="sr-only">Ngày tiếp theo</span> + </button> + </div> + <hr> + <div id="weekday-row"> + <div id="solar-weekday-en"></div> + <div id="solar-weekday-vi" lang=vi></div> + <div id="solar-weekday-zh" lang=zh></div> + </div> + </div> + <hr> + <div id="lunar-cal"> + <div id=lunar-cal-vi lang="vi"> + <div id="lunar-year-vi"></div> + <div id="lunar-month-vi"></div> + <div id="lunar-month-zodiac-vi"></div> + <div id="lunar-day-zodiac-vi"></div> + <div id="solar-term-vi"></div> + </div> + <div id="lunar-day"></div> + <div id=lunar-cal-zh lang="zh"> + <div id="lunar-year-zh"></div> + <div> + <span id="lunar-month-zh"></span> · + <span id="lunar-month-zodiac-zh"></span> + </div> + <div id="lunar-day-zh"></div> + <div id="lunar-day-zodiac-zh"></div> + <div> + <span id="solar-term-zh"></span> + <span id="special-day-zh"></span> + </div> + </div> + </div> +</div> +<script src="lunar.js"></script> diff --git a/content/cal/lunar.js b/content/cal/lunar.js new file mode 100644 index 0000000..4ab5e26 --- /dev/null +++ b/content/cal/lunar.js @@ -0,0 +1,522 @@ +// Part 1: Converter functions + +// Sin function with degree instead of radian +function sind(degree) { + return Math.sin(degree * Math.PI / 180) +} + +// Convert Gregorian date to Julian day +function getJulianDay(date) { + const year = date.getFullYear() + const month = date.getMonth() + 1 + const day = date.getDate() + + let a = parseInt((14 - month) / 12) + let y = year + 4800 - a + y = y * 365 + parseInt(y / 4) - parseInt(y / 100) + parseInt(y / 400) + let m = month + 12 * a - 3 + return parseInt(day + (153 * m + 2) / 5) + y - 32045 +} + +// Convert Julian day to Gregorian date +function getDateFromJulianDay(jd) { + const a = jd + 32044 + const b = parseInt((4 * a + 3) / 146097) + const c = a - parseInt((b * 146097) / 4) + const d = parseInt((4 * c + 3) / 1461) + const e = c - parseInt((1461 * d) / 4) + const m = parseInt((5 * e + 2) / 153) + const dd = e - parseInt((153 * m + 2) / 5) + 1 + const mm = m + 2 - 12 * parseInt(m / 10) + const yy = b * 100 + d - 4800 + parseInt(m / 10) + return new Date(yy, mm, dd) +} + +// Get kth new moon day since 1900-01-01 in Julian day +function getNewMoonDay(k, tzOffset) { + const t = k / 1236.85 + const t2 = t * t + const t3 = t2 * t + + let jd1 = 2415020.75933 + 29.53058868 * k + 0.0001178 * t2 - 0.000000155 * t3 + jd1 += 0.00033 * sind(166.56 + 132.87 * t - 0.009173 * t2) + + const m = 359.2242 + 29.10535608 * k - 0.0000333 * t2 - 0.00000347 * t3 + const mpr = 306.0253 + 385.81691806 * k + 0.0107306 * t2 + 0.00001236 * t3 + const f = 21.2964 + 390.67050646 * k - 0.0016528 * t2 - 0.00000239 * t3 + + let c1 = (0.1734 - 0.000393 * t) * sind(m) + 0.0021 * sind(2 * m) + c1 -= 0.4068 * sind(mpr) + 0.0161 * sind(2 * mpr) + c1 -= 0.0004 * sind(3 * mpr) + c1 += 0.0104 * sind(2 * f) - 0.0051 * sind(m + mpr) + c1 -= 0.0074 * sind(m - mpr) + 0.0004 * sind(2 * f + m) + c1 -= 0.0004 * sind(2 * f - m) - 0.0006 * sind(2 * f + mpr) + c1 += 0.0010 * sind(2 * f - mpr) + 0.0005 * sind(2 * mpr + m) + + let dt + if (t < -11) { + dt = 0.001 + 0.000839 * t + 0.0002261 * t2 - 0.00000845 * t3 - 0.000000081 * t * t3 + } else { + dt = -0.000278 + 0.000265 * t + 0.000262 * t2 + } + let jdNew = jd1 + c1 - dt + return parseInt(jdNew + 0.5 + tzOffset / 24) +} + +// Get solar term from Julian day, from 0 to 23, corresponding to Chunfen to Jingzhe. +function getSolarTerm(jd, tzOffset) { + t = (jd - 2451545.5 - tzOffset / 24) / 36525 + t2 = t * t + m = 357.52910 + 35999.05030 * t - 0.0001559 * t2 - 0.00000048 * t * t2 + l0 = 280.46645 + 36000.76983 * t + 0.0003032 * t2 + dl = (1.914600 - 0.004817 * t - 0.000014 * t2) * sind(m) + dl = dl + (0.019993 - 0.000101 * t) * sind(2 * m) + 0.000290 * sind(3 * m) + l = l0 + dl + l %= 360 // normalize to (0, 360) + return parseInt(l * 24 / 360) +} + +// Get the solar longitude of the day, from 0 to 11. +// 0 is corresponding to 0 degree to 30 degree and solar term Chunfen (spring equinox) - Guyu +// 1 is corresponding to 30 degree to 60 degree and solar term Guyu - Xiaoman +// 2 is corresponding to 60 degree to 90 degree and solar term Xiaoman - Xiazhi (summer solstince) +// etc +function getSunLongitude(jd, tzOffset) { + t = (jd - 2451545.5 - tzOffset / 24) / 36525 + t2 = t * t + m = 357.52910 + 35999.05030 * t - 0.0001559 * t2 - 0.00000048 * t * t2 + l0 = 280.46645 + 36000.76983 * t + 0.0003032 * t2 + dl = (1.914600 - 0.004817 * t - 0.000014 * t2) * sind(m) + dl = dl + (0.019993 - 0.000101 * t) * sind(2 * m) + 0.000290 * sind(3 * m) + l = l0 + dl + l %= 360 // normalize to (0, 360 deg) + return parseInt(l * 12 / 360) +} + +// Get Julian day for the first day of 11th lunar month of the year. +function getMonth11(year, tzOffset) { + off = getJulianDay(new Date(year, 11, 31)) - 2415021 + k = parseInt(off / 29.530588853) + nm = getNewMoonDay(k, tzOffset) + sun_long = getSunLongitude(nm, tzOffset) + if (sun_long >= 9) { + nm = getNewMoonDay(k-1, tzOffset) + } + return nm +} + +// Get the leap month offset from the 11th month before it. +// +// a11: Julian day of the first day of the 11th month +function getLeapMonthOffset(a11, tzOffset) { + k = parseInt((a11 - 2415021.076998695) / 29.530588853 + 0.5) + i = 1 + arc = getSunLongitude(getNewMoonDay(k + i, tzOffset), tzOffset) + last = 0 + while (arc != last && i < 14) { + last = arc + i++ + arc = getSunLongitude(getNewMoonDay(k + i, tzOffset), tzOffset) + } + return i - 1 +} + +function convertSolarToLunar(date, tzOffset) { + const jd = getJulianDay(date) + + let k = parseInt((jd - 2415021.076998695) / 29.530588853) + let monthStart = getNewMoonDay(k + 1, tzOffset) + if (monthStart > jd) { + monthStart = getNewMoonDay(k, tzOffset) + } + let a11 = getMonth11(date.getFullYear(), tzOffset) + let b11 = a11 + let lunarYear + if (a11 >= monthStart) { + lunarYear = date.getFullYear() + a11 = getMonth11(lunarYear - 1, tzOffset) + } else { + lunarYear = date.getFullYear() + 1 + b11 = getMonth11(lunarYear, tzOffset) + } + let lunarDay = jd - monthStart + 1 + let diff = parseInt((monthStart - a11) / 29) + let isLeapMonth = false + let lunarMonth = diff + 11 + if (b11 - a11 > 365) { + leapMonthDiff = getLeapMonthOffset(a11, tzOffset) + if (diff >= leapMonthDiff) { + lunarMonth = diff + 10 + if (diff == leapMonthDiff) { + isLeapMonth = true + } + } + } + if (lunarMonth > 12) { + lunarMonth -= 12 + } + if (lunarMonth >= 11 && diff < 4) { + lunarYear -= 1 + } + return { + year: lunarYear, + month: lunarMonth, + day: lunarDay, + isLeap: isLeapMonth, + jd: jd + } +} + +const CAN_VI = ['Giáp', 'Ất', 'Bính', 'Đinh', 'Mậu', 'Kỷ', 'Canh', 'Tân', 'Nhâm', 'Quý'] +const CAN_ZH = ['甲', '乙', '丙', '丁', '戊', '己', '庚', '辛', '壬', '癸'] +const CHI_VI = ['Tý', 'Sửu', 'Dần', 'Mão', 'Thìn', 'Tỵ', 'Ngọ', 'Mùi', 'Thân', 'Dậu', 'Tuất', 'Hợi'] +const CHI_ZH = ['子', '丑', '寅', '卯', '辰', '巳', '午', '未', '申', '酉', '戌', '亥'] +const TERM_VI = [ + 'Xuân phân', + 'Thanh minh', + 'Cốc vũ', + 'Lập hạ', + 'Tiểu mãn', + 'Mang chủng', + 'Hạ chí', + 'Tiểu thử', + 'Đại thử', + 'Lập thu', + 'Xử thử', + 'Bạch lộ', + 'Thu phân', + 'Hàn lộ', + 'Sương giáng', + 'Lập đông', + 'Tiểu tuyết', + 'Đại tuyết', + 'Đông chí', + 'Tiểu hàn', + 'Đại hàn', + 'Lập xuân', + 'Vũ thuỷ', + 'Kinh trập', +] +const TERM_ZH = [ + '春分', + '清明', + '穀雨', + '立夏', + '小滿', + '芒種', + '夏至', + '小暑', + '大暑', + '立秋', + '處暑', + '白露', + '秋分', + '寒露', + '霜降', + '立冬', + '小雪', + '大雪', + '冬至', + '小寒', + '大寒', + '立春', + '雨水', + '驚蟄' +] + +// Get can/chi of a lunar date +function getZodiac({year, month, day, jd}) { + let yearZodiac = { + can: (year + 6) % 10, + chi: (year + 8) % 12 + } + let monthZodiac = { + can: (year * 12 + month + 3) % 10, + chi: (month + 1) % 12 + } + let dayZodiac = { + can: (jd + 9) % 10, + chi: (jd + 1) % 12 + } + return {yearZodiac, monthZodiac, dayZodiac} +} + +function getZodiacText(zodiac, lang) { + switch (lang) { + case "vi": + return CAN_VI[zodiac.can] + " " + CHI_VI[zodiac.chi] + case "zh": + return CAN_ZH[zodiac.can] + CHI_ZH[zodiac.chi] + default: + throw("Unsupported") + } +} + +// Part 2: Update DOM + +// DOM +const dateInput = document.querySelector('#solar-date') +const calendar = document.querySelector('#lunar-solar-cal') +const solarYearOutput = document.querySelector('#solar-year') +const solarMonthOutputEN = document.querySelector('#solar-month-en') +const solarMonthOutputVI = document.querySelector('#solar-month-vi') + +const solarDayOutput = document.querySelector('#solar-day') +const specialDayOutputVI = document.querySelector('#special-day-vi') +const specialDayOutputZH = document.querySelector('#special-day-zh') + +const solarWeekdayOutputEN = document.querySelector('#solar-weekday-en') +const solarWeekdayOutputVI = document.querySelector('#solar-weekday-vi') +const solarWeekdayOutputZH = document.querySelector('#solar-weekday-zh') + +const lunarYearOutputVI = document.querySelector('#lunar-year-vi') +const lunarMonthOutputVI = document.querySelector('#lunar-month-vi') +const lunarMonthZodiacOutputVI = document.querySelector('#lunar-month-zodiac-vi') +const lunarDayZodiacOutputVI = document.querySelector('#lunar-day-zodiac-vi') +const solarTermVI = document.querySelector('#solar-term-vi') + +const lunarDayOutput = document.querySelector('#lunar-day') + +const lunarYearOutputZH = document.querySelector('#lunar-year-zh') +const lunarMonthOutputZH = document.querySelector('#lunar-month-zh') +const lunarMonthZodiacOutputZH = document.querySelector('#lunar-month-zodiac-zh') +const lunarDayOutputZH = document.querySelector('#lunar-day-zh') +const lunarDayZodiacOutputZH = document.querySelector('#lunar-day-zodiac-zh') +const solarTermZH = document.querySelector('#solar-term-zh') + +const dayBeforeBtn = document.querySelector('#nav-day-before') +const dayAfterBtn = document.querySelector('#nav-day-after') + +const monthFormatEN = new Intl.DateTimeFormat("en-US", {month: "long"}) +const monthFormatVI = new Intl.DateTimeFormat("vi-VN", {month: "long"}) +const weekdayFormatEN = new Intl.DateTimeFormat("en-US", {weekday: "long"}) +const weekdayFormatVI = new Intl.DateTimeFormat("vi-VN", {weekday: "long"}) +const weekdayFormatZH = new Intl.DateTimeFormat("zh-CN", {weekday: "long"}) + +const SOLAR_MONTH_VI = ["Một", "Hai", "Ba", "Tư", "Năm", "Sáu", "Bảy", "Tám", "Chín", "Mười", "Mười Một", "Mười Hai"] +const LUNAR_MONTH_VI = ["Giêng", "Hai", "Ba", "Tư", "Năm", "Sáu", "Bảy", "Tám", "Chín", "Mười", "Mười Một", "Chạp"] +const LUNAR_MONTH_ZH = ["元", "二", "三", "四", "五", "六", "七", "八", "九", "十", "十一", "臘", ] +const tzOffset = 7 + +const CHINESE_NUMBERS = "一二三四五六七八九十" + +function getChineseDay(day) { + if (day <= 10) { + return "初" + CHINESE_NUMBERS[day - 1] + } else if (day < 20) { + return "十" + CHINESE_NUMBERS[(day - 1) % 10] + } else if (day == 20) { + return "二十" + } else if (day < 30) { + return "廿" + CHINESE_NUMBERS[(day - 1) % 10] + } else { + return "三十" + } +} + +function isFullMonth(date, lunarDate) { + const daysTill30 = 30 - lunarDate.day + date.setDate(date.getDate() + daysTill30) + let day30 = convertSolarToLunar(date, tzOffset) + return day30.month === lunarDate.month +} + +const specialDaysSolar = { + "01-01": { + vi: "Tết Dương Lịch", + zh: "元旦", + isHoliday: true + }, + "02-03": { + vi: "Ngày thành lập Đảng Cộng Sản Việt Nam", + isHoliday: false + }, + "02-14": { + vi: "Lễ tình nhân (Valentine)", + isHoliday: false + }, + "03-08": { + vi: "Ngày Quốc tế Phụ nữ", + isHoliday: false + }, + "04-30": { + vi: "Ngày Thống nhất", + isHoliday: true + }, + "05-01": { + vi: "Ngày Quốc tế Lao động", + zh: "劳动节", + isHoliday: true + }, + "06-01": { + vi: "Ngày Quốc tế thiếu nhi", + isHoliday: false + }, + "08-19": { + vi: "Ngày kỷ niệm Cách mạng Tháng 8 thành công", + isHoliday: false + }, + "09-02": { + vi: "Ngày Quốc Khánh", + isHoliday: true + }, + "10-01": { + vi: "Ngày quốc tế người cao tuổi", + isHoliday: false + }, + "10-20": { + vi: "Ngày Phụ nữ Việt Nam", + isHoliday: false + }, + "10-31": { + vi: "Halloween", + isHoliday: false + }, + "11-19": { + vi: "Ngày Quốc tế Nam giới", + isHoliday: false + }, + "11-20": { + vi: "Ngày Nhà giáo Việt Nam", + isHoliday: false + }, + "12-24": { + vi: "Đêm Giáng sinh", + isHoliday: false + }, + "12-25": { + vi: "Giáng sinh", + isHoliday: false + } +} +const specialDaysLunar = { + "1-1": { + vi: "Tết Nguyên Đán", + zh: "春节", + isHoliday: true + }, + "1-15": { + vi: "Tết Nguyên Tiêu", + zh: "元宵节", + isHoliday: false + }, + "3-3": { + vi: "Tết Hàn thực", + isHoliday: false + }, + "3-10": { + vi: "Giỗ tổ Hùng Vương", + isHoliday: true + }, + "5-5": { + vi: "Tết Đoan ngọ", + isHoliday: false + }, + "7-7": { + vi: "Lễ Thất tịch", + zh: "七夕", + isHoliday: false + }, + "7-15": { + vi: "Lễ Vu Lan", + isHoliday: false + }, + "8-15": { + vi: "Tết Trung Thu", + zh: "中秋节", + isHoliday: false + }, + "12-23": { + vi: "Tết ông Công ông Táo", + isHoliday: false + } +} + +function getSpecialDays(date, lunarDate) { + const dateStr = date.toISOString().substring(5, 10) + const lunarStr = lunarDate.month + "-" + lunarDate.day + return [specialDaysSolar[dateStr], specialDaysLunar[lunarStr]] +} + +function updateOutputs() { + if (dateInput.valueAsDate === null) { + dateInput.valueAsDate = new Date() + } + const date = dateInput.valueAsDate + solarYearOutput.innerText = date.getFullYear() + solarMonthOutputEN.innerText = monthFormatEN.format(date) + solarMonthOutputVI.innerText = monthFormatVI.format(date) + solarDayOutput.innerText = date.getDate() + solarWeekdayOutputEN.innerText = weekdayFormatEN.format(date) + solarWeekdayOutputVI.innerText = weekdayFormatVI.format(date) + solarWeekdayOutputZH.innerText = weekdayFormatZH.format(date) + + const lunarDate = convertSolarToLunar(date, tzOffset) + const zodiac = getZodiac(lunarDate) + lunarYearOutputVI.innerText = "Năm " + getZodiacText(zodiac.yearZodiac, "vi") + lunarYearOutputZH.innerText = getZodiacText(zodiac.yearZodiac, "zh") + "年" + lunarMonthOutputVI.innerText = "Tháng " + LUNAR_MONTH_VI[lunarDate.month - 1] + lunarMonthOutputZH.innerText = LUNAR_MONTH_ZH[lunarDate.month - 1] + "月" + if (lunarDate.isLeap) { + lunarMonthOutputVI.innerText += " nhuận" + } + if (isFullMonth(structuredClone(date), lunarDate)) { + lunarMonthOutputVI.innerText += " (đủ)" + lunarMonthOutputZH.innerText += "大" + } else { + lunarMonthOutputVI.innerText += " (thiếu)" + lunarMonthOutputZH.innerText += "小" + } + lunarDayOutput.innerText = lunarDate.day + lunarMonthZodiacOutputVI.innerText = "Tháng " + getZodiacText(zodiac.monthZodiac, "vi") + lunarMonthZodiacOutputZH.innerText = getZodiacText(zodiac.monthZodiac, "zh") + "月" + lunarDayZodiacOutputVI.innerText = "Ngày " + getZodiacText(zodiac.dayZodiac, "vi") + lunarDayOutputZH.innerText = getChineseDay(lunarDate.day) + lunarDayZodiacOutputZH.innerText = getZodiacText(zodiac.dayZodiac, "zh") + "曰" + + const solarTerm = getSolarTerm(lunarDate.jd, tzOffset) + solarTermVI.innerText = "Tiết " + TERM_VI[solarTerm] + solarTermZH.innerText = TERM_ZH[solarTerm] + + const specialDays = getSpecialDays(date, lunarDate) + specialDayOutputVI.innerText = "" + specialDayOutputZH.innerText = "" + let isHoliday = false + for (let sday of specialDays) { + if (sday === undefined) { + continue + } + specialDayOutputVI.innerText += "\n" + sday.vi + if (sday.zh) { + specialDayOutputZH.innerText += " · " + sday.zh + } + if (sday.isHoliday) { + isHoliday = true + } + } + if (isHoliday || date.getDay() === 0) { + calendar.className = "holiday" + } else { + calendar.className = "" + } + +} + +dayBeforeBtn.onclick = () => { + let date = new Date(dateInput.valueAsDate.setDate(dateInput.valueAsDate.getDate() - 1)) + dateInput.valueAsDate = date + updateOutputs() +} +dayAfterBtn.onclick = () => { + let date = new Date(dateInput.valueAsDate.setDate(dateInput.valueAsDate.getDate() + 1)) + dateInput.valueAsDate = date + updateOutputs() +} +document.querySelector("#nav-today").onclick = () => { + console.log("a") + dateInput.valueAsDate = new Date() + updateOutputs() +} +document.addEventListener("DOMContentLoaded", updateOutputs) + +dateInput.onchange = updateOutputs diff --git a/content/misc/books.md b/content/misc/books.md index 6a2a284..7d6bdd2 100644 --- a/content/misc/books.md +++ b/content/misc/books.md @@ -28,11 +28,11 @@ I read and liked: - <i>Le petit prince</i>, a novella with a childish theme but discuss many aspects of life in a lighthearted way. - [Ellana][ellana] (<i>Le Pacte des MarchOmbres</i> series) (French) +- [Tous les hommes sont mortels][hommes-mortels] (French) Books I'm reading: - [Ellana: L'envol][ellana-2] (<i>Le Pacte des MarchOmbres</i> series) (French) -- [Tous les hommes sont mortels][hommes-mortels] (French) - <i>The Necromancer</i> (<i>The Secrets of the Immortal Nicholas Flamel</i> series) diff --git a/content/posts/2025-02-23-last-post.md b/content/posts/2025-02-23-last-post.md new file mode 100644 index 0000000..72e4dec --- /dev/null +++ b/content/posts/2025-02-23-last-post.md @@ -0,0 +1,67 @@ +--- +title: "This will be the last post on this RSS feed" +date: 2025-02-23 +lang: en +categories: [ blog ] +tags: [] +translationKey: "2025-02-23-last-post" +--- + +I should preface this by saying I am not taking this website down or anything. +If you are not bothered by all meta stuff, the takeaway is to update your +<abbr>RSS</abbr> feed link from <https://xrvs.net/en/index.xml> to +<https://xrvs.net/index.xml>. It was changed from the latter to the former +previously, and I believed it did wreck the subscription for some of you (not +that I believe there are that many of *you*), which I regretted, so I make this +announcement to not make that mistake again. It will probably take at least a +month or more since this post is published until I finish with the update, so +take your time. + +## Motivation + +As you can see, this website hasn't received much updates (last post was almost +a year ago), and it's probably going to stay that way for a while. There's a +joke that there are two kinds of personal websites: one that runs on wordpress +and receive weekly update, and another where there's only two posts, first post +is "I set up my website with jekyll" and the second post is "I changed from +jekyll to hugo". I am trying hard to not be the second one---I promise, these +changes will not be for the sake of bikeshedding!---but well, it's kinda hard +to find something to write about when most of your time is spent at work, and +talking publicly about stuff happening at work is legally risky. + +So, I intend to spend more writing reviews on books and games as I read and +play them. I am not satisfied with the current state of their the book reviews +section. I have a list of books I read in [the misc](/en/misc/books/) and +another list with [the reviews](/en/book-reviews/), which is a duplication. +After the update, there will be one list at [/reading/](/reading/), with +three-column kanban-esque design: + +- Backlog: list of books I intend to read, maybe with a reason why I want to + reador where I got recommended that book +- Currently reading: books I'm currently reading, probably with comments as I + read (likely contain spoiler) +- Read: books that I finished reading, with the review. + +Note that obviously, I will not update the old posts to backfill the reading +log or reason I want to read a book, if they're not already there. Game +reviews will also be in this format. + +The second issue with the book reviews is, I review the book in the language I +read the book in. As a result, the reviews are scattered. I intend to merge +the languages into one so it'd be easier to track. It's not like I translate +posts or enjoy translating them anyways, so I'll also remove any translations +that happened to be there as well. I will figure out how to add a filter for +language in the <abbr>RSS</abbr> feed. Let me know if you're aware of such a +way. + +Another improvements that I planned is the taxonomy (i.e. tags and categories). +I'd like the categories to be clearly defined with a hierarchy rather than a +mess it is right now---it is for this reason that I hide those from the main +menu bar. + +## Change plan summary + +- Add new list type "backlog" for books, movies, games etc +- Improve taxonomy +- Removing post translations +- Move site root from /en/ to / diff --git a/content/sw-notes/ssh-timeout.md b/content/sw-notes/ssh-timeout.md new file mode 100644 index 0000000..fdb53d9 --- /dev/null +++ b/content/sw-notes/ssh-timeout.md @@ -0,0 +1,20 @@ +--- +title: "How to prevent SSH timeout from hanging your terminal" +date: 2025-03-17 +draft: true +lang: en +categories: [ blog ] +tags: [] +translationKey: "ssh-timeout" +--- + +Sometimes, I open an SSH session and then forget about it. When I get back to it, it hangs indefinitely, without a way to close it other than closing the terminal. + +To avoid this, add this to the client config: + +```sshconfig +Host * + ServerAliveInterval 100 +``` + +If you're disconnected from the SSH server, you'll get this message `Timeout, server example.com not responding.` and the connection is terminated. |